content/base/src/nsContentIterator.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsISupports.h"
     7 #include "nsIDOMNodeList.h"
     8 #include "nsIContentIterator.h"
     9 #include "nsRange.h"
    10 #include "nsIContent.h"
    11 #include "nsCOMPtr.h"
    12 #include "nsTArray.h"
    13 #include "nsContentUtils.h"
    14 #include "nsINode.h"
    15 #include "nsCycleCollectionParticipant.h"
    17 // couple of utility static functs
    19 ///////////////////////////////////////////////////////////////////////////
    20 // NodeToParentOffset: returns the node's parent and offset.
    21 //
    23 static nsINode*
    24 NodeToParentOffset(nsINode* aNode, int32_t* aOffset)
    25 {
    26   *aOffset = 0;
    28   nsINode* parent = aNode->GetParentNode();
    30   if (parent) {
    31     *aOffset = parent->IndexOf(aNode);
    32   }
    34   return parent;
    35 }
    37 ///////////////////////////////////////////////////////////////////////////
    38 // NodeIsInTraversalRange: returns true if content is visited during
    39 // the traversal of the range in the specified mode.
    40 //
    41 static bool
    42 NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
    43                        nsINode* aStartNode, int32_t aStartOffset,
    44                        nsINode* aEndNode, int32_t aEndOffset)
    45 {
    46   if (!aStartNode || !aEndNode || !aNode) {
    47     return false;
    48   }
    50   // If a chardata node contains an end point of the traversal range, it is
    51   // always in the traversal range.
    52   if (aNode->IsNodeOfType(nsINode::eDATA_NODE) &&
    53       (aNode == aStartNode || aNode == aEndNode)) {
    54     return true;
    55   }
    57   nsINode* parent = aNode->GetParentNode();
    58   if (!parent) {
    59     return false;
    60   }
    62   int32_t indx = parent->IndexOf(aNode);
    64   if (!aIsPreMode) {
    65     ++indx;
    66   }
    68   return nsContentUtils::ComparePoints(aStartNode, aStartOffset,
    69                                        parent, indx) <= 0 &&
    70          nsContentUtils::ComparePoints(aEndNode, aEndOffset,
    71                                        parent, indx) >= 0;
    72 }
    76 /*
    77  *  A simple iterator class for traversing the content in "close tag" order
    78  */
    79 class nsContentIterator : public nsIContentIterator
    80 {
    81 public:
    82   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    83   NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator)
    85   explicit nsContentIterator(bool aPre);
    86   virtual ~nsContentIterator();
    88   // nsIContentIterator interface methods ------------------------------
    90   virtual nsresult Init(nsINode* aRoot);
    92   virtual nsresult Init(nsIDOMRange* aRange);
    94   virtual void First();
    96   virtual void Last();
    98   virtual void Next();
   100   virtual void Prev();
   102   virtual nsINode* GetCurrentNode();
   104   virtual bool IsDone();
   106   virtual nsresult PositionAt(nsINode* aCurNode);
   108 protected:
   110   // Recursively get the deepest first/last child of aRoot.  This will return
   111   // aRoot itself if it has no children.
   112   nsINode* GetDeepFirstChild(nsINode* aRoot,
   113                              nsTArray<int32_t>* aIndexes = nullptr);
   114   nsIContent* GetDeepFirstChild(nsIContent* aRoot,
   115                                 nsTArray<int32_t>* aIndexes = nullptr);
   116   nsINode* GetDeepLastChild(nsINode* aRoot,
   117                             nsTArray<int32_t>* aIndexes = nullptr);
   118   nsIContent* GetDeepLastChild(nsIContent* aRoot,
   119                                nsTArray<int32_t>* aIndexes = nullptr);
   121   // Get the next/previous sibling of aNode, or its parent's, or grandparent's,
   122   // etc.  Returns null if aNode and all its ancestors have no next/previous
   123   // sibling.
   124   nsIContent* GetNextSibling(nsINode* aNode,
   125                              nsTArray<int32_t>* aIndexes = nullptr);
   126   nsIContent* GetPrevSibling(nsINode* aNode,
   127                              nsTArray<int32_t>* aIndexes = nullptr);
   129   nsINode* NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes = nullptr);
   130   nsINode* PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes = nullptr);
   132   // WARNING: This function is expensive
   133   nsresult RebuildIndexStack();
   135   void MakeEmpty();
   137   virtual void LastRelease();
   139   nsCOMPtr<nsINode> mCurNode;
   140   nsCOMPtr<nsINode> mFirst;
   141   nsCOMPtr<nsINode> mLast;
   142   nsCOMPtr<nsINode> mCommonParent;
   144   // used by nsContentIterator to cache indices
   145   nsAutoTArray<int32_t, 8> mIndexes;
   147   // used by nsSubtreeIterator to cache indices.  Why put them in the base
   148   // class?  Because otherwise I have to duplicate the routines GetNextSibling
   149   // etc across both classes, with slight variations for caching.  Or
   150   // alternately, create a base class for the cache itself and have all the
   151   // cache manipulation go through a vptr.  I think this is the best space and
   152   // speed combo, even though it's ugly.
   153   int32_t mCachedIndex;
   154   // another note about mCachedIndex: why should the subtree iterator use a
   155   // trivial cached index instead of the mre robust array of indicies (which is
   156   // what the basic content iterator uses)?  The reason is that subtree
   157   // iterators do not do much transitioning between parents and children.  They
   158   // tend to stay at the same level.  In fact, you can prove (though I won't
   159   // attempt it here) that they change levels at most n+m times, where n is the
   160   // height of the parent hierarchy from the range start to the common
   161   // ancestor, and m is the the height of the parent hierarchy from the range
   162   // end to the common ancestor.  If we used the index array, we would pay the
   163   // price up front for n, and then pay the cost for m on the fly later on.
   164   // With the simple cache, we only "pay as we go".  Either way, we call
   165   // IndexOf() once for each change of level in the hierarchy.  Since a trivial
   166   // index is much simpler, we use it for the subtree iterator.
   168   bool mIsDone;
   169   bool mPre;
   171 private:
   173   // no copies or assigns  FIX ME
   174   nsContentIterator(const nsContentIterator&);
   175   nsContentIterator& operator=(const nsContentIterator&);
   177 };
   180 /******************************************************
   181  * repository cruft
   182  ******************************************************/
   184 already_AddRefed<nsIContentIterator>
   185 NS_NewContentIterator()
   186 {
   187   nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(false);
   188   return iter.forget();
   189 }
   192 already_AddRefed<nsIContentIterator>
   193 NS_NewPreContentIterator()
   194 {
   195   nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(true);
   196   return iter.forget();
   197 }
   200 /******************************************************
   201  * XPCOM cruft
   202  ******************************************************/
   204 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator)
   205 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsContentIterator,
   206                                                    LastRelease())
   208 NS_INTERFACE_MAP_BEGIN(nsContentIterator)
   209   NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
   210   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
   211   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator)
   212 NS_INTERFACE_MAP_END
   214 NS_IMPL_CYCLE_COLLECTION(nsContentIterator,
   215                          mCurNode,
   216                          mFirst,
   217                          mLast,
   218                          mCommonParent)
   220 void
   221 nsContentIterator::LastRelease()
   222 {
   223   mCurNode = nullptr;
   224   mFirst = nullptr;
   225   mLast = nullptr;
   226   mCommonParent = nullptr;
   227 }
   229 /******************************************************
   230  * constructor/destructor
   231  ******************************************************/
   233 nsContentIterator::nsContentIterator(bool aPre) :
   234   // don't need to explicitly initialize |nsCOMPtr|s, they will automatically
   235   // be nullptr
   236   mCachedIndex(0), mIsDone(false), mPre(aPre)
   237 {
   238 }
   241 nsContentIterator::~nsContentIterator()
   242 {
   243 }
   246 /******************************************************
   247  * Init routines
   248  ******************************************************/
   251 nsresult
   252 nsContentIterator::Init(nsINode* aRoot)
   253 {
   254   if (!aRoot) {
   255     return NS_ERROR_NULL_POINTER;
   256   }
   258   mIsDone = false;
   259   mIndexes.Clear();
   261   if (mPre) {
   262     mFirst = aRoot;
   263     mLast  = GetDeepLastChild(aRoot);
   264   } else {
   265     mFirst = GetDeepFirstChild(aRoot);
   266     mLast  = aRoot;
   267   }
   269   mCommonParent = aRoot;
   270   mCurNode = mFirst;
   271   RebuildIndexStack();
   272   return NS_OK;
   273 }
   275 nsresult
   276 nsContentIterator::Init(nsIDOMRange* aDOMRange)
   277 {
   278   NS_ENSURE_ARG_POINTER(aDOMRange);
   279   nsRange* range = static_cast<nsRange*>(aDOMRange);
   281   mIsDone = false;
   283   // get common content parent
   284   mCommonParent = range->GetCommonAncestor();
   285   NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE);
   287   // get the start node and offset
   288   int32_t startIndx = range->StartOffset();
   289   nsINode* startNode = range->GetStartParent();
   290   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
   292   // get the end node and offset
   293   int32_t endIndx = range->EndOffset();
   294   nsINode* endNode = range->GetEndParent();
   295   NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
   297   bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
   299   // short circuit when start node == end node
   300   if (startNode == endNode) {
   301     // Check to see if we have a collapsed range, if so, there is nothing to
   302     // iterate over.
   303     //
   304     // XXX: CharacterDataNodes (text nodes) are currently an exception, since
   305     //      we always want to be able to iterate text nodes at the end points
   306     //      of a range.
   308     if (!startIsData && startIndx == endIndx) {
   309       MakeEmpty();
   310       return NS_OK;
   311     }
   313     if (startIsData) {
   314       // It's a character data node.
   315       mFirst   = startNode->AsContent();
   316       mLast    = mFirst;
   317       mCurNode = mFirst;
   319       RebuildIndexStack();
   320       return NS_OK;
   321     }
   322   }
   324   // Find first node in range.
   326   nsIContent* cChild = nullptr;
   328   if (!startIsData && startNode->HasChildren()) {
   329     cChild = startNode->GetChildAt(startIndx);
   330   }
   332   if (!cChild) {
   333     // no children, must be a text node
   334     //
   335     // XXXbz no children might also just mean no children.  So I'm not
   336     // sure what that comment above is talking about.
   338     if (mPre) {
   339       // XXX: In the future, if start offset is after the last
   340       //      character in the cdata node, should we set mFirst to
   341       //      the next sibling?
   343       if (!startIsData) {
   344         mFirst = GetNextSibling(startNode);
   346         // Does mFirst node really intersect the range?  The range could be
   347         // 'degenerate', i.e., not collapsed but still contain no content.
   349         if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode,
   350                                               startIndx, endNode, endIndx)) {
   351           mFirst = nullptr;
   352         }
   353       } else {
   354         mFirst = startNode->AsContent();
   355       }
   356     } else {
   357       // post-order
   358       if (startNode->IsContent()) {
   359         mFirst = startNode->AsContent();
   360       } else {
   361         // What else can we do?
   362         mFirst = nullptr;
   363       }
   364     }
   365   } else {
   366     if (mPre) {
   367       mFirst = cChild;
   368     } else {
   369       // post-order
   370       mFirst = GetDeepFirstChild(cChild);
   372       // Does mFirst node really intersect the range?  The range could be
   373       // 'degenerate', i.e., not collapsed but still contain no content.
   375       if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
   376                                             endNode, endIndx)) {
   377         mFirst = nullptr;
   378       }
   379     }
   380   }
   383   // Find last node in range.
   385   bool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);
   387   if (endIsData || !endNode->HasChildren() || endIndx == 0) {
   388     if (mPre) {
   389       if (endNode->IsContent()) {
   390         mLast = endNode->AsContent();
   391       } else {
   392         // Not much else to do here...
   393         mLast = nullptr;
   394       }
   395     } else {
   396       // post-order
   397       //
   398       // XXX: In the future, if end offset is before the first character in the
   399       //      cdata node, should we set mLast to the prev sibling?
   401       if (!endIsData) {
   402         mLast = GetPrevSibling(endNode);
   404         if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
   405                                     endNode, endIndx)) {
   406           mLast = nullptr;
   407         }
   408       } else {
   409         mLast = endNode->AsContent();
   410       }
   411     }
   412   } else {
   413     int32_t indx = endIndx;
   415     cChild = endNode->GetChildAt(--indx);
   417     if (!cChild) {
   418       // No child at offset!
   419       NS_NOTREACHED("nsContentIterator::nsContentIterator");
   420       return NS_ERROR_FAILURE;
   421     }
   423     if (mPre) {
   424       mLast  = GetDeepLastChild(cChild);
   426       if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
   427                                   endNode, endIndx)) {
   428         mLast = nullptr;
   429       }
   430     } else {
   431       // post-order
   432       mLast = cChild;
   433     }
   434   }
   436   // If either first or last is null, they both have to be null!
   438   if (!mFirst || !mLast) {
   439     mFirst = nullptr;
   440     mLast  = nullptr;
   441   }
   443   mCurNode = mFirst;
   444   mIsDone  = !mCurNode;
   446   if (!mCurNode) {
   447     mIndexes.Clear();
   448   } else {
   449     RebuildIndexStack();
   450   }
   452   return NS_OK;
   453 }
   456 /******************************************************
   457  * Helper routines
   458  ******************************************************/
   459 // WARNING: This function is expensive
   460 nsresult
   461 nsContentIterator::RebuildIndexStack()
   462 {
   463   // Make sure we start at the right indexes on the stack!  Build array up
   464   // to common parent of start and end.  Perhaps it's too many entries, but
   465   // that's far better than too few.
   466   nsINode* parent;
   467   nsINode* current;
   469   mIndexes.Clear();
   470   current = mCurNode;
   471   if (!current) {
   472     return NS_OK;
   473   }
   475   while (current != mCommonParent) {
   476     parent = current->GetParentNode();
   478     if (!parent) {
   479       return NS_ERROR_FAILURE;
   480     }
   482     mIndexes.InsertElementAt(0, parent->IndexOf(current));
   484     current = parent;
   485   }
   487   return NS_OK;
   488 }
   490 void
   491 nsContentIterator::MakeEmpty()
   492 {
   493   mCurNode      = nullptr;
   494   mFirst        = nullptr;
   495   mLast         = nullptr;
   496   mCommonParent = nullptr;
   497   mIsDone       = true;
   498   mIndexes.Clear();
   499 }
   501 nsINode*
   502 nsContentIterator::GetDeepFirstChild(nsINode* aRoot,
   503                                      nsTArray<int32_t>* aIndexes)
   504 {
   505   if (!aRoot || !aRoot->HasChildren()) {
   506     return aRoot;
   507   }
   508   // We can't pass aRoot itself to the full GetDeepFirstChild, because that
   509   // will only take nsIContent and aRoot might be a document.  Pass aRoot's
   510   // child, but be sure to preserve aIndexes.
   511   if (aIndexes) {
   512     aIndexes->AppendElement(0);
   513   }
   514   return GetDeepFirstChild(aRoot->GetFirstChild(), aIndexes);
   515 }
   517 nsIContent*
   518 nsContentIterator::GetDeepFirstChild(nsIContent* aRoot,
   519                                      nsTArray<int32_t>* aIndexes)
   520 {
   521   if (!aRoot) {
   522     return nullptr;
   523   }
   525   nsIContent* node = aRoot;
   526   nsIContent* child = node->GetFirstChild();
   528   while (child) {
   529     if (aIndexes) {
   530       // Add this node to the stack of indexes
   531       aIndexes->AppendElement(0);
   532     }
   533     node = child;
   534     child = node->GetFirstChild();
   535   }
   537   return node;
   538 }
   540 nsINode*
   541 nsContentIterator::GetDeepLastChild(nsINode* aRoot,
   542                                     nsTArray<int32_t>* aIndexes)
   543 {
   544   if (!aRoot || !aRoot->HasChildren()) {
   545     return aRoot;
   546   }
   547   // We can't pass aRoot itself to the full GetDeepLastChild, because that will
   548   // only take nsIContent and aRoot might be a document.  Pass aRoot's child,
   549   // but be sure to preserve aIndexes.
   550   if (aIndexes) {
   551     aIndexes->AppendElement(aRoot->GetChildCount() - 1);
   552   }
   553   return GetDeepLastChild(aRoot->GetLastChild(), aIndexes);
   554 }
   556 nsIContent*
   557 nsContentIterator::GetDeepLastChild(nsIContent* aRoot,
   558                                     nsTArray<int32_t>* aIndexes)
   559 {
   560   if (!aRoot) {
   561     return nullptr;
   562   }
   564   nsIContent* node = aRoot;
   565   int32_t numChildren = node->GetChildCount();
   567   while (numChildren) {
   568     nsIContent* child = node->GetChildAt(--numChildren);
   570     if (aIndexes) {
   571       // Add this node to the stack of indexes
   572       aIndexes->AppendElement(numChildren);
   573     }
   574     numChildren = child->GetChildCount();
   575     node = child;
   576   }
   578   return node;
   579 }
   581 // Get the next sibling, or parent's next sibling, or grandpa's next sibling...
   582 nsIContent*
   583 nsContentIterator::GetNextSibling(nsINode* aNode,
   584                                   nsTArray<int32_t>* aIndexes)
   585 {
   586   if (!aNode) {
   587     return nullptr;
   588   }
   590   nsINode* parent = aNode->GetParentNode();
   591   if (!parent) {
   592     return nullptr;
   593   }
   595   int32_t indx = 0;
   597   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
   598                "ContentIterator stack underflow");
   599   if (aIndexes && !aIndexes->IsEmpty()) {
   600     // use the last entry on the Indexes array for the current index
   601     indx = (*aIndexes)[aIndexes->Length()-1];
   602   } else {
   603     indx = mCachedIndex;
   604   }
   606   // reverify that the index of the current node hasn't changed.
   607   // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
   608   // ignore result this time - the index may now be out of range.
   609   nsIContent* sib = parent->GetChildAt(indx);
   610   if (sib != aNode) {
   611     // someone changed our index - find the new index the painful way
   612     indx = parent->IndexOf(aNode);
   613   }
   615   // indx is now canonically correct
   616   if ((sib = parent->GetChildAt(++indx))) {
   617     // update index cache
   618     if (aIndexes && !aIndexes->IsEmpty()) {
   619       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
   620     } else {
   621       mCachedIndex = indx;
   622     }
   623   } else {
   624     if (parent != mCommonParent) {
   625       if (aIndexes) {
   626         // pop node off the stack, go up one level and return parent or fail.
   627         // Don't leave the index empty, especially if we're
   628         // returning nullptr.  This confuses other parts of the code.
   629         if (aIndexes->Length() > 1) {
   630           aIndexes->RemoveElementAt(aIndexes->Length()-1);
   631         }
   632       }
   633     }
   635     // ok to leave cache out of date here if parent == mCommonParent?
   636     sib = GetNextSibling(parent, aIndexes);
   637   }
   639   return sib;
   640 }
   642 // Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling...
   643 nsIContent*
   644 nsContentIterator::GetPrevSibling(nsINode* aNode,
   645                                   nsTArray<int32_t>* aIndexes)
   646 {
   647   if (!aNode) {
   648     return nullptr;
   649   }
   651   nsINode* parent = aNode->GetParentNode();
   652   if (!parent) {
   653     return nullptr;
   654   }
   656   int32_t indx = 0;
   658   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
   659                "ContentIterator stack underflow");
   660   if (aIndexes && !aIndexes->IsEmpty()) {
   661     // use the last entry on the Indexes array for the current index
   662     indx = (*aIndexes)[aIndexes->Length()-1];
   663   } else {
   664     indx = mCachedIndex;
   665   }
   667   // reverify that the index of the current node hasn't changed
   668   // ignore result this time - the index may now be out of range.
   669   nsIContent* sib = parent->GetChildAt(indx);
   670   if (sib != aNode) {
   671     // someone changed our index - find the new index the painful way
   672     indx = parent->IndexOf(aNode);
   673   }
   675   // indx is now canonically correct
   676   if (indx > 0 && (sib = parent->GetChildAt(--indx))) {
   677     // update index cache
   678     if (aIndexes && !aIndexes->IsEmpty()) {
   679       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
   680     } else {
   681       mCachedIndex = indx;
   682     }
   683   } else if (parent != mCommonParent) {
   684     if (aIndexes && !aIndexes->IsEmpty()) {
   685       // pop node off the stack, go up one level and try again.
   686       aIndexes->RemoveElementAt(aIndexes->Length()-1);
   687     }
   688     return GetPrevSibling(parent, aIndexes);
   689   }
   691   return sib;
   692 }
   694 nsINode*
   695 nsContentIterator::NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
   696 {
   697   nsINode* node = aNode;
   699   // if we are a Pre-order iterator, use pre-order
   700   if (mPre) {
   701     // if it has children then next node is first child
   702     if (node->HasChildren()) {
   703       nsIContent* firstChild = node->GetFirstChild();
   705       // update cache
   706       if (aIndexes) {
   707         // push an entry on the index stack
   708         aIndexes->AppendElement(0);
   709       } else {
   710         mCachedIndex = 0;
   711       }
   713       return firstChild;
   714     }
   716     // else next sibling is next
   717     return GetNextSibling(node, aIndexes);
   718   }
   720   // post-order
   721   nsINode* parent = node->GetParentNode();
   722   nsIContent* sibling = nullptr;
   723   int32_t indx = 0;
   725   // get the cached index
   726   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
   727                "ContentIterator stack underflow");
   728   if (aIndexes && !aIndexes->IsEmpty()) {
   729     // use the last entry on the Indexes array for the current index
   730     indx = (*aIndexes)[aIndexes->Length()-1];
   731   } else {
   732     indx = mCachedIndex;
   733   }
   735   // reverify that the index of the current node hasn't changed.  not super
   736   // cheap, but a lot cheaper than IndexOf(), and still O(1).  ignore result
   737   // this time - the index may now be out of range.
   738   if (indx >= 0) {
   739     sibling = parent->GetChildAt(indx);
   740   }
   741   if (sibling != node) {
   742     // someone changed our index - find the new index the painful way
   743     indx = parent->IndexOf(node);
   744   }
   746   // indx is now canonically correct
   747   sibling = parent->GetChildAt(++indx);
   748   if (sibling) {
   749     // update cache
   750     if (aIndexes && !aIndexes->IsEmpty()) {
   751       // replace an entry on the index stack
   752       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
   753     } else {
   754       mCachedIndex = indx;
   755     }
   757     // next node is sibling's "deep left" child
   758     return GetDeepFirstChild(sibling, aIndexes);
   759   }
   761   // else it's the parent, update cache
   762   if (aIndexes) {
   763     // Pop an entry off the index stack.  Don't leave the index empty,
   764     // especially if we're returning nullptr.  This confuses other parts of the
   765     // code.
   766     if (aIndexes->Length() > 1) {
   767       aIndexes->RemoveElementAt(aIndexes->Length()-1);
   768     }
   769   } else {
   770     // this might be wrong, but we are better off guessing
   771     mCachedIndex = 0;
   772   }
   774   return parent;
   775 }
   777 nsINode*
   778 nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
   779 {
   780   nsINode* node = aNode;
   782   // if we are a Pre-order iterator, use pre-order
   783   if (mPre) {
   784     nsINode* parent = node->GetParentNode();
   785     nsIContent* sibling = nullptr;
   786     int32_t indx = 0;
   788     // get the cached index
   789     NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
   790                  "ContentIterator stack underflow");
   791     if (aIndexes && !aIndexes->IsEmpty()) {
   792       // use the last entry on the Indexes array for the current index
   793       indx = (*aIndexes)[aIndexes->Length()-1];
   794     } else {
   795       indx = mCachedIndex;
   796     }
   798     // reverify that the index of the current node hasn't changed.  not super
   799     // cheap, but a lot cheaper than IndexOf(), and still O(1).  ignore result
   800     // this time - the index may now be out of range.
   801     if (indx >= 0) {
   802       sibling = parent->GetChildAt(indx);
   803     }
   805     if (sibling != node) {
   806       // someone changed our index - find the new index the painful way
   807       indx = parent->IndexOf(node);
   808     }
   810     // indx is now canonically correct
   811     if (indx && (sibling = parent->GetChildAt(--indx))) {
   812       // update cache
   813       if (aIndexes && !aIndexes->IsEmpty()) {
   814         // replace an entry on the index stack
   815         aIndexes->ElementAt(aIndexes->Length()-1) = indx;
   816       } else {
   817         mCachedIndex = indx;
   818       }
   820       // prev node is sibling's "deep right" child
   821       return GetDeepLastChild(sibling, aIndexes);
   822     }
   824     // else it's the parent, update cache
   825     if (aIndexes && !aIndexes->IsEmpty()) {
   826       // pop an entry off the index stack
   827       aIndexes->RemoveElementAt(aIndexes->Length()-1);
   828     } else {
   829       // this might be wrong, but we are better off guessing
   830       mCachedIndex = 0;
   831     }
   832     return parent;
   833   }
   835   // post-order
   836   int32_t numChildren = node->GetChildCount();
   838   // if it has children then prev node is last child
   839   if (numChildren) {
   840     nsIContent* lastChild = node->GetLastChild();
   841     numChildren--;
   843     // update cache
   844     if (aIndexes) {
   845       // push an entry on the index stack
   846       aIndexes->AppendElement(numChildren);
   847     } else {
   848       mCachedIndex = numChildren;
   849     }
   851     return lastChild;
   852   }
   854   // else prev sibling is previous
   855   return GetPrevSibling(node, aIndexes);
   856 }
   858 /******************************************************
   859  * ContentIterator routines
   860  ******************************************************/
   862 void
   863 nsContentIterator::First()
   864 {
   865   if (mFirst) {
   866 #ifdef DEBUG
   867     nsresult rv =
   868 #endif
   869     PositionAt(mFirst);
   871     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
   872   }
   874   mIsDone = mFirst == nullptr;
   875 }
   878 void
   879 nsContentIterator::Last()
   880 {
   881   NS_ASSERTION(mLast, "No last node!");
   883   if (mLast) {
   884 #ifdef DEBUG
   885     nsresult rv =
   886 #endif
   887     PositionAt(mLast);
   889     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
   890   }
   892   mIsDone = mLast == nullptr;
   893 }
   896 void
   897 nsContentIterator::Next()
   898 {
   899   if (mIsDone || !mCurNode) {
   900     return;
   901   }
   903   if (mCurNode == mLast) {
   904     mIsDone = true;
   905     return;
   906   }
   908   mCurNode = NextNode(mCurNode, &mIndexes);
   909 }
   912 void
   913 nsContentIterator::Prev()
   914 {
   915   if (mIsDone || !mCurNode) {
   916     return;
   917   }
   919   if (mCurNode == mFirst) {
   920     mIsDone = true;
   921     return;
   922   }
   924   mCurNode = PrevNode(mCurNode, &mIndexes);
   925 }
   928 bool
   929 nsContentIterator::IsDone()
   930 {
   931   return mIsDone;
   932 }
   935 // Keeping arrays of indexes for the stack of nodes makes PositionAt
   936 // interesting...
   937 nsresult
   938 nsContentIterator::PositionAt(nsINode* aCurNode)
   939 {
   940   if (!aCurNode) {
   941     return NS_ERROR_NULL_POINTER;
   942   }
   944   nsINode* newCurNode = aCurNode;
   945   nsINode* tempNode = mCurNode;
   947   mCurNode = aCurNode;
   948   // take an early out if this doesn't actually change the position
   949   if (mCurNode == tempNode) {
   950     mIsDone = false;  // paranoia
   951     return NS_OK;
   952   }
   954   // Check to see if the node falls within the traversal range.
   956   nsINode* firstNode = mFirst;
   957   nsINode* lastNode = mLast;
   958   int32_t firstOffset = 0, lastOffset = 0;
   960   if (firstNode && lastNode) {
   961     if (mPre) {
   962       firstNode = NodeToParentOffset(mFirst, &firstOffset);
   964       if (lastNode->GetChildCount()) {
   965         lastOffset = 0;
   966       } else {
   967         lastNode = NodeToParentOffset(mLast, &lastOffset);
   968         ++lastOffset;
   969       }
   970     } else {
   971       uint32_t numChildren = firstNode->GetChildCount();
   973       if (numChildren) {
   974         firstOffset = numChildren;
   975       } else {
   976         firstNode = NodeToParentOffset(mFirst, &firstOffset);
   977       }
   979       lastNode = NodeToParentOffset(mLast, &lastOffset);
   980       ++lastOffset;
   981     }
   982   }
   984   // The end positions are always in the range even if it has no parent.  We
   985   // need to allow that or 'iter->Init(root)' would assert in Last() or First()
   986   // for example, bug 327694.
   987   if (mFirst != mCurNode && mLast != mCurNode &&
   988       (!firstNode || !lastNode ||
   989        !NodeIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset,
   990                                lastNode, lastOffset))) {
   991     mIsDone = true;
   992     return NS_ERROR_FAILURE;
   993   }
   995   // We can be at ANY node in the sequence.  Need to regenerate the array of
   996   // indexes back to the root or common parent!
   997   nsAutoTArray<nsINode*, 8>     oldParentStack;
   998   nsAutoTArray<int32_t, 8>      newIndexes;
  1000   // Get a list of the parents up to the root, then compare the new node with
  1001   // entries in that array until we find a match (lowest common ancestor).  If
  1002   // no match, use IndexOf, take the parent, and repeat.  This avoids using
  1003   // IndexOf() N times on possibly large arrays.  We still end up doing it a
  1004   // fair bit.  It's better to use Clone() if possible.
  1006   // we know the depth we're down (though we may not have started at the top).
  1007   oldParentStack.SetCapacity(mIndexes.Length() + 1);
  1009   // We want to loop mIndexes.Length() + 1 times here, because we want to make
  1010   // sure we include mCommonParent in the oldParentStack, for use in the next
  1011   // for loop, and mIndexes only has entries for nodes from tempNode up through
  1012   // an ancestor of tempNode that's a child of mCommonParent.
  1013   for (int32_t i = mIndexes.Length() + 1; i > 0 && tempNode; i--) {
  1014     // Insert at head since we're walking up
  1015     oldParentStack.InsertElementAt(0, tempNode);
  1017     nsINode* parent = tempNode->GetParentNode();
  1019     if (!parent) {
  1020       // this node has no parent, and thus no index
  1021       break;
  1024     if (parent == mCurNode) {
  1025       // The position was moved to a parent of the current position.  All we
  1026       // need to do is drop some indexes.  Shortcut here.
  1027       mIndexes.RemoveElementsAt(mIndexes.Length() - oldParentStack.Length(),
  1028                                 oldParentStack.Length());
  1029       mIsDone = false;
  1030       return NS_OK;
  1032     tempNode = parent;
  1035   // Ok.  We have the array of old parents.  Look for a match.
  1036   while (newCurNode) {
  1037     nsINode* parent = newCurNode->GetParentNode();
  1039     if (!parent) {
  1040       // this node has no parent, and thus no index
  1041       break;
  1044     int32_t indx = parent->IndexOf(newCurNode);
  1046     // insert at the head!
  1047     newIndexes.InsertElementAt(0, indx);
  1049     // look to see if the parent is in the stack
  1050     indx = oldParentStack.IndexOf(parent);
  1051     if (indx >= 0) {
  1052       // ok, the parent IS on the old stack!  Rework things.  We want
  1053       // newIndexes to replace all nodes equal to or below the match.  Note
  1054       // that index oldParentStack.Length() - 1 is the last node, which is one
  1055       // BELOW the last index in the mIndexes stack.  In other words, we want
  1056       // to remove elements starting at index (indx + 1).
  1057       int32_t numToDrop = oldParentStack.Length() - (1 + indx);
  1058       if (numToDrop > 0) {
  1059         mIndexes.RemoveElementsAt(mIndexes.Length() - numToDrop, numToDrop);
  1061       mIndexes.AppendElements(newIndexes);
  1063       break;
  1065     newCurNode = parent;
  1068   // phew!
  1070   mIsDone = false;
  1071   return NS_OK;
  1074 nsINode*
  1075 nsContentIterator::GetCurrentNode()
  1077   if (mIsDone) {
  1078     return nullptr;
  1081   NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
  1083   return mCurNode;
  1090 /*====================================================================================*/
  1091 /*====================================================================================*/
  1098 /******************************************************
  1099  * nsContentSubtreeIterator
  1100  ******************************************************/
  1103 /*
  1104  *  A simple iterator class for traversing the content in "top subtree" order
  1105  */
  1106 class nsContentSubtreeIterator : public nsContentIterator
  1108 public:
  1109   nsContentSubtreeIterator() : nsContentIterator(false) {}
  1110   virtual ~nsContentSubtreeIterator() {}
  1112   NS_DECL_ISUPPORTS_INHERITED
  1113   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator, nsContentIterator)
  1115   // nsContentIterator overrides ------------------------------
  1117   virtual nsresult Init(nsINode* aRoot);
  1119   virtual nsresult Init(nsIDOMRange* aRange);
  1121   virtual void Next();
  1123   virtual void Prev();
  1125   virtual nsresult PositionAt(nsINode* aCurNode);
  1127   // Must override these because we don't do PositionAt
  1128   virtual void First();
  1130   // Must override these because we don't do PositionAt
  1131   virtual void Last();
  1133 protected:
  1135   // Returns the highest inclusive ancestor of aNode that's in the range
  1136   // (possibly aNode itself).  Returns null if aNode is null, or is not itself
  1137   // in the range.  A node is in the range if (node, 0) comes strictly after
  1138   // the range endpoint, and (node, node.length) comes strictly before it, so
  1139   // the range's start and end nodes will never be considered "in" it.
  1140   nsIContent* GetTopAncestorInRange(nsINode* aNode);
  1142   // no copy's or assigns  FIX ME
  1143   nsContentSubtreeIterator(const nsContentSubtreeIterator&);
  1144   nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
  1146   virtual void LastRelease() MOZ_OVERRIDE;
  1148   nsRefPtr<nsRange> mRange;
  1150   // these arrays all typically are used and have elements
  1151   nsAutoTArray<nsIContent*, 8> mEndNodes;
  1152   nsAutoTArray<int32_t, 8>     mEndOffsets;
  1153 };
  1155 NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator)
  1156 NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator)
  1158 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator)
  1159 NS_INTERFACE_MAP_END_INHERITING(nsContentIterator)
  1161 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator, nsContentIterator,
  1162                                    mRange)
  1164 void
  1165 nsContentSubtreeIterator::LastRelease()
  1167   mRange = nullptr;
  1168   nsContentIterator::LastRelease();
  1171 /******************************************************
  1172  * repository cruft
  1173  ******************************************************/
  1175 already_AddRefed<nsIContentIterator>
  1176 NS_NewContentSubtreeIterator()
  1178   nsCOMPtr<nsIContentIterator> iter = new nsContentSubtreeIterator();
  1179   return iter.forget();
  1184 /******************************************************
  1185  * Init routines
  1186  ******************************************************/
  1189 nsresult
  1190 nsContentSubtreeIterator::Init(nsINode* aRoot)
  1192   return NS_ERROR_NOT_IMPLEMENTED;
  1196 nsresult
  1197 nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
  1199   MOZ_ASSERT(aRange);
  1201   mIsDone = false;
  1203   mRange = static_cast<nsRange*>(aRange);
  1205   // get the start node and offset, convert to nsINode
  1206   mCommonParent = mRange->GetCommonAncestor();
  1207   nsINode* startParent = mRange->GetStartParent();
  1208   int32_t startOffset = mRange->StartOffset();
  1209   nsINode* endParent = mRange->GetEndParent();
  1210   int32_t endOffset = mRange->EndOffset();
  1211   MOZ_ASSERT(mCommonParent && startParent && endParent);
  1212   // Bug 767169
  1213   MOZ_ASSERT(uint32_t(startOffset) <= startParent->Length() &&
  1214              uint32_t(endOffset) <= endParent->Length());
  1216   // short circuit when start node == end node
  1217   if (startParent == endParent) {
  1218     nsINode* child = startParent->GetFirstChild();
  1220     if (!child || startOffset == endOffset) {
  1221       // Text node, empty container, or collapsed
  1222       MakeEmpty();
  1223       return NS_OK;
  1227   // cache ancestors
  1228   nsContentUtils::GetAncestorsAndOffsets(endParent->AsDOMNode(), endOffset,
  1229                                          &mEndNodes, &mEndOffsets);
  1231   nsIContent* firstCandidate = nullptr;
  1232   nsIContent* lastCandidate = nullptr;
  1234   // find first node in range
  1235   int32_t offset = mRange->StartOffset();
  1237   nsINode* node;
  1238   if (!startParent->GetChildCount()) {
  1239     // no children, start at the node itself
  1240     node = startParent;
  1241   } else {
  1242     nsIContent* child = startParent->GetChildAt(offset);
  1243     if (!child) {
  1244       // offset after last child
  1245       node = startParent;
  1246     } else {
  1247       firstCandidate = child;
  1251   if (!firstCandidate) {
  1252     // then firstCandidate is next node after node
  1253     firstCandidate = GetNextSibling(node);
  1255     if (!firstCandidate) {
  1256       MakeEmpty();
  1257       return NS_OK;
  1261   firstCandidate = GetDeepFirstChild(firstCandidate);
  1263   // confirm that this first possible contained node is indeed contained.  Else
  1264   // we have a range that does not fully contain any node.
  1266   bool nodeBefore, nodeAfter;
  1267   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
  1268     nsRange::CompareNodeToRange(firstCandidate, mRange, &nodeBefore, &nodeAfter)));
  1270   if (nodeBefore || nodeAfter) {
  1271     MakeEmpty();
  1272     return NS_OK;
  1275   // cool, we have the first node in the range.  Now we walk up its ancestors
  1276   // to find the most senior that is still in the range.  That's the real first
  1277   // node.
  1278   mFirst = GetTopAncestorInRange(firstCandidate);
  1280   // now to find the last node
  1281   offset = mRange->EndOffset();
  1282   int32_t numChildren = endParent->GetChildCount();
  1284   if (offset > numChildren) {
  1285     // Can happen for text nodes
  1286     offset = numChildren;
  1288   if (!offset || !numChildren) {
  1289     node = endParent;
  1290   } else {
  1291     lastCandidate = endParent->GetChildAt(--offset);
  1292     NS_ASSERTION(lastCandidate,
  1293                  "tree traversal trouble in nsContentSubtreeIterator::Init");
  1296   if (!lastCandidate) {
  1297     // then lastCandidate is prev node before node
  1298     lastCandidate = GetPrevSibling(node);
  1301   if (!lastCandidate) {
  1302     MakeEmpty();
  1303     return NS_OK;
  1306   lastCandidate = GetDeepLastChild(lastCandidate);
  1308   // confirm that this last possible contained node is indeed contained.  Else
  1309   // we have a range that does not fully contain any node.
  1311   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
  1312     nsRange::CompareNodeToRange(lastCandidate, mRange, &nodeBefore, &nodeAfter)));
  1314   if (nodeBefore || nodeAfter) {
  1315     MakeEmpty();
  1316     return NS_OK;
  1319   // cool, we have the last node in the range.  Now we walk up its ancestors to
  1320   // find the most senior that is still in the range.  That's the real first
  1321   // node.
  1322   mLast = GetTopAncestorInRange(lastCandidate);
  1324   mCurNode = mFirst;
  1326   return NS_OK;
  1329 /****************************************************************
  1330  * nsContentSubtreeIterator overrides of ContentIterator routines
  1331  ****************************************************************/
  1333 // we can't call PositionAt in a subtree iterator...
  1334 void
  1335 nsContentSubtreeIterator::First()
  1337   mIsDone = mFirst == nullptr;
  1339   mCurNode = mFirst;
  1342 // we can't call PositionAt in a subtree iterator...
  1343 void
  1344 nsContentSubtreeIterator::Last()
  1346   mIsDone = mLast == nullptr;
  1348   mCurNode = mLast;
  1352 void
  1353 nsContentSubtreeIterator::Next()
  1355   if (mIsDone || !mCurNode) {
  1356     return;
  1359   if (mCurNode == mLast) {
  1360     mIsDone = true;
  1361     return;
  1364   nsINode* nextNode = GetNextSibling(mCurNode);
  1365   NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
  1367   int32_t i = mEndNodes.IndexOf(nextNode);
  1368   while (i != -1) {
  1369     // as long as we are finding ancestors of the endpoint of the range,
  1370     // dive down into their children
  1371     nextNode = nextNode->GetFirstChild();
  1372     NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
  1374     // should be impossible to get a null pointer.  If we went all the way
  1375     // down the child chain to the bottom without finding an interior node,
  1376     // then the previous node should have been the last, which was
  1377     // was tested at top of routine.
  1378     i = mEndNodes.IndexOf(nextNode);
  1381   mCurNode = nextNode;
  1383   // This shouldn't be needed, but since our selection code can put us
  1384   // in a situation where mLast is in generated content, we need this
  1385   // to stop the iterator when we've walked past past the last node!
  1386   mIsDone = mCurNode == nullptr;
  1390 void
  1391 nsContentSubtreeIterator::Prev()
  1393   // Prev should be optimized to use the mStartNodes, just as Next
  1394   // uses mEndNodes.
  1395   if (mIsDone || !mCurNode) {
  1396     return;
  1399   if (mCurNode == mFirst) {
  1400     mIsDone = true;
  1401     return;
  1404   // If any of these function calls return null, so will all succeeding ones,
  1405   // so mCurNode will wind up set to null.
  1406   nsINode* prevNode = GetDeepFirstChild(mCurNode);
  1408   prevNode = PrevNode(prevNode);
  1410   prevNode = GetDeepLastChild(prevNode);
  1412   mCurNode = GetTopAncestorInRange(prevNode);
  1414   // This shouldn't be needed, but since our selection code can put us
  1415   // in a situation where mFirst is in generated content, we need this
  1416   // to stop the iterator when we've walked past past the first node!
  1417   mIsDone = mCurNode == nullptr;
  1421 nsresult
  1422 nsContentSubtreeIterator::PositionAt(nsINode* aCurNode)
  1424   NS_ERROR("Not implemented!");
  1426   return NS_ERROR_NOT_IMPLEMENTED;
  1429 /****************************************************************
  1430  * nsContentSubtreeIterator helper routines
  1431  ****************************************************************/
  1433 nsIContent*
  1434 nsContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode)
  1436   if (!aNode || !aNode->GetParentNode()) {
  1437     return nullptr;
  1440   // aNode has a parent, so it must be content.
  1441   nsIContent* content = aNode->AsContent();
  1443   // sanity check: aNode is itself in the range
  1444   bool nodeBefore, nodeAfter;
  1445   nsresult res = nsRange::CompareNodeToRange(aNode, mRange,
  1446                                              &nodeBefore, &nodeAfter);
  1447   NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
  1448                "aNode isn't in mRange, or something else weird happened");
  1449   if (NS_FAILED(res) || nodeBefore || nodeAfter) {
  1450     return nullptr;
  1453   while (content) {
  1454     nsIContent* parent = content->GetParent();
  1455     // content always has a parent.  If its parent is the root, however --
  1456     // i.e., either it's not content, or it is content but its own parent is
  1457     // null -- then we're finished, since we don't go up to the root.
  1458     //
  1459     // We have to special-case this because CompareNodeToRange treats the root
  1460     // node differently -- see bug 765205.
  1461     if (!parent || !parent->GetParentNode()) {
  1462       return content;
  1464     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
  1465       nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter)));
  1467     if (nodeBefore || nodeAfter) {
  1468       return content;
  1470     content = parent;
  1473   MOZ_CRASH("This should only be possible if aNode was null");

mercurial