LCOV - code coverage report
Current view: directory - content/base/src - nsContentIterator.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 553 176 31.8 %
Date: 2012-06-02 Functions: 57 29 50.9 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsISupports.h"
      40                 : #include "nsIDOMNodeList.h"
      41                 : #include "nsIContentIterator.h"
      42                 : #include "nsRange.h"
      43                 : #include "nsIContent.h"
      44                 : #include "nsCOMPtr.h"
      45                 : #include "nsTArray.h"
      46                 : #include "nsContentUtils.h"
      47                 : #include "nsINode.h"
      48                 : #include "nsCycleCollectionParticipant.h"
      49                 : 
      50                 : // couple of utility static functs
      51                 : 
      52                 : ///////////////////////////////////////////////////////////////////////////
      53                 : // ContentHasChildren: returns true if the node has children
      54                 : //
      55                 : static inline bool
      56               0 : NodeHasChildren(nsINode *aNode)
      57                 : {
      58               0 :   return aNode->GetChildCount() > 0;
      59                 : }
      60                 : 
      61                 : ///////////////////////////////////////////////////////////////////////////
      62                 : // NodeToParentOffset: returns the node's parent and offset.
      63                 : //
      64                 : 
      65                 : static nsINode*
      66               0 : NodeToParentOffset(nsINode *aNode, PRInt32 *aOffset)
      67                 : {
      68               0 :   *aOffset  = 0;
      69                 : 
      70               0 :   nsINode* parent = aNode->GetNodeParent();
      71                 : 
      72               0 :   if (parent) {
      73               0 :     *aOffset = parent->IndexOf(aNode);
      74                 :   }
      75                 :   
      76               0 :   return parent;
      77                 : }
      78                 : 
      79                 : ///////////////////////////////////////////////////////////////////////////
      80                 : // NodeIsInTraversalRange: returns true if content is visited during
      81                 : // the traversal of the range in the specified mode.
      82                 : //
      83                 : static bool
      84               0 : NodeIsInTraversalRange(nsINode *aNode, bool aIsPreMode,
      85                 :                        nsINode *aStartNode, PRInt32 aStartOffset,
      86                 :                        nsINode *aEndNode, PRInt32 aEndOffset)
      87                 : {
      88               0 :   if (!aStartNode || !aEndNode || !aNode)
      89               0 :     return false;
      90                 : 
      91                 :   // If a chardata node contains an end point of the traversal range,
      92                 :   // it is always in the traversal range.
      93               0 :   if (aNode->IsNodeOfType(nsINode::eDATA_NODE) &&
      94                 :       (aNode == aStartNode || aNode == aEndNode)) {
      95               0 :     return true;
      96                 :   }
      97                 : 
      98               0 :   nsINode* parent = aNode->GetNodeParent();
      99               0 :   if (!parent)
     100               0 :     return false;
     101                 : 
     102               0 :   PRInt32 indx = parent->IndexOf(aNode);
     103                 : 
     104               0 :   if (!aIsPreMode)
     105               0 :     ++indx;
     106                 : 
     107                 :   return (nsContentUtils::ComparePoints(aStartNode, aStartOffset,
     108               0 :                                         parent, indx) <= 0) &&
     109                 :          (nsContentUtils::ComparePoints(aEndNode, aEndOffset,
     110               0 :                                         parent, indx) >= 0);
     111                 : }
     112                 : 
     113                 : 
     114                 : 
     115                 : /*
     116                 :  *  A simple iterator class for traversing the content in "close tag" order
     117                 :  */
     118                 : class nsContentIterator : public nsIContentIterator //, public nsIEnumerator
     119                 : {
     120                 : public:
     121               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     122            2952 :   NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator)
     123                 : 
     124                 :   explicit nsContentIterator(bool aPre);
     125                 :   virtual ~nsContentIterator();
     126                 : 
     127                 :   // nsIContentIterator interface methods ------------------------------
     128                 : 
     129                 :   virtual nsresult Init(nsINode* aRoot);
     130                 : 
     131                 :   virtual nsresult Init(nsIDOMRange* aRange);
     132                 : 
     133                 :   virtual void First();
     134                 : 
     135                 :   virtual void Last();
     136                 :   
     137                 :   virtual void Next();
     138                 : 
     139                 :   virtual void Prev();
     140                 : 
     141                 :   virtual nsINode *GetCurrentNode();
     142                 : 
     143                 :   virtual bool IsDone();
     144                 : 
     145                 :   virtual nsresult PositionAt(nsINode* aCurNode);
     146                 : 
     147                 :   // nsIEnumertor interface methods ------------------------------
     148                 :   
     149                 :   //NS_IMETHOD CurrentItem(nsISupports **aItem);
     150                 : 
     151                 : protected:
     152                 : 
     153                 :   nsINode* GetDeepFirstChild(nsINode *aRoot, nsTArray<PRInt32> *aIndexes);
     154                 :   nsINode* GetDeepLastChild(nsINode *aRoot, nsTArray<PRInt32> *aIndexes);
     155                 : 
     156                 :   // Get the next sibling of aNode.  Note that this will generally return null
     157                 :   // if aNode happens not to be a content node.  That's OK.
     158                 :   nsINode* GetNextSibling(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
     159                 : 
     160                 :   // Get the prev sibling of aNode.  Note that this will generally return null
     161                 :   // if aNode happens not to be a content node.  That's OK.
     162                 :   nsINode* GetPrevSibling(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
     163                 : 
     164                 :   nsINode* NextNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
     165                 :   nsINode* PrevNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
     166                 : 
     167                 :   // WARNING: This function is expensive
     168                 :   nsresult RebuildIndexStack();
     169                 : 
     170                 :   void MakeEmpty();
     171                 :   
     172                 :   nsCOMPtr<nsINode> mCurNode;
     173                 :   nsCOMPtr<nsINode> mFirst;
     174                 :   nsCOMPtr<nsINode> mLast;
     175                 :   nsCOMPtr<nsINode> mCommonParent;
     176                 : 
     177                 :   // used by nsContentIterator to cache indices
     178                 :   nsAutoTArray<PRInt32, 8> mIndexes;
     179                 : 
     180                 :   // used by nsSubtreeIterator to cache indices.  Why put them in the base class?
     181                 :   // Because otherwise I have to duplicate the routines GetNextSibling etc across both classes,
     182                 :   // with slight variations for caching.  Or alternately, create a base class for the cache
     183                 :   // itself and have all the cache manipulation go through a vptr.
     184                 :   // I think this is the best space and speed combo, even though it's ugly.
     185                 :   PRInt32 mCachedIndex;
     186                 :   // another note about mCachedIndex: why should the subtree iterator use a trivial cached index
     187                 :   // instead of the mre robust array of indicies (which is what the basic content iterator uses)?
     188                 :   // The reason is that subtree iterators do not do much transitioning between parents and children.
     189                 :   // They tend to stay at the same level.  In fact, you can prove (though I won't attempt it here)
     190                 :   // that they change levels at most n+m times, where n is the height of the parent hierarchy from the 
     191                 :   // range start to the common ancestor, and m is the the height of the parent hierarchy from the 
     192                 :   // range end to the common ancestor.  If we used the index array, we would pay the price up front
     193                 :   // for n, and then pay the cost for m on the fly later on.  With the simple cache, we only "pay
     194                 :   // as we go".  Either way, we call IndexOf() once for each change of level in the hierarchy.
     195                 :   // Since a trivial index is much simpler, we use it for the subtree iterator.
     196                 :   
     197                 :   bool mIsDone;
     198                 :   bool mPre;
     199                 :   
     200                 : private:
     201                 : 
     202                 :   // no copy's or assigns  FIX ME
     203                 :   nsContentIterator(const nsContentIterator&);
     204                 :   nsContentIterator& operator=(const nsContentIterator&);
     205                 : 
     206                 : };
     207                 : 
     208                 : 
     209                 : /******************************************************
     210                 :  * repository cruft
     211                 :  ******************************************************/
     212                 : 
     213               0 : nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult)
     214                 : {
     215               0 :   nsContentIterator * iter = new nsContentIterator(false);
     216               0 :   if (!iter) {
     217               0 :     return NS_ERROR_OUT_OF_MEMORY;
     218                 :   }
     219                 : 
     220               0 :   NS_ADDREF(*aInstancePtrResult = iter);
     221                 : 
     222               0 :   return NS_OK;
     223                 : }
     224                 : 
     225                 : 
     226               0 : nsresult NS_NewPreContentIterator(nsIContentIterator** aInstancePtrResult)
     227                 : {
     228               0 :   nsContentIterator * iter = new nsContentIterator(true);
     229               0 :   if (!iter) {
     230               0 :     return NS_ERROR_OUT_OF_MEMORY;
     231                 :   }
     232                 : 
     233               0 :   NS_ADDREF(*aInstancePtrResult = iter);
     234                 : 
     235               0 :   return NS_OK;
     236                 : }
     237                 : 
     238                 : 
     239                 : /******************************************************
     240                 :  * XPCOM cruft
     241                 :  ******************************************************/
     242                 :  
     243              12 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator)
     244              12 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentIterator)
     245                 : 
     246               6 : NS_INTERFACE_MAP_BEGIN(nsContentIterator)
     247               6 :   NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
     248               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
     249               0 :   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator)
     250               0 : NS_INTERFACE_MAP_END
     251                 : 
     252            1464 : NS_IMPL_CYCLE_COLLECTION_4(nsContentIterator,
     253                 :                            mCurNode,
     254                 :                            mFirst,
     255                 :                            mLast,
     256                 :                            mCommonParent)
     257                 : 
     258                 : /******************************************************
     259                 :  * constructor/destructor
     260                 :  ******************************************************/
     261                 : 
     262               6 : nsContentIterator::nsContentIterator(bool aPre) :
     263                 :   // don't need to explicitly initialize |nsCOMPtr|s, they will automatically be NULL
     264               6 :   mCachedIndex(0), mIsDone(false), mPre(aPre)
     265                 : {
     266               6 : }
     267                 : 
     268                 : 
     269               6 : nsContentIterator::~nsContentIterator()
     270                 : {
     271              12 : }
     272                 : 
     273                 : 
     274                 : /******************************************************
     275                 :  * Init routines
     276                 :  ******************************************************/
     277                 : 
     278                 : 
     279                 : nsresult
     280               0 : nsContentIterator::Init(nsINode* aRoot)
     281                 : {
     282               0 :   if (!aRoot) 
     283               0 :     return NS_ERROR_NULL_POINTER; 
     284                 : 
     285               0 :   mIsDone = false;
     286               0 :   mIndexes.Clear();
     287                 :   
     288               0 :   if (mPre)
     289                 :   {
     290               0 :     mFirst = aRoot;
     291               0 :     mLast  = GetDeepLastChild(aRoot, nsnull);
     292                 :   }
     293                 :   else
     294                 :   {
     295               0 :     mFirst = GetDeepFirstChild(aRoot, nsnull); 
     296               0 :     mLast  = aRoot;
     297                 :   }
     298                 : 
     299               0 :   mCommonParent = aRoot;
     300               0 :   mCurNode = mFirst;
     301               0 :   RebuildIndexStack();
     302               0 :   return NS_OK;
     303                 : }
     304                 : 
     305                 : nsresult
     306               0 : nsContentIterator::Init(nsIDOMRange* aDOMRange)
     307                 : {
     308               0 :   NS_ENSURE_ARG_POINTER(aDOMRange);
     309               0 :   nsRange* range = static_cast<nsRange*>(aDOMRange);
     310                 : 
     311               0 :   mIsDone = false;
     312                 : 
     313                 :   // get common content parent
     314               0 :   mCommonParent = range->GetCommonAncestor();
     315               0 :   NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE);
     316                 : 
     317                 :   // get the start node and offset
     318               0 :   PRInt32 startIndx = range->StartOffset();
     319               0 :   nsINode* startNode = range->GetStartParent();
     320               0 :   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
     321                 : 
     322                 :   // get the end node and offset
     323               0 :   PRInt32 endIndx = range->EndOffset();
     324               0 :   nsINode* endNode = range->GetEndParent();
     325               0 :   NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
     326                 : 
     327               0 :   bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
     328                 : 
     329                 :   // short circuit when start node == end node
     330               0 :   if (startNode == endNode)
     331                 :   {
     332                 :     // Check to see if we have a collapsed range, if so,
     333                 :     // there is nothing to iterate over.
     334                 :     //
     335                 :     // XXX: CharacterDataNodes (text nodes) are currently an exception,
     336                 :     //      since we always want to be able to iterate text nodes at
     337                 :     //      the end points of a range.
     338                 : 
     339               0 :     if (!startIsData && startIndx == endIndx)
     340                 :     {
     341               0 :       MakeEmpty();
     342               0 :       return NS_OK;
     343                 :     }
     344                 : 
     345               0 :     if (startIsData)
     346                 :     {
     347                 :       // It's a textnode.
     348               0 :       NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
     349                 :                    "Data node that's not content?");
     350                 : 
     351               0 :       mFirst   = static_cast<nsIContent*>(startNode);
     352               0 :       mLast    = mFirst;
     353               0 :       mCurNode = mFirst;
     354                 : 
     355               0 :       RebuildIndexStack();
     356               0 :       return NS_OK;
     357                 :     }
     358                 :   }
     359                 :   
     360                 :   // Find first node in range.
     361                 : 
     362               0 :   nsIContent *cChild = nsnull;
     363                 : 
     364               0 :   if (!startIsData && NodeHasChildren(startNode))
     365               0 :     cChild = startNode->GetChildAt(startIndx);
     366                 : 
     367               0 :   if (!cChild) // no children, must be a text node
     368                 :   {
     369                 :     // XXXbz no children might also just mean no children.  So I'm not
     370                 :     // sure what that comment above is talking about.
     371               0 :     if (mPre)
     372                 :     {
     373                 :       // XXX: In the future, if start offset is after the last
     374                 :       //      character in the cdata node, should we set mFirst to
     375                 :       //      the next sibling?
     376                 : 
     377               0 :       if (!startIsData)
     378                 :       {
     379               0 :         mFirst = GetNextSibling(startNode, nsnull);
     380                 : 
     381                 :         // Does mFirst node really intersect the range?
     382                 :         // The range could be 'degenerate', ie not collapsed 
     383                 :         // but still contain no content.
     384                 :   
     385               0 :         if (mFirst &&
     386                 :             !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
     387               0 :                                     endNode, endIndx)) {
     388               0 :           mFirst = nsnull;
     389                 :         }
     390                 :       }
     391                 :       else {
     392               0 :         NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
     393                 :                    "Data node that's not content?");
     394                 : 
     395               0 :         mFirst = static_cast<nsIContent*>(startNode);
     396                 :       }
     397                 :     }
     398                 :     else {
     399                 :       // post-order
     400               0 :       if (startNode->IsNodeOfType(nsINode::eCONTENT)) {
     401               0 :         mFirst = static_cast<nsIContent*>(startNode);
     402                 :       } else {
     403                 :         // What else can we do?
     404               0 :         mFirst = nsnull;
     405                 :       }
     406                 :     }
     407                 :   }
     408                 :   else
     409                 :   {
     410               0 :     if (mPre)
     411               0 :       mFirst = cChild;
     412                 :     else // post-order
     413                 :     {
     414               0 :       mFirst = GetDeepFirstChild(cChild, nsnull);
     415                 : 
     416                 :       // Does mFirst node really intersect the range?
     417                 :       // The range could be 'degenerate', ie not collapsed 
     418                 :       // but still contain no content.
     419                 :   
     420               0 :       if (mFirst &&
     421                 :           !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
     422               0 :                                   endNode, endIndx))
     423               0 :         mFirst = nsnull;
     424                 :     }
     425                 :   }
     426                 : 
     427                 : 
     428                 :   // Find last node in range.
     429                 : 
     430               0 :   bool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);
     431                 : 
     432               0 :   if (endIsData || !NodeHasChildren(endNode) || endIndx == 0)
     433                 :   {
     434               0 :     if (mPre) {
     435               0 :       if (endNode->IsNodeOfType(nsINode::eCONTENT)) {
     436               0 :         mLast = static_cast<nsIContent*>(endNode);
     437                 :       } else {
     438                 :         // Not much else to do here...
     439               0 :         mLast = nsnull;
     440                 :       }
     441                 :     }
     442                 :     else // post-order
     443                 :     {
     444                 :       // XXX: In the future, if end offset is before the first
     445                 :       //      character in the cdata node, should we set mLast to
     446                 :       //      the prev sibling?
     447                 : 
     448               0 :       if (!endIsData)
     449                 :       {
     450               0 :         mLast = GetPrevSibling(endNode, nsnull);
     451                 : 
     452               0 :         if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
     453               0 :                                     endNode, endIndx))
     454               0 :           mLast = nsnull;
     455                 :       }
     456                 :       else {
     457               0 :         NS_ASSERTION(endNode->IsNodeOfType(nsINode::eCONTENT),
     458                 :                      "Data node that's not content?");
     459                 : 
     460               0 :         mLast = static_cast<nsIContent*>(endNode);
     461                 :       }
     462                 :     }
     463                 :   }
     464                 :   else
     465                 :   {
     466               0 :     PRInt32 indx = endIndx;
     467                 : 
     468               0 :     cChild = endNode->GetChildAt(--indx);
     469                 : 
     470               0 :     if (!cChild)  // No child at offset!
     471                 :     {
     472               0 :       NS_NOTREACHED("nsContentIterator::nsContentIterator");
     473               0 :       return NS_ERROR_FAILURE; 
     474                 :     }
     475                 : 
     476               0 :     if (mPre)
     477                 :     {
     478               0 :       mLast  = GetDeepLastChild(cChild, nsnull);
     479                 : 
     480               0 :       if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
     481               0 :                                   endNode, endIndx)) {
     482               0 :         mLast = nsnull;
     483                 :       }
     484                 :     }
     485                 :     else { // post-order 
     486               0 :       mLast = cChild;
     487                 :     }
     488                 :   }
     489                 : 
     490                 :   // If either first or last is null, they both
     491                 :   // have to be null!
     492                 : 
     493               0 :   if (!mFirst || !mLast)
     494                 :   {
     495               0 :     mFirst = nsnull;
     496               0 :     mLast  = nsnull;
     497                 :   }
     498                 :   
     499               0 :   mCurNode = mFirst;
     500               0 :   mIsDone  = !mCurNode;
     501                 : 
     502               0 :   if (!mCurNode)
     503               0 :     mIndexes.Clear();
     504                 :   else
     505               0 :     RebuildIndexStack();
     506                 : 
     507               0 :   return NS_OK;
     508                 : }
     509                 : 
     510                 : 
     511                 : /******************************************************
     512                 :  * Helper routines
     513                 :  ******************************************************/
     514                 : // WARNING: This function is expensive
     515               0 : nsresult nsContentIterator::RebuildIndexStack()
     516                 : {
     517                 :   // Make sure we start at the right indexes on the stack!  Build array up
     518                 :   // to common parent of start and end.  Perhaps it's too many entries, but
     519                 :   // that's far better than too few.
     520                 :   nsINode* parent;
     521                 :   nsINode* current;
     522                 : 
     523               0 :   mIndexes.Clear();
     524               0 :   current = mCurNode;
     525               0 :   if (!current) {
     526               0 :     return NS_OK;
     527                 :   }
     528                 : 
     529               0 :   while (current != mCommonParent)
     530                 :   {
     531               0 :     parent = current->GetNodeParent();
     532                 :     
     533               0 :     if (!parent)
     534               0 :       return NS_ERROR_FAILURE;
     535                 :   
     536               0 :     mIndexes.InsertElementAt(0, parent->IndexOf(current));
     537                 : 
     538               0 :     current = parent;
     539                 :   }
     540               0 :   return NS_OK;
     541                 : }
     542                 : 
     543                 : void
     544               0 : nsContentIterator::MakeEmpty()
     545                 : {
     546               0 :   mCurNode      = nsnull;
     547               0 :   mFirst        = nsnull;
     548               0 :   mLast         = nsnull;
     549               0 :   mCommonParent = nsnull;
     550               0 :   mIsDone       = true;
     551               0 :   mIndexes.Clear();
     552               0 : }
     553                 : 
     554                 : nsINode*
     555              10 : nsContentIterator::GetDeepFirstChild(nsINode *aRoot,
     556                 :                                      nsTArray<PRInt32> *aIndexes)
     557                 : {
     558              10 :   if (!aRoot) {
     559               0 :     return nsnull;
     560                 :   }
     561                 : 
     562              10 :   nsINode *n = aRoot;
     563              10 :   nsINode *nChild = n->GetFirstChild();
     564                 : 
     565              22 :   while (nChild)
     566                 :   {
     567               2 :     if (aIndexes)
     568                 :     {
     569                 :       // Add this node to the stack of indexes
     570               0 :       aIndexes->AppendElement(0);
     571                 :     }
     572               2 :     n = nChild;
     573               2 :     nChild = n->GetFirstChild();
     574                 :   }
     575                 : 
     576              10 :   return n;
     577                 : }
     578                 : 
     579                 : nsINode*
     580              10 : nsContentIterator::GetDeepLastChild(nsINode *aRoot, nsTArray<PRInt32> *aIndexes)
     581                 : {
     582              10 :   if (!aRoot) {
     583               0 :     return nsnull;
     584                 :   }
     585                 : 
     586              10 :   nsINode *deepLastChild = aRoot;
     587                 : 
     588              10 :   nsINode *n = aRoot;
     589              10 :   PRInt32 numChildren = n->GetChildCount();
     590                 : 
     591              22 :   while (numChildren)
     592                 :   {
     593               2 :     nsINode *nChild = n->GetChildAt(--numChildren);
     594                 : 
     595               2 :     if (aIndexes)
     596                 :     {
     597                 :       // Add this node to the stack of indexes
     598               0 :       aIndexes->AppendElement(numChildren);
     599                 :     }
     600               2 :     numChildren = nChild->GetChildCount();
     601               2 :     n = nChild;
     602                 : 
     603               2 :     deepLastChild = n;
     604                 :   }
     605                 : 
     606              10 :   return deepLastChild;
     607                 : }
     608                 : 
     609                 : // Get the next sibling, or parents next sibling, or grandpa's next sibling...
     610                 : nsINode *
     611               2 : nsContentIterator::GetNextSibling(nsINode *aNode, 
     612                 :                                   nsTArray<PRInt32> *aIndexes)
     613                 : {
     614               2 :   if (!aNode) 
     615               0 :     return nsnull;
     616                 : 
     617               2 :   nsINode *parent = aNode->GetNodeParent();
     618               2 :   if (!parent)
     619               0 :     return nsnull;
     620                 : 
     621               2 :   PRInt32 indx = 0;
     622                 : 
     623               2 :   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
     624                 :                "ContentIterator stack underflow");
     625               2 :   if (aIndexes && !aIndexes->IsEmpty())
     626                 :   {
     627                 :     // use the last entry on the Indexes array for the current index
     628               0 :     indx = (*aIndexes)[aIndexes->Length()-1];
     629                 :   }
     630                 :   else
     631               2 :     indx = mCachedIndex;
     632                 : 
     633                 :   // reverify that the index of the current node hasn't changed.
     634                 :   // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
     635                 :   // ignore result this time - the index may now be out of range.
     636               2 :   nsINode *sib = parent->GetChildAt(indx);
     637               2 :   if (sib != aNode)
     638                 :   {
     639                 :     // someone changed our index - find the new index the painful way
     640               2 :     indx = parent->IndexOf(aNode);
     641                 :   }
     642                 : 
     643                 :   // indx is now canonically correct
     644               2 :   if ((sib = parent->GetChildAt(++indx)))
     645                 :   {
     646                 :     // update index cache
     647               2 :     if (aIndexes && !aIndexes->IsEmpty())
     648                 :     {
     649               0 :       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
     650                 :     }
     651               2 :     else mCachedIndex = indx;
     652                 :   }
     653                 :   else
     654                 :   {
     655               0 :     if (parent != mCommonParent)
     656                 :     {
     657               0 :       if (aIndexes)
     658                 :       {
     659                 :         // pop node off the stack, go up one level and return parent or fail.
     660                 :         // Don't leave the index empty, especially if we're
     661                 :         // returning NULL.  This confuses other parts of the code.
     662               0 :         if (aIndexes->Length() > 1)
     663               0 :           aIndexes->RemoveElementAt(aIndexes->Length()-1);
     664                 :       }
     665                 :     }
     666                 : 
     667                 :     // ok to leave cache out of date here if parent == mCommonParent?
     668               0 :     sib = GetNextSibling(parent, aIndexes);
     669                 :   }
     670                 :   
     671               2 :   return sib;
     672                 : }
     673                 : 
     674                 : // Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
     675                 : nsINode*
     676               6 : nsContentIterator::GetPrevSibling(nsINode *aNode, 
     677                 :                                   nsTArray<PRInt32> *aIndexes)
     678                 : {
     679               6 :   if (!aNode)
     680               0 :     return nsnull;
     681                 : 
     682               6 :   nsINode *parent = aNode->GetNodeParent();
     683               6 :   if (!parent)
     684               0 :     return nsnull;
     685                 : 
     686               6 :   PRInt32 indx = 0;
     687                 : 
     688               6 :   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
     689                 :                "ContentIterator stack underflow");
     690               6 :   if (aIndexes && !aIndexes->IsEmpty())
     691                 :   {
     692                 :     // use the last entry on the Indexes array for the current index
     693               0 :     indx = (*aIndexes)[aIndexes->Length()-1];
     694                 :   }
     695                 :   else
     696               6 :     indx = mCachedIndex;
     697                 : 
     698                 :   // reverify that the index of the current node hasn't changed
     699                 :   // ignore result this time - the index may now be out of range.
     700               6 :   nsINode *sib = parent->GetChildAt(indx);
     701               6 :   if (sib != aNode)
     702                 :   {
     703                 :     // someone changed our index - find the new index the painful way
     704               6 :     indx = parent->IndexOf(aNode);
     705                 :   }
     706                 : 
     707                 :   // indx is now canonically correct
     708               6 :   if (indx > 0 && (sib = parent->GetChildAt(--indx)))
     709                 :   {
     710                 :     // update index cache
     711               6 :     if (aIndexes && !aIndexes->IsEmpty())
     712                 :     {
     713               0 :       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
     714                 :     }
     715               6 :     else mCachedIndex = indx;
     716                 :   }
     717               0 :   else if (parent != mCommonParent)
     718                 :   {
     719               0 :     if (aIndexes && !aIndexes->IsEmpty())
     720                 :     {
     721                 :       // pop node off the stack, go up one level and try again.
     722               0 :       aIndexes->RemoveElementAt(aIndexes->Length()-1);
     723                 :     }
     724               0 :     return GetPrevSibling(parent, aIndexes);
     725                 :   }
     726                 : 
     727               6 :   return sib;
     728                 : }
     729                 : 
     730                 : nsINode*
     731               0 : nsContentIterator::NextNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes)
     732                 : {
     733               0 :   nsINode *n = aNode;
     734               0 :   nsINode *nextNode = nsnull;
     735                 : 
     736               0 :   if (mPre)  // if we are a Pre-order iterator, use pre-order
     737                 :   {
     738                 :     // if it has children then next node is first child
     739               0 :     if (NodeHasChildren(n))
     740                 :     {
     741               0 :       nsINode *nFirstChild = n->GetFirstChild();
     742                 : 
     743                 :       // update cache
     744               0 :       if (aIndexes)
     745                 :       {
     746                 :         // push an entry on the index stack
     747               0 :         aIndexes->AppendElement(0);
     748                 :       }
     749               0 :       else mCachedIndex = 0;
     750                 :       
     751               0 :       return nFirstChild;
     752                 :     }
     753                 : 
     754                 :     // else next sibling is next
     755               0 :     nextNode = GetNextSibling(n, aIndexes);
     756                 :   }
     757                 :   else  // post-order
     758                 :   {
     759               0 :     nsINode *parent = n->GetNodeParent();
     760               0 :     nsINode *nSibling = nsnull;
     761               0 :     PRInt32 indx = 0;
     762                 : 
     763                 :     // get the cached index
     764               0 :     NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
     765                 :                  "ContentIterator stack underflow");
     766               0 :     if (aIndexes && !aIndexes->IsEmpty())
     767                 :     {
     768                 :       // use the last entry on the Indexes array for the current index
     769               0 :       indx = (*aIndexes)[aIndexes->Length()-1];
     770                 :     }
     771               0 :     else indx = mCachedIndex;
     772                 : 
     773                 :     // reverify that the index of the current node hasn't changed.
     774                 :     // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
     775                 :     // ignore result this time - the index may now be out of range.
     776               0 :     if (indx >= 0)
     777               0 :       nSibling = parent->GetChildAt(indx);
     778               0 :     if (nSibling != n)
     779                 :     {
     780                 :       // someone changed our index - find the new index the painful way
     781               0 :       indx = parent->IndexOf(n);
     782                 :     }
     783                 : 
     784                 :     // indx is now canonically correct
     785               0 :     nSibling = parent->GetChildAt(++indx);
     786               0 :     if (nSibling)
     787                 :     {
     788                 :       // update cache
     789               0 :       if (aIndexes && !aIndexes->IsEmpty())
     790                 :       {
     791                 :         // replace an entry on the index stack
     792               0 :         aIndexes->ElementAt(aIndexes->Length()-1) = indx;
     793                 :       }
     794               0 :       else mCachedIndex = indx;
     795                 :       
     796                 :       // next node is siblings "deep left" child
     797               0 :       return GetDeepFirstChild(nSibling, aIndexes); 
     798                 :     }
     799                 :   
     800                 :     // else it's the parent
     801                 :     // update cache
     802               0 :     if (aIndexes)
     803                 :     {
     804                 :       // pop an entry off the index stack
     805                 :       // Don't leave the index empty, especially if we're
     806                 :       // returning NULL.  This confuses other parts of the code.
     807               0 :       if (aIndexes->Length() > 1)
     808               0 :         aIndexes->RemoveElementAt(aIndexes->Length()-1);
     809                 :     }
     810               0 :     else mCachedIndex = 0;   // this might be wrong, but we are better off guessing
     811               0 :     nextNode = parent;
     812                 :   }
     813                 : 
     814               0 :   return nextNode;
     815                 : }
     816                 : 
     817                 : nsINode*
     818               4 : nsContentIterator::PrevNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes)
     819                 : {
     820               4 :   nsINode *prevNode = nsnull;
     821               4 :   nsINode *n = aNode;
     822                 :    
     823               4 :   if (mPre)  // if we are a Pre-order iterator, use pre-order
     824                 :   {
     825               0 :     nsINode *parent = n->GetNodeParent();
     826               0 :     nsINode *nSibling = nsnull;
     827               0 :     PRInt32 indx = 0;
     828                 : 
     829                 :     // get the cached index
     830               0 :     NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
     831                 :                  "ContentIterator stack underflow");
     832               0 :     if (aIndexes && !aIndexes->IsEmpty())
     833                 :     {
     834                 :       // use the last entry on the Indexes array for the current index
     835               0 :       indx = (*aIndexes)[aIndexes->Length()-1];
     836                 :     }
     837               0 :     else indx = mCachedIndex;
     838                 : 
     839                 :     // reverify that the index of the current node hasn't changed.
     840                 :     // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
     841                 :     // ignore result this time - the index may now be out of range.
     842               0 :     if (indx >= 0)
     843               0 :       nSibling = parent->GetChildAt(indx);
     844                 : 
     845               0 :     if (nSibling != n)
     846                 :     {
     847                 :       // someone changed our index - find the new index the painful way
     848               0 :       indx = parent->IndexOf(n);
     849                 :     }
     850                 : 
     851                 :     // indx is now canonically correct
     852               0 :     if (indx && (nSibling = parent->GetChildAt(--indx)))
     853                 :     {
     854                 :       // update cache
     855               0 :       if (aIndexes && !aIndexes->IsEmpty())
     856                 :       {
     857                 :         // replace an entry on the index stack
     858               0 :         aIndexes->ElementAt(aIndexes->Length()-1) = indx;
     859                 :       }
     860               0 :       else mCachedIndex = indx;
     861                 :       
     862                 :       // prev node is siblings "deep right" child
     863               0 :       return GetDeepLastChild(nSibling, aIndexes); 
     864                 :     }
     865                 :   
     866                 :     // else it's the parent
     867                 :     // update cache
     868               0 :     if (aIndexes && !aIndexes->IsEmpty())
     869                 :     {
     870                 :       // pop an entry off the index stack
     871               0 :       aIndexes->RemoveElementAt(aIndexes->Length()-1);
     872                 :     }
     873               0 :     else mCachedIndex = 0;   // this might be wrong, but we are better off guessing
     874               0 :     prevNode = parent;
     875                 :   }
     876                 :   else  // post-order
     877                 :   {
     878               4 :     PRInt32 numChildren = n->GetChildCount();
     879                 :   
     880                 :     // if it has children then prev node is last child
     881               4 :     if (numChildren)
     882                 :     {
     883               0 :       nsINode *nLastChild = n->GetLastChild();
     884               0 :       numChildren--;
     885                 : 
     886                 :       // update cache
     887               0 :       if (aIndexes)
     888                 :       {
     889                 :         // push an entry on the index stack
     890               0 :         aIndexes->AppendElement(numChildren);
     891                 :       }
     892               0 :       else mCachedIndex = numChildren;
     893                 :       
     894               0 :       return nLastChild;
     895                 :     }
     896                 : 
     897                 :     // else prev sibling is previous
     898               4 :     prevNode = GetPrevSibling(n, aIndexes);
     899                 :   }
     900                 : 
     901               4 :   return prevNode;
     902                 : }
     903                 : 
     904                 : /******************************************************
     905                 :  * ContentIterator routines
     906                 :  ******************************************************/
     907                 : 
     908                 : void
     909               0 : nsContentIterator::First()
     910                 : {
     911               0 :   if (mFirst) {
     912                 : #ifdef DEBUG
     913                 :     nsresult rv =
     914                 : #endif
     915               0 :     PositionAt(mFirst);
     916                 : 
     917               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
     918                 :   }
     919                 : 
     920               0 :   mIsDone = mFirst == nsnull;
     921               0 : }
     922                 : 
     923                 : 
     924                 : void
     925               0 : nsContentIterator::Last()
     926                 : {
     927               0 :   NS_ASSERTION(mLast, "No last node!");
     928                 : 
     929               0 :   if (mLast) {
     930                 : #ifdef DEBUG
     931                 :     nsresult rv =
     932                 : #endif
     933               0 :     PositionAt(mLast);
     934                 : 
     935               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
     936                 :   }
     937                 : 
     938               0 :   mIsDone = mLast == nsnull;
     939               0 : }
     940                 : 
     941                 : 
     942                 : void
     943               0 : nsContentIterator::Next()
     944                 : {
     945               0 :   if (mIsDone || !mCurNode) 
     946               0 :     return;
     947                 : 
     948               0 :   if (mCurNode == mLast) 
     949                 :   {
     950               0 :     mIsDone = true;
     951               0 :     return;
     952                 :   }
     953                 : 
     954               0 :   mCurNode = NextNode(mCurNode, &mIndexes);
     955                 : }
     956                 : 
     957                 : 
     958                 : void
     959               0 : nsContentIterator::Prev()
     960                 : {
     961               0 :   if (mIsDone || !mCurNode) 
     962               0 :     return;
     963                 : 
     964               0 :   if (mCurNode == mFirst) 
     965                 :   {
     966               0 :     mIsDone = true;
     967               0 :     return;
     968                 :   }
     969                 : 
     970               0 :   mCurNode = PrevNode(mCurNode, &mIndexes);
     971                 : }
     972                 : 
     973                 : 
     974                 : bool
     975              16 : nsContentIterator::IsDone()
     976                 : {
     977              16 :   return mIsDone;
     978                 : }
     979                 : 
     980                 : 
     981                 : // Keeping arrays of indexes for the stack of nodes makes PositionAt
     982                 : // interesting...
     983                 : nsresult
     984               0 : nsContentIterator::PositionAt(nsINode* aCurNode)
     985                 : {
     986               0 :   if (!aCurNode)
     987               0 :     return NS_ERROR_NULL_POINTER;
     988                 : 
     989               0 :   nsINode *newCurNode = aCurNode;
     990               0 :   nsINode *tempNode = mCurNode;
     991                 : 
     992               0 :   mCurNode = aCurNode;
     993                 :   // take an early out if this doesn't actually change the position
     994               0 :   if (mCurNode == tempNode)
     995                 :   {
     996               0 :     mIsDone = false;  // paranoia
     997               0 :     return NS_OK;
     998                 :   }
     999                 : 
    1000                 :   // Check to see if the node falls within the traversal range.
    1001                 : 
    1002               0 :   nsINode* firstNode = mFirst;
    1003               0 :   nsINode* lastNode = mLast;
    1004               0 :   PRInt32 firstOffset=0, lastOffset=0;
    1005                 : 
    1006               0 :   if (firstNode && lastNode)
    1007                 :   {
    1008               0 :     if (mPre)
    1009                 :     {
    1010               0 :       firstNode = NodeToParentOffset(mFirst, &firstOffset);
    1011                 : 
    1012               0 :       if (lastNode->GetChildCount())
    1013               0 :         lastOffset = 0;
    1014                 :       else
    1015                 :       {
    1016               0 :         lastNode = NodeToParentOffset(mLast, &lastOffset);
    1017               0 :         ++lastOffset;
    1018                 :       }
    1019                 :     }
    1020                 :     else
    1021                 :     {
    1022               0 :       PRUint32 numChildren = firstNode->GetChildCount();
    1023                 : 
    1024               0 :       if (numChildren)
    1025               0 :         firstOffset = numChildren;
    1026                 :       else
    1027               0 :         firstNode = NodeToParentOffset(mFirst, &firstOffset);
    1028                 : 
    1029               0 :       lastNode = NodeToParentOffset(mLast, &lastOffset);
    1030               0 :       ++lastOffset;
    1031                 :     }
    1032                 :   }
    1033                 : 
    1034                 :   // The end positions are always in the range even if it has no parent.
    1035                 :   // We need to allow that or 'iter->Init(root)' would assert in Last()
    1036                 :   // or First() for example, bug 327694.
    1037               0 :   if (mFirst != mCurNode && mLast != mCurNode &&
    1038                 :       (!firstNode || !lastNode ||
    1039                 :        !NodeIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset,
    1040               0 :                                lastNode, lastOffset)))
    1041                 :   {
    1042               0 :     mIsDone = true;
    1043               0 :     return NS_ERROR_FAILURE;
    1044                 :   }
    1045                 : 
    1046                 :   // We can be at ANY node in the sequence.
    1047                 :   // Need to regenerate the array of indexes back to the root or common parent!
    1048               0 :   nsAutoTArray<nsINode*, 8>     oldParentStack;
    1049               0 :   nsAutoTArray<PRInt32, 8>      newIndexes;
    1050                 : 
    1051                 :   // Get a list of the parents up to the root, then compare the new node
    1052                 :   // with entries in that array until we find a match (lowest common
    1053                 :   // ancestor).  If no match, use IndexOf, take the parent, and repeat.
    1054                 :   // This avoids using IndexOf() N times on possibly large arrays.  We
    1055                 :   // still end up doing it a fair bit.  It's better to use Clone() if
    1056                 :   // possible.
    1057                 : 
    1058                 :   // we know the depth we're down (though we may not have started at the
    1059                 :   // top).
    1060               0 :   if (!oldParentStack.SetCapacity(mIndexes.Length()+1))
    1061               0 :     return NS_ERROR_FAILURE;
    1062                 : 
    1063                 :   // We want to loop mIndexes.Length() + 1 times here, because we want to make
    1064                 :   // sure we include mCommonParent in the oldParentStack, for use in the next
    1065                 :   // for loop, and mIndexes only has entries for nodes from tempNode up through
    1066                 :   // an ancestor of tempNode that's a child of mCommonParent.
    1067               0 :   for (PRInt32 i = mIndexes.Length()+1; i > 0 && tempNode; i--)
    1068                 :   {
    1069                 :     // Insert at head since we're walking up
    1070               0 :     oldParentStack.InsertElementAt(0, tempNode);
    1071                 : 
    1072               0 :     nsINode *parent = tempNode->GetNodeParent();
    1073                 : 
    1074               0 :     if (!parent)  // this node has no parent, and thus no index
    1075               0 :       break;
    1076                 : 
    1077               0 :     if (parent == mCurNode)
    1078                 :     {
    1079                 :       // The position was moved to a parent of the current position. 
    1080                 :       // All we need to do is drop some indexes.  Shortcut here.
    1081               0 :       mIndexes.RemoveElementsAt(mIndexes.Length() - oldParentStack.Length(),
    1082               0 :                                 oldParentStack.Length());
    1083               0 :       mIsDone = false;
    1084               0 :       return NS_OK;
    1085                 :     }
    1086               0 :     tempNode = parent;
    1087                 :   }
    1088                 : 
    1089                 :   // Ok.  We have the array of old parents.  Look for a match.
    1090               0 :   while (newCurNode)
    1091                 :   {
    1092               0 :     nsINode *parent = newCurNode->GetNodeParent();
    1093                 : 
    1094               0 :     if (!parent)  // this node has no parent, and thus no index
    1095               0 :       break;
    1096                 : 
    1097               0 :     PRInt32 indx = parent->IndexOf(newCurNode);
    1098                 : 
    1099                 :     // insert at the head!
    1100               0 :     newIndexes.InsertElementAt(0, indx);
    1101                 : 
    1102                 :     // look to see if the parent is in the stack
    1103               0 :     indx = oldParentStack.IndexOf(parent);
    1104               0 :     if (indx >= 0)
    1105                 :     {
    1106                 :       // ok, the parent IS on the old stack!  Rework things.
    1107                 :       // we want newIndexes to replace all nodes equal to or below the match
    1108                 :       // Note that index oldParentStack.Length()-1 is the last node, which is
    1109                 :       // one BELOW the last index in the mIndexes stack.  In other words, we
    1110                 :       // want to remove elements starting at index (indx+1).
    1111               0 :       PRInt32 numToDrop = oldParentStack.Length()-(1+indx);
    1112               0 :       if (numToDrop > 0)
    1113               0 :         mIndexes.RemoveElementsAt(mIndexes.Length() - numToDrop, numToDrop);
    1114               0 :       mIndexes.AppendElements(newIndexes);
    1115                 : 
    1116               0 :       break;
    1117                 :     }
    1118               0 :     newCurNode = parent;
    1119                 :   }
    1120                 : 
    1121                 :   // phew!
    1122                 : 
    1123               0 :   mIsDone = false;
    1124               0 :   return NS_OK;
    1125                 : }
    1126                 : 
    1127                 : nsINode*
    1128              13 : nsContentIterator::GetCurrentNode()
    1129                 : {
    1130              13 :   if (mIsDone) {
    1131               0 :     return nsnull;
    1132                 :   }
    1133                 : 
    1134              13 :   NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
    1135                 : 
    1136              13 :   return mCurNode;
    1137                 : }
    1138                 : 
    1139                 : 
    1140                 : 
    1141                 : 
    1142                 : 
    1143                 : /*====================================================================================*/
    1144                 : /*====================================================================================*/
    1145                 : 
    1146                 : 
    1147                 : 
    1148                 : 
    1149                 : 
    1150                 : 
    1151                 : /******************************************************
    1152                 :  * nsContentSubtreeIterator
    1153                 :  ******************************************************/
    1154                 : 
    1155                 : 
    1156                 : /*
    1157                 :  *  A simple iterator class for traversing the content in "top subtree" order
    1158                 :  */
    1159                 : class nsContentSubtreeIterator : public nsContentIterator 
    1160                 : {
    1161                 : public:
    1162               6 :   nsContentSubtreeIterator() : nsContentIterator(false) {}
    1163              24 :   virtual ~nsContentSubtreeIterator() {}
    1164                 : 
    1165                 :   NS_DECL_ISUPPORTS_INHERITED
    1166            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator, nsContentIterator)
    1167                 : 
    1168                 :   // nsContentIterator overrides ------------------------------
    1169                 : 
    1170                 :   virtual nsresult Init(nsINode* aRoot);
    1171                 : 
    1172                 :   virtual nsresult Init(nsIDOMRange* aRange);
    1173                 : 
    1174                 :   virtual void Next();
    1175                 : 
    1176                 :   virtual void Prev();
    1177                 : 
    1178                 :   virtual nsresult PositionAt(nsINode* aCurNode);
    1179                 : 
    1180                 :   // Must override these because we don't do PositionAt
    1181                 :   virtual void First();
    1182                 : 
    1183                 :   // Must override these because we don't do PositionAt
    1184                 :   virtual void Last();
    1185                 : 
    1186                 : protected:
    1187                 : 
    1188                 :   nsresult GetTopAncestorInRange(nsINode *aNode,
    1189                 :                                  nsCOMPtr<nsINode> *outAnestor);
    1190                 : 
    1191                 :   // no copy's or assigns  FIX ME
    1192                 :   nsContentSubtreeIterator(const nsContentSubtreeIterator&);
    1193                 :   nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
    1194                 : 
    1195                 :   nsRefPtr<nsRange> mRange;
    1196                 :   // these arrays all typically are used and have elements
    1197                 : #if 0
    1198                 :   nsAutoTArray<nsIContent*, 8> mStartNodes;
    1199                 :   nsAutoTArray<PRInt32, 8>     mStartOffsets;
    1200                 : #endif
    1201                 : 
    1202                 :   nsAutoTArray<nsIContent*, 8> mEndNodes;
    1203                 :   nsAutoTArray<PRInt32, 8>     mEndOffsets;
    1204                 : };
    1205                 : 
    1206              12 : NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator)
    1207              12 : NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator)
    1208                 : 
    1209              12 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator)
    1210               6 : NS_INTERFACE_MAP_END_INHERITING(nsContentIterator)
    1211                 : 
    1212            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSubtreeIterator)
    1213               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsContentSubtreeIterator, nsContentIterator)
    1214               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRange, nsIDOMRange)
    1215               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1216               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsContentSubtreeIterator, nsContentIterator)
    1217               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRange)
    1218               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1219                 : 
    1220                 : nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
    1221                 : 
    1222                 : 
    1223                 : 
    1224                 : 
    1225                 : /******************************************************
    1226                 :  * repository cruft
    1227                 :  ******************************************************/
    1228                 : 
    1229               6 : nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult)
    1230                 : {
    1231               6 :   nsContentIterator * iter = new nsContentSubtreeIterator();
    1232               6 :   if (!iter) {
    1233               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1234                 :   }
    1235                 : 
    1236               6 :   NS_ADDREF(*aInstancePtrResult = iter);
    1237                 : 
    1238               6 :   return NS_OK;
    1239                 : }
    1240                 : 
    1241                 : 
    1242                 : 
    1243                 : /******************************************************
    1244                 :  * Init routines
    1245                 :  ******************************************************/
    1246                 : 
    1247                 : 
    1248               0 : nsresult nsContentSubtreeIterator::Init(nsINode* aRoot)
    1249                 : {
    1250               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1251                 : }
    1252                 : 
    1253                 : 
    1254               6 : nsresult nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
    1255                 : {
    1256               6 :   if (!aRange) 
    1257               0 :     return NS_ERROR_NULL_POINTER; 
    1258                 : 
    1259               6 :   mIsDone = false;
    1260                 : 
    1261               6 :   mRange = static_cast<nsRange*>(aRange);
    1262                 :   
    1263                 :   // get the start node and offset, convert to nsINode
    1264              12 :   nsCOMPtr<nsIDOMNode> commonParent;
    1265              12 :   nsCOMPtr<nsIDOMNode> startParent;
    1266              12 :   nsCOMPtr<nsIDOMNode> endParent;
    1267              12 :   nsCOMPtr<nsINode> nStartP;
    1268              12 :   nsCOMPtr<nsINode> nEndP;
    1269              12 :   nsCOMPtr<nsINode> n;
    1270               6 :   nsINode *firstCandidate = nsnull;
    1271               6 :   nsINode *lastCandidate = nsnull;
    1272                 :   PRInt32 indx, startIndx, endIndx;
    1273                 : 
    1274                 :   // get common content parent
    1275               6 :   if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent))) || !commonParent)
    1276               0 :     return NS_ERROR_FAILURE;
    1277               6 :   mCommonParent = do_QueryInterface(commonParent);
    1278                 : 
    1279                 :   // get start content parent
    1280               6 :   if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(startParent))) || !startParent)
    1281               0 :     return NS_ERROR_FAILURE;
    1282               6 :   nStartP = do_QueryInterface(startParent);
    1283               6 :   aRange->GetStartOffset(&startIndx);
    1284                 : 
    1285                 :   // get end content parent
    1286               6 :   if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(endParent))) || !endParent)
    1287               0 :     return NS_ERROR_FAILURE;
    1288               6 :   nEndP = do_QueryInterface(endParent);
    1289               6 :   aRange->GetEndOffset(&endIndx);
    1290                 : 
    1291                 :   // short circuit when start node == end node
    1292               6 :   if (startParent == endParent)
    1293                 :   {
    1294               4 :     nsINode* nChild = nStartP->GetFirstChild();
    1295                 :   
    1296               4 :     if (!nChild) // no children, must be a text node or empty container
    1297                 :     {
    1298                 :       // all inside one text node - empty subtree iterator
    1299               0 :       MakeEmpty();
    1300               0 :       return NS_OK;
    1301                 :     }
    1302                 :     else
    1303                 :     {
    1304               4 :       if (startIndx == endIndx)  // collapsed range
    1305                 :       {
    1306               0 :         MakeEmpty();
    1307               0 :         return NS_OK;
    1308                 :       }
    1309                 :     }
    1310                 :   }
    1311                 :   
    1312                 :   // cache ancestors
    1313                 : #if 0
    1314                 :   nsContentUtils::GetAncestorsAndOffsets(startParent, startIndx,
    1315                 :                                          &mStartNodes, &mStartOffsets);
    1316                 : #endif
    1317                 :   nsContentUtils::GetAncestorsAndOffsets(endParent, endIndx,
    1318               6 :                                          &mEndNodes, &mEndOffsets);
    1319                 : 
    1320                 :   // find first node in range
    1321               6 :   aRange->GetStartOffset(&indx);
    1322                 : 
    1323               6 :   if (!nStartP->GetChildCount()) // no children, start at the node itself
    1324                 :   {
    1325               2 :     n = nStartP;
    1326                 :   }
    1327                 :   else
    1328                 :   {
    1329               4 :     nsINode* nChild = nStartP->GetChildAt(indx);
    1330               4 :     if (!nChild)  // offset after last child
    1331                 :     {
    1332               0 :       n = nStartP;
    1333                 :     }
    1334                 :     else
    1335                 :     {
    1336               4 :       firstCandidate = nChild;
    1337                 :     }
    1338                 :   }
    1339                 :   
    1340               6 :   if (!firstCandidate)
    1341                 :   {
    1342                 :     // then firstCandidate is next node after cN
    1343               2 :     firstCandidate = GetNextSibling(n, nsnull);
    1344                 : 
    1345               2 :     if (!firstCandidate)
    1346                 :     {
    1347               0 :       MakeEmpty();
    1348               0 :       return NS_OK;
    1349                 :     }
    1350                 :   }
    1351                 :   
    1352               6 :   firstCandidate = GetDeepFirstChild(firstCandidate, nsnull);
    1353                 :   
    1354                 :   // confirm that this first possible contained node
    1355                 :   // is indeed contained.  Else we have a range that
    1356                 :   // does not fully contain any node.
    1357                 :   
    1358                 :   bool nodeBefore, nodeAfter;
    1359               6 :   if (NS_FAILED(nsRange::CompareNodeToRange(firstCandidate, mRange,
    1360                 :                                             &nodeBefore, &nodeAfter)))
    1361               0 :     return NS_ERROR_FAILURE;
    1362                 : 
    1363               6 :   if (nodeBefore || nodeAfter)
    1364                 :   {
    1365               0 :     MakeEmpty();
    1366               0 :     return NS_OK;
    1367                 :   }
    1368                 : 
    1369                 :   // cool, we have the first node in the range.  Now we walk
    1370                 :   // up its ancestors to find the most senior that is still
    1371                 :   // in the range.  That's the real first node.
    1372               6 :   if (NS_FAILED(GetTopAncestorInRange(firstCandidate, address_of(mFirst))))
    1373               0 :     return NS_ERROR_FAILURE;
    1374                 : 
    1375                 :   // now to find the last node
    1376               6 :   aRange->GetEndOffset(&indx);
    1377               6 :   PRInt32 numChildren = nEndP->GetChildCount();
    1378                 : 
    1379               6 :   if (indx > numChildren) indx = numChildren;
    1380               6 :   if (!indx)
    1381                 :   {
    1382               2 :     n = nEndP;
    1383                 :   }
    1384                 :   else
    1385                 :   {
    1386               4 :     if (!numChildren) // no children, must be a text node
    1387                 :     {
    1388               0 :       n = nEndP;
    1389                 :     }
    1390                 :     else
    1391                 :     {
    1392               4 :       lastCandidate = nEndP->GetChildAt(--indx);
    1393               4 :       NS_ASSERTION(lastCandidate,
    1394                 :                    "tree traversal trouble in nsContentSubtreeIterator::Init");
    1395                 :     }
    1396                 :   }
    1397                 :   
    1398               6 :   if (!lastCandidate)
    1399                 :   {
    1400                 :     // then lastCandidate is prev node before n
    1401               2 :     lastCandidate = GetPrevSibling(n, nsnull);
    1402                 :   }
    1403                 :   
    1404               6 :   lastCandidate = GetDeepLastChild(lastCandidate, nsnull);
    1405                 :   
    1406                 :   // confirm that this last possible contained node
    1407                 :   // is indeed contained.  Else we have a range that
    1408                 :   // does not fully contain any node.
    1409                 :   
    1410               6 :   if (NS_FAILED(nsRange::CompareNodeToRange(lastCandidate, mRange, &nodeBefore,
    1411                 :                                             &nodeAfter)))
    1412               0 :     return NS_ERROR_FAILURE;
    1413                 : 
    1414               6 :   if (nodeBefore || nodeAfter)
    1415                 :   {
    1416               0 :     MakeEmpty();
    1417               0 :     return NS_OK;
    1418                 :   }
    1419                 : 
    1420                 :   // cool, we have the last node in the range.  Now we walk
    1421                 :   // up its ancestors to find the most senior that is still
    1422                 :   // in the range.  That's the real first node.
    1423               6 :   if (NS_FAILED(GetTopAncestorInRange(lastCandidate, address_of(mLast))))
    1424               0 :     return NS_ERROR_FAILURE;
    1425                 :   
    1426               6 :   mCurNode = mFirst;
    1427                 : 
    1428               6 :   return NS_OK;
    1429                 : }
    1430                 : 
    1431                 : /****************************************************************
    1432                 :  * nsContentSubtreeIterator overrides of ContentIterator routines
    1433                 :  ****************************************************************/
    1434                 : 
    1435                 : // we can't call PositionAt in a subtree iterator...
    1436                 : void
    1437               4 : nsContentSubtreeIterator::First()
    1438                 : {
    1439               4 :   mIsDone = mFirst == nsnull;
    1440                 : 
    1441               4 :   mCurNode = mFirst;
    1442               4 : }
    1443                 : 
    1444                 : // we can't call PositionAt in a subtree iterator...
    1445                 : void
    1446               6 : nsContentSubtreeIterator::Last()
    1447                 : {
    1448               6 :   mIsDone = mLast == nsnull;
    1449                 : 
    1450               6 :   mCurNode = mLast;
    1451               6 : }
    1452                 : 
    1453                 : 
    1454                 : void
    1455               0 : nsContentSubtreeIterator::Next()
    1456                 : {
    1457               0 :   if (mIsDone || !mCurNode) 
    1458               0 :     return;
    1459                 : 
    1460               0 :   if (mCurNode == mLast) 
    1461                 :   {
    1462               0 :     mIsDone = true;
    1463               0 :     return;
    1464                 :   }
    1465                 : 
    1466               0 :   nsINode *nextNode = GetNextSibling(mCurNode, nsnull);
    1467               0 :   NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
    1468                 : 
    1469                 : /*
    1470                 :   nextNode = GetDeepFirstChild(nextNode);
    1471                 :   return GetTopAncestorInRange(nextNode, address_of(mCurNode));
    1472                 : */
    1473               0 :   PRInt32 i = mEndNodes.IndexOf(nextNode);
    1474               0 :   while (i != -1)
    1475                 :   {
    1476                 :     // as long as we are finding ancestors of the endpoint of the range,
    1477                 :     // dive down into their children
    1478               0 :     nextNode = nextNode->GetFirstChild();
    1479               0 :     NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
    1480                 : 
    1481                 :     // should be impossible to get a null pointer.  If we went all the way
    1482                 :     // down the child chain to the bottom without finding an interior node, 
    1483                 :     // then the previous node should have been the last, which was
    1484                 :     // was tested at top of routine.
    1485               0 :     i = mEndNodes.IndexOf(nextNode);
    1486                 :   }
    1487                 : 
    1488               0 :   mCurNode = nextNode;
    1489                 : 
    1490                 :   // This shouldn't be needed, but since our selection code can put us
    1491                 :   // in a situation where mLast is in generated content, we need this
    1492                 :   // to stop the iterator when we've walked past past the last node!
    1493               0 :   mIsDone = mCurNode == nsnull;
    1494                 : 
    1495               0 :   return;
    1496                 : }
    1497                 : 
    1498                 : 
    1499                 : void
    1500              10 : nsContentSubtreeIterator::Prev()
    1501                 : {
    1502                 :   // Prev should be optimized to use the mStartNodes, just as Next
    1503                 :   // uses mEndNodes.
    1504              10 :   if (mIsDone || !mCurNode) 
    1505               0 :     return;
    1506                 : 
    1507              10 :   if (mCurNode == mFirst) 
    1508                 :   {
    1509               6 :     mIsDone = true;
    1510               6 :     return;
    1511                 :   }
    1512                 : 
    1513               4 :   nsINode *prevNode = PrevNode(GetDeepFirstChild(mCurNode, nsnull), nsnull);
    1514                 : 
    1515               4 :   prevNode = GetDeepLastChild(prevNode, nsnull);
    1516                 :   
    1517               4 :   GetTopAncestorInRange(prevNode, address_of(mCurNode));
    1518                 : 
    1519                 :   // This shouldn't be needed, but since our selection code can put us
    1520                 :   // in a situation where mFirst is in generated content, we need this
    1521                 :   // to stop the iterator when we've walked past past the first node!
    1522               4 :   mIsDone = mCurNode == nsnull;
    1523                 : }
    1524                 : 
    1525                 : 
    1526                 : nsresult
    1527               0 : nsContentSubtreeIterator::PositionAt(nsINode* aCurNode)
    1528                 : {
    1529               0 :   NS_ERROR("Not implemented!");
    1530                 : 
    1531               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1532                 : }
    1533                 : 
    1534                 : /****************************************************************
    1535                 :  * nsContentSubtreeIterator helper routines
    1536                 :  ****************************************************************/
    1537                 : 
    1538                 : nsresult
    1539              16 : nsContentSubtreeIterator::GetTopAncestorInRange(nsINode *aNode,
    1540                 :                                                 nsCOMPtr<nsINode> *outAncestor)
    1541                 : {
    1542              16 :   if (!aNode) 
    1543               0 :     return NS_ERROR_NULL_POINTER;
    1544              16 :   if (!outAncestor) 
    1545               0 :     return NS_ERROR_NULL_POINTER;
    1546                 :   
    1547                 :   
    1548                 :   // sanity check: aNode is itself in the range
    1549                 :   bool nodeBefore, nodeAfter;
    1550              16 :   if (NS_FAILED(nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore,
    1551                 :                                             &nodeAfter)))
    1552               0 :     return NS_ERROR_FAILURE;
    1553                 : 
    1554              16 :   if (nodeBefore || nodeAfter)
    1555               0 :     return NS_ERROR_FAILURE;
    1556                 :   
    1557              32 :   nsCOMPtr<nsINode> parent, tmp;
    1558              36 :   while (aNode)
    1559                 :   {
    1560              20 :     parent = aNode->GetNodeParent();
    1561              20 :     if (!parent)
    1562                 :     {
    1563               0 :       if (tmp)
    1564                 :       {
    1565               0 :         *outAncestor = tmp;
    1566               0 :         return NS_OK;
    1567                 :       }
    1568               0 :       else return NS_ERROR_FAILURE;
    1569                 :     }
    1570              20 :     if (NS_FAILED(nsRange::CompareNodeToRange(parent, mRange, &nodeBefore,
    1571                 :                                               &nodeAfter)))
    1572               0 :       return NS_ERROR_FAILURE;
    1573                 : 
    1574              20 :     if (nodeBefore || nodeAfter)
    1575                 :     {
    1576              16 :       *outAncestor = aNode;
    1577              16 :       return NS_OK;
    1578                 :     }
    1579               4 :     tmp = aNode;
    1580               4 :     aNode = parent;
    1581                 :   }
    1582               0 :   return NS_ERROR_FAILURE;
    1583            4392 : }
    1584                 : 

Generated by: LCOV version 1.7