Bug 763869 part 4 - Use nsIContent* in nsContentIterator where possible; r=bz
authorAryeh Gregor <ayg@aryeh.name>
Thu, 14 Jun 2012 09:47:03 +0300
changeset 96828 d0f514bd6ebcfc46bcb0232464af47211f286be4
parent 96827 20a5ddaca1a2e9c2a486014e337e3b2eb5a0f529
child 96829 bc241a81c6a5ddbc20f7402e9a9b06ae0c3e9e74
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbz
bugs763869
milestone16.0a1
Bug 763869 part 4 - Use nsIContent* in nsContentIterator where possible; r=bz
content/base/src/nsContentIterator.cpp
--- a/content/base/src/nsContentIterator.cpp
+++ b/content/base/src/nsContentIterator.cpp
@@ -102,30 +102,34 @@ public:
   virtual nsINode* GetCurrentNode();
 
   virtual bool IsDone();
 
   virtual nsresult PositionAt(nsINode* aCurNode);
 
 protected:
 
+  // Recursively get the deepest first/last child of aRoot.  This will return
+  // aRoot itself if it has no children.
   nsINode* GetDeepFirstChild(nsINode* aRoot,
                              nsTArray<PRInt32>* aIndexes = nsnull);
+  nsIContent* GetDeepFirstChild(nsIContent* aRoot,
+                                nsTArray<PRInt32>* aIndexes = nsnull);
   nsINode* GetDeepLastChild(nsINode* aRoot,
                             nsTArray<PRInt32>* aIndexes = nsnull);
+  nsIContent* GetDeepLastChild(nsIContent* aRoot,
+                               nsTArray<PRInt32>* aIndexes = nsnull);
 
-  // Get the next sibling of aNode.  Note that this will generally return null
-  // if aNode happens not to be a content node.  That's OK.
-  nsINode* GetNextSibling(nsINode* aNode,
-                          nsTArray<PRInt32>* aIndexes = nsnull);
-
-  // Get the prev sibling of aNode.  Note that this will generally return null
-  // if aNode happens not to be a content node.  That's OK.
-  nsINode* GetPrevSibling(nsINode* aNode,
-                          nsTArray<PRInt32>* aIndexes = nsnull);
+  // Get the next/previous sibling of aNode, or its parent's, or grandparent's,
+  // etc.  Returns null if aNode and all its ancestors have no next/previous
+  // sibling.
+  nsIContent* GetNextSibling(nsINode* aNode,
+                             nsTArray<PRInt32>* aIndexes = nsnull);
+  nsIContent* GetPrevSibling(nsINode* aNode,
+                             nsTArray<PRInt32>* aIndexes = nsnull);
 
   nsINode* NextNode(nsINode* aNode, nsTArray<PRInt32>* aIndexes = nsnull);
   nsINode* PrevNode(nsINode* aNode, nsTArray<PRInt32>* aIndexes = nsnull);
 
   // WARNING: This function is expensive
   nsresult RebuildIndexStack();
 
   void MakeEmpty();
@@ -481,22 +485,38 @@ nsContentIterator::MakeEmpty()
   mIsDone       = true;
   mIndexes.Clear();
 }
 
 nsINode*
 nsContentIterator::GetDeepFirstChild(nsINode* aRoot,
                                      nsTArray<PRInt32>* aIndexes)
 {
+  if (!aRoot || !aRoot->HasChildren()) {
+    return aRoot;
+  }
+  // We can't pass aRoot itself to the full GetDeepFirstChild, because that
+  // will only take nsIContent and aRoot might be a document.  Pass aRoot's
+  // child, but be sure to preserve aIndexes.
+  if (aIndexes) {
+    aIndexes->AppendElement(0);
+  }
+  return GetDeepFirstChild(aRoot->GetFirstChild(), aIndexes);
+}
+
+nsIContent*
+nsContentIterator::GetDeepFirstChild(nsIContent* aRoot,
+                                     nsTArray<PRInt32>* aIndexes)
+{
   if (!aRoot) {
     return nsnull;
   }
 
-  nsINode* node = aRoot;
-  nsINode* child = node->GetFirstChild();
+  nsIContent* node = aRoot;
+  nsIContent* child = node->GetFirstChild();
 
   while (child) {
     if (aIndexes) {
       // Add this node to the stack of indexes
       aIndexes->AppendElement(0);
     }
     node = child;
     child = node->GetFirstChild();
@@ -504,43 +524,55 @@ nsContentIterator::GetDeepFirstChild(nsI
 
   return node;
 }
 
 nsINode*
 nsContentIterator::GetDeepLastChild(nsINode* aRoot,
                                     nsTArray<PRInt32>* aIndexes)
 {
+  if (!aRoot || !aRoot->HasChildren()) {
+    return aRoot;
+  }
+  // We can't pass aRoot itself to the full GetDeepLastChild, because that will
+  // only take nsIContent and aRoot might be a document.  Pass aRoot's child,
+  // but be sure to preserve aIndexes.
+  if (aIndexes) {
+    aIndexes->AppendElement(aRoot->GetChildCount() - 1);
+  }
+  return GetDeepLastChild(aRoot->GetLastChild(), aIndexes);
+}
+
+nsIContent*
+nsContentIterator::GetDeepLastChild(nsIContent* aRoot,
+                                    nsTArray<PRInt32>* aIndexes)
+{
   if (!aRoot) {
     return nsnull;
   }
 
-  nsINode* deepLastChild = aRoot;
-
-  nsINode* node = aRoot;
+  nsIContent* node = aRoot;
   PRInt32 numChildren = node->GetChildCount();
 
   while (numChildren) {
-    nsINode* child = node->GetChildAt(--numChildren);
+    nsIContent* child = node->GetChildAt(--numChildren);
 
     if (aIndexes) {
       // Add this node to the stack of indexes
       aIndexes->AppendElement(numChildren);
     }
     numChildren = child->GetChildCount();
     node = child;
-
-    deepLastChild = node;
   }
 
-  return deepLastChild;
+  return node;
 }
 
-// Get the next sibling, or parents next sibling, or grandpa's next sibling...
-nsINode*
+// Get the next sibling, or parent's next sibling, or grandpa's next sibling...
+nsIContent*
 nsContentIterator::GetNextSibling(nsINode* aNode,
                                   nsTArray<PRInt32>* aIndexes)
 {
   if (!aNode) {
     return nsnull;
   }
 
   nsINode* parent = aNode->GetNodeParent();
@@ -557,17 +589,17 @@ nsContentIterator::GetNextSibling(nsINod
     indx = (*aIndexes)[aIndexes->Length()-1];
   } else {
     indx = mCachedIndex;
   }
 
   // reverify that the index of the current node hasn't changed.
   // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
   // ignore result this time - the index may now be out of range.
-  nsINode* sib = parent->GetChildAt(indx);
+  nsIContent* sib = parent->GetChildAt(indx);
   if (sib != aNode) {
     // someone changed our index - find the new index the painful way
     indx = parent->IndexOf(aNode);
   }
 
   // indx is now canonically correct
   if ((sib = parent->GetChildAt(++indx))) {
     // update index cache
@@ -590,18 +622,18 @@ nsContentIterator::GetNextSibling(nsINod
 
     // ok to leave cache out of date here if parent == mCommonParent?
     sib = GetNextSibling(parent, aIndexes);
   }
 
   return sib;
 }
 
-// Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
-nsINode*
+// Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling...
+nsIContent*
 nsContentIterator::GetPrevSibling(nsINode* aNode,
                                   nsTArray<PRInt32>* aIndexes)
 {
   if (!aNode) {
     return nsnull;
   }
 
   nsINode* parent = aNode->GetNodeParent();
@@ -617,17 +649,17 @@ nsContentIterator::GetPrevSibling(nsINod
     // use the last entry on the Indexes array for the current index
     indx = (*aIndexes)[aIndexes->Length()-1];
   } else {
     indx = mCachedIndex;
   }
 
   // reverify that the index of the current node hasn't changed
   // ignore result this time - the index may now be out of range.
-  nsINode* sib = parent->GetChildAt(indx);
+  nsIContent* sib = parent->GetChildAt(indx);
   if (sib != aNode) {
     // someone changed our index - find the new index the painful way
     indx = parent->IndexOf(aNode);
   }
 
   // indx is now canonically correct
   if (indx > 0 && (sib = parent->GetChildAt(--indx))) {
     // update index cache
@@ -651,17 +683,17 @@ nsINode*
 nsContentIterator::NextNode(nsINode* aNode, nsTArray<PRInt32>* aIndexes)
 {
   nsINode* node = aNode;
 
   // if we are a Pre-order iterator, use pre-order
   if (mPre) {
     // if it has children then next node is first child
     if (node->HasChildren()) {
-      nsINode* firstChild = node->GetFirstChild();
+      nsIContent* firstChild = node->GetFirstChild();
 
       // update cache
       if (aIndexes) {
         // push an entry on the index stack
         aIndexes->AppendElement(0);
       } else {
         mCachedIndex = 0;
       }
@@ -670,17 +702,17 @@ nsContentIterator::NextNode(nsINode* aNo
     }
 
     // else next sibling is next
     return GetNextSibling(node, aIndexes);
   }
 
   // post-order
   nsINode* parent = node->GetNodeParent();
-  nsINode* sibling = nsnull;
+  nsIContent* sibling = nsnull;
   PRInt32 indx = 0;
 
   // get the cached index
   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
                "ContentIterator stack underflow");
   if (aIndexes && !aIndexes->IsEmpty()) {
     // use the last entry on the Indexes array for the current index
     indx = (*aIndexes)[aIndexes->Length()-1];
@@ -733,17 +765,17 @@ nsContentIterator::NextNode(nsINode* aNo
 nsINode*
 nsContentIterator::PrevNode(nsINode* aNode, nsTArray<PRInt32>* aIndexes)
 {
   nsINode* node = aNode;
 
   // if we are a Pre-order iterator, use pre-order
   if (mPre) {
     nsINode* parent = node->GetNodeParent();
-    nsINode* sibling = nsnull;
+    nsIContent* sibling = nsnull;
     PRInt32 indx = 0;
 
     // get the cached index
     NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
                  "ContentIterator stack underflow");
     if (aIndexes && !aIndexes->IsEmpty()) {
       // use the last entry on the Indexes array for the current index
       indx = (*aIndexes)[aIndexes->Length()-1];
@@ -788,17 +820,17 @@ nsContentIterator::PrevNode(nsINode* aNo
     return parent;
   }
 
   // post-order
   PRInt32 numChildren = node->GetChildCount();
 
   // if it has children then prev node is last child
   if (numChildren) {
-    nsINode* lastChild = node->GetLastChild();
+    nsIContent* lastChild = node->GetLastChild();
     numChildren--;
 
     // update cache
     if (aIndexes) {
       // push an entry on the index stack
       aIndexes->AppendElement(numChildren);
     } else {
       mCachedIndex = numChildren;
@@ -1087,18 +1119,20 @@ public:
 
   // Must override these because we don't do PositionAt
   virtual void Last();
 
 protected:
 
   // Returns the highest inclusive ancestor of aNode that's in the range
   // (possibly aNode itself).  Returns null if aNode is null, or is not itself
-  // in the range.
-  nsINode* GetTopAncestorInRange(nsINode* aNode);
+  // in the range.  A node is in the range if (node, 0) comes strictly after
+  // the range endpoint, and (node, node.length) comes strictly before it, so
+  // the range's start and end nodes will never be considered "in" it.
+  nsIContent* GetTopAncestorInRange(nsINode* aNode);
 
   // no copy's or assigns  FIX ME
   nsContentSubtreeIterator(const nsContentSubtreeIterator&);
   nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
 
   nsRefPtr<nsRange> mRange;
 
   // these arrays all typically are used and have elements
@@ -1175,28 +1209,28 @@ nsContentSubtreeIterator::Init(nsIDOMRan
       return NS_OK;
     }
   }
 
   // cache ancestors
   nsContentUtils::GetAncestorsAndOffsets(endParent->AsDOMNode(), endOffset,
                                          &mEndNodes, &mEndOffsets);
 
-  nsINode* firstCandidate = nsnull;
-  nsINode* lastCandidate = nsnull;
+  nsIContent* firstCandidate = nsnull;
+  nsIContent* lastCandidate = nsnull;
 
   // find first node in range
   PRInt32 offset = mRange->StartOffset();
 
   nsINode* node;
   if (!startParent->GetChildCount()) {
     // no children, start at the node itself
     node = startParent;
   } else {
-    nsINode* child = startParent->GetChildAt(offset);
+    nsIContent* child = startParent->GetChildAt(offset);
     if (!child) {
       // offset after last child
       node = startParent;
     } else {
       firstCandidate = child;
     }
   }
 
@@ -1345,16 +1379,18 @@ nsContentSubtreeIterator::Prev()
     return;
   }
 
   if (mCurNode == mFirst) {
     mIsDone = true;
     return;
   }
 
+  // If any of these function calls return null, so will all succeeding ones,
+  // so mCurNode will wind up set to null.
   nsINode* prevNode = GetDeepFirstChild(mCurNode);
 
   prevNode = PrevNode(prevNode);
 
   prevNode = GetDeepLastChild(prevNode);
 
   mCurNode = GetTopAncestorInRange(prevNode);
 
@@ -1372,43 +1408,50 @@ nsContentSubtreeIterator::PositionAt(nsI
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /****************************************************************
  * nsContentSubtreeIterator helper routines
  ****************************************************************/
 
-nsINode*
+nsIContent*
 nsContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode)
 {
-  if (!aNode) {
+  if (!aNode || !aNode->GetNodeParent()) {
     return nsnull;
   }
 
+  // aNode has a parent, so it must be content.
+  nsIContent* content = aNode->AsContent();
+
   // sanity check: aNode is itself in the range
   bool nodeBefore, nodeAfter;
   nsresult res = nsRange::CompareNodeToRange(aNode, mRange,
                                              &nodeBefore, &nodeAfter);
   NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
                "aNode isn't in mRange, or something else weird happened");
   if (NS_FAILED(res) || nodeBefore || nodeAfter) {
     return nsnull;
   }
 
-  nsCOMPtr<nsINode> parent, tmp;
-  while (aNode) {
-    parent = aNode->GetNodeParent();
-    if (!parent) {
-      return tmp;
+  while (content) {
+    nsIContent* parent = content->GetParent();
+    // content always has a parent.  If its parent is the root, however --
+    // i.e., either it's not content, or it is content but its own parent is
+    // null -- then we're finished, since we don't go up to the root.
+    //
+    // We have to special-case this because CompareNodeToRange treats the root
+    // node differently -- see bug 765205.
+    if (!parent || !parent->GetNodeParent()) {
+      return content;
     }
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
       nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter)));
 
     if (nodeBefore || nodeAfter) {
-      return aNode;
+      return content;
     }
-    tmp = aNode;
-    aNode = parent;
+    content = parent;
   }
 
   MOZ_NOT_REACHED("This should only be possible if aNode was null");
 }