// WARNING: This function is expensive nsresult nsContentIterator::RebuildIndexStack() { // Make sure we start at the right indexes on the stack! Build array up // to common parent of start and end. Perhaps it's too many entries, but // that's far better than too few. nsINode* parent; nsINode* current; mIndexes.Clear(); current = mCurNode; if (!current) { return NS_OK; } while (current != mCommonParent) { parent = current->GetNodeParent(); if (!parent) return NS_ERROR_FAILURE; mIndexes.InsertElementAt(0, parent->IndexOf(current)); current = parent; } return NS_OK; }
nsresult nsContentIterator::Init(nsINode* aRoot) { if (!aRoot) return NS_ERROR_NULL_POINTER; mIsDone = PR_FALSE; mIndexes.Clear(); if (mPre) { mFirst = aRoot; mLast = GetDeepLastChild(aRoot, nsnull); } else { mFirst = GetDeepFirstChild(aRoot, nsnull); mLast = aRoot; } mCommonParent = aRoot; mCurNode = mFirst; RebuildIndexStack(); return NS_OK; }
void nsContentIterator::MakeEmpty() { mCurNode = nsnull; mFirst = nsnull; mLast = nsnull; mCommonParent = nsnull; mIsDone = PR_TRUE; mIndexes.Clear(); }
nsresult nsContentIterator::Init(nsIRange* aRange) { NS_ENSURE_ARG_POINTER(aRange); mIsDone = PR_FALSE; // get common content parent mCommonParent = aRange->GetCommonAncestor(); NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE); // get the start node and offset PRInt32 startIndx = aRange->StartOffset(); nsINode* startNode = aRange->GetStartParent(); NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); // get the end node and offset PRInt32 endIndx = aRange->EndOffset(); nsINode* endNode = aRange->GetEndParent(); NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE); PRBool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE); // short circuit when start node == end node if (startNode == endNode) { // Check to see if we have a collapsed range, if so, // there is nothing to iterate over. // // XXX: CharacterDataNodes (text nodes) are currently an exception, // since we always want to be able to iterate text nodes at // the end points of a range. if (!startIsData && startIndx == endIndx) { MakeEmpty(); return NS_OK; } if (startIsData) { // It's a textnode. NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT), "Data node that's not content?"); mFirst = static_cast<nsIContent*>(startNode); mLast = mFirst; mCurNode = mFirst; RebuildIndexStack(); return NS_OK; } } // Find first node in range. nsIContent *cChild = nsnull; if (!startIsData && NodeHasChildren(startNode)) cChild = startNode->GetChildAt(startIndx); if (!cChild) // no children, must be a text node { // XXXbz no children might also just mean no children. So I'm not // sure what that comment above is talking about. if (mPre) { // XXX: In the future, if start offset is after the last // character in the cdata node, should we set mFirst to // the next sibling? if (!startIsData) { mFirst = GetNextSibling(startNode, nsnull); // Does mFirst node really intersect the range? // The range could be 'degenerate', ie not collapsed // but still contain no content. if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx, endNode, endIndx)) { mFirst = nsnull; } } else { NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT), "Data node that's not content?"); mFirst = static_cast<nsIContent*>(startNode); } } else { // post-order if (startNode->IsNodeOfType(nsINode::eCONTENT)) { mFirst = static_cast<nsIContent*>(startNode); } else { // What else can we do? mFirst = nsnull; } } } else { if (mPre) mFirst = cChild; else // post-order { mFirst = GetDeepFirstChild(cChild, nsnull); // Does mFirst node really intersect the range? // The range could be 'degenerate', ie not collapsed // but still contain no content. if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx, endNode, endIndx)) mFirst = nsnull; } } // Find last node in range. PRBool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE); if (endIsData || !NodeHasChildren(endNode) || endIndx == 0) { if (mPre) { if (endNode->IsNodeOfType(nsINode::eCONTENT)) { mLast = static_cast<nsIContent*>(endNode); } else { // Not much else to do here... mLast = nsnull; } } else // post-order { // XXX: In the future, if end offset is before the first // character in the cdata node, should we set mLast to // the prev sibling? if (!endIsData) { mLast = GetPrevSibling(endNode, nsnull); if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, endNode, endIndx)) mLast = nsnull; } else { NS_ASSERTION(endNode->IsNodeOfType(nsINode::eCONTENT), "Data node that's not content?"); mLast = static_cast<nsIContent*>(endNode); } } } else { PRInt32 indx = endIndx; cChild = endNode->GetChildAt(--indx); if (!cChild) // No child at offset! { NS_NOTREACHED("nsContentIterator::nsContentIterator"); return NS_ERROR_FAILURE; } if (mPre) { mLast = GetDeepLastChild(cChild, nsnull); if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, endNode, endIndx)) { mLast = nsnull; } } else { // post-order mLast = cChild; } } // If either first or last is null, they both // have to be null! if (!mFirst || !mLast) { mFirst = nsnull; mLast = nsnull; } mCurNode = mFirst; mIsDone = !mCurNode; if (!mCurNode) mIndexes.Clear(); else RebuildIndexStack(); return NS_OK; }