Back to index

lightning-sunbird  0.9+nobinonly
nsGeneratedIterator.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040  * nsContentIterator.cpp: Implementation of the nsContentIterator object.
00041  * This ite
00042  */
00043 #include "nsISupports.h"
00044 #include "nsIDOMNodeList.h"
00045 #include "nsIContentIterator.h"
00046 #include "nsRange.h"
00047 #include "nsIContent.h"
00048 #include "nsIDOMText.h"
00049 #include "nsISupportsArray.h"
00050 #include "nsCOMPtr.h"
00051 #include "nsPresContext.h"
00052 #include "nsIComponentManager.h"
00053 #include "nsContentCID.h"
00054 #include "nsIPresShell.h"
00055 
00056 #define DO_AFTER 1
00057 #define DO_BEFORE 1
00058 
00060 // GetNumChildren: returns the number of things inside aNode.
00061 //
00062 static PRUint32
00063 GetNumChildren(nsIDOMNode *aNode)
00064 {
00065   PRUint32 numChildren = 0;
00066   if (!aNode)
00067     return 0;
00068 
00069   PRBool hasChildNodes;
00070   aNode->HasChildNodes(&hasChildNodes);
00071   if (hasChildNodes)
00072   {
00073     nsCOMPtr<nsIDOMNodeList>nodeList;
00074     nsresult res = aNode->GetChildNodes(getter_AddRefs(nodeList));
00075     if (NS_SUCCEEDED(res) && nodeList)
00076       nodeList->GetLength(&numChildren);
00077   }
00078   return numChildren;
00079 }
00080 
00082 // GetChildAt: returns the node at this position index in the parent
00083 //
00084 static nsCOMPtr<nsIDOMNode>
00085 GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset)
00086 {
00087   nsCOMPtr<nsIDOMNode> resultNode;
00088 
00089   if (!aParent)
00090     return resultNode;
00091 
00092   PRBool hasChildNodes;
00093   aParent->HasChildNodes(&hasChildNodes);
00094   if (PR_TRUE==hasChildNodes)
00095   {
00096     nsCOMPtr<nsIDOMNodeList>nodeList;
00097     nsresult res = aParent->GetChildNodes(getter_AddRefs(nodeList));
00098     if (NS_SUCCEEDED(res) && nodeList)
00099       nodeList->Item(aOffset, getter_AddRefs(resultNode));
00100   }
00101 
00102   return resultNode;
00103 }
00104 
00105 
00106 /*
00107  *  A simple iterator class for traversing the generated content in "close tag" order
00108  */
00109 class nsGeneratedContentIterator : public nsIContentIterator,
00110                                    public nsIGeneratedContentIterator
00111 {
00112 public:
00113   NS_DECL_ISUPPORTS
00114 
00115   nsGeneratedContentIterator();
00116   virtual ~nsGeneratedContentIterator();
00117 
00118   // nsIContentIterator interface methods ------------------------------
00119 
00120   virtual nsresult Init(nsIContent* aRoot);
00121 
00122   virtual nsresult Init(nsIDOMRange* aRange);
00123 
00124   virtual void First();
00125 
00126   virtual void Last();
00127 
00128   virtual void Next();
00129 
00130   virtual void Prev();
00131 
00132   virtual nsIContent *GetCurrentNode();
00133 
00134   virtual PRBool IsDone();
00135 
00136   virtual nsresult PositionAt(nsIContent* aCurNode);
00137 
00138   // nsIEnumertor interface methods ------------------------------
00139 
00140   //NS_IMETHOD CurrentItem(nsISupports **aItem);
00141 
00142   //nsIGeneratedContentIterator
00143   virtual nsresult Init(nsIPresShell *aShell, nsIDOMRange* aRange);
00144   virtual nsresult Init(nsIPresShell *aShell, nsIContent* aContent);
00145 
00146 protected:
00147 
00148   // Do these cause too much refcounting???
00149   nsCOMPtr<nsIContent> GetDeepFirstChild(nsCOMPtr<nsIContent> aRoot);
00150   nsCOMPtr<nsIContent> GetDeepLastChild(nsCOMPtr<nsIContent> aRoot);
00151 
00152   nsIContent *GetNextSibling(nsIContent *aNode);
00153   nsIContent *GetPrevSibling(nsIContent *aNode);
00154 
00155   nsIContent *NextNode(nsIContent *aNode);
00156   nsIContent *PrevNode(nsIContent *aNode);
00157 
00158   void MakeEmpty();
00159 
00160   nsCOMPtr<nsIContent> mCurNode;
00161   nsCOMPtr<nsIContent> mFirst;
00162   nsCOMPtr<nsIContent> mLast;
00163   nsCOMPtr<nsIContent> mCommonParent;
00164 
00165   nsCOMPtr<nsIContentIterator> mFirstIter;
00166   nsCOMPtr<nsIContentIterator> mLastIter;
00167   nsCOMPtr<nsIContentIterator> mGenIter;
00168   nsIPresShell::GeneratedContentType mIterType;
00169   nsIPresShell::GeneratedContentType mFirstIterType;
00170   nsIPresShell::GeneratedContentType mLastIterType;
00171   nsCOMPtr<nsIPresShell> mPresShell;
00172   PRBool mIsDone;
00173 
00174 private:
00175 
00176   // no copy's or assigns  FIX ME
00177   nsGeneratedContentIterator(const nsGeneratedContentIterator&);
00178   nsGeneratedContentIterator& operator=(const nsGeneratedContentIterator&);
00179 
00180 };
00181 
00182 
00183 /******************************************************
00184  * repository cruft
00185  ******************************************************/
00186 
00187 nsresult
00188 NS_NewGenRegularIterator(nsIContentIterator ** aInstancePtrResult)
00189 {
00190   nsGeneratedContentIterator * iter = new nsGeneratedContentIterator();
00191   if (!iter) {
00192     return NS_ERROR_OUT_OF_MEMORY;
00193   }
00194 
00195   NS_ADDREF(*aInstancePtrResult = iter);
00196 
00197   return NS_OK;
00198 }
00199 
00200 
00201 /******************************************************
00202  * XPCOM cruft
00203  ******************************************************/
00204 
00205 NS_IMPL_ISUPPORTS2(nsGeneratedContentIterator, nsIGeneratedContentIterator,
00206                    nsIContentIterator)
00207 
00208 
00209 /******************************************************
00210  * constructor/destructor
00211  ******************************************************/
00212 
00213 nsGeneratedContentIterator::nsGeneratedContentIterator()
00214   : mIsDone(PR_FALSE)
00215 {
00216 }
00217 
00218 
00219 nsGeneratedContentIterator::~nsGeneratedContentIterator()
00220 {
00221 }
00222 
00223 
00224 /******************************************************
00225  * Init routines
00226  ******************************************************/
00227 
00228 
00229 nsresult
00230 nsGeneratedContentIterator::Init(nsIContent* aRoot)
00231 {
00232   if (!aRoot)
00233     return NS_ERROR_NULL_POINTER;
00234   mIsDone = PR_FALSE;
00235   nsCOMPtr<nsIContent> root(aRoot);
00236   mFirst = GetDeepFirstChild(root);
00237   if (mGenIter)//we have generated
00238   {
00239     mFirstIter = mGenIter;
00240     mFirstIterType = mIterType;
00241   }
00242   mLast = root;
00243   mCommonParent = root;
00244   mCurNode = mFirst;
00245   return NS_OK;
00246 }
00247 
00248 nsresult
00249 nsGeneratedContentIterator::Init(nsIPresShell *aShell, nsIDOMRange* aRange)
00250 {
00251   mPresShell = aShell;
00252   return Init(aRange);
00253 }
00254 
00255 nsresult
00256 nsGeneratedContentIterator::Init(nsIPresShell *aShell, nsIContent* aContent)
00257 {
00258   mPresShell = aShell;
00259   return Init(aContent);
00260 }
00261 
00262 
00263 nsresult
00264 nsGeneratedContentIterator::Init(nsIDOMRange* aRange)
00265 {
00266   if (!aRange)
00267     return NS_ERROR_NULL_POINTER;
00268 
00269   nsCOMPtr<nsIDOMNode> dN;
00270 
00271   nsCOMPtr<nsIContent> startCon;
00272   nsCOMPtr<nsIDOMNode> startDOM;
00273   nsCOMPtr<nsIContent> endCon;
00274   nsCOMPtr<nsIDOMNode> endDOM;
00275   PRInt32 startIndx;
00276   PRInt32 endIndx;
00277 
00278   mIsDone = PR_FALSE;
00279 
00280   // get common content parent
00281   if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(dN))) || !dN)
00282     return NS_ERROR_FAILURE;
00283   mCommonParent = do_QueryInterface(dN);
00284 
00285   // get the start node and offset, convert to nsIContent
00286   aRange->GetStartContainer(getter_AddRefs(startDOM));
00287   if (!startDOM)
00288     return NS_ERROR_ILLEGAL_VALUE;
00289   startCon = do_QueryInterface(startDOM);
00290   if (!startCon)
00291     return NS_ERROR_FAILURE;
00292 
00293   aRange->GetStartOffset(&startIndx);
00294 
00295   // get the end node and offset, convert to nsIContent
00296   aRange->GetEndContainer(getter_AddRefs(endDOM));
00297   if (!endDOM)
00298     return NS_ERROR_ILLEGAL_VALUE;
00299   endCon = do_QueryInterface(endDOM);
00300   if (!endCon)
00301     return NS_ERROR_FAILURE;
00302 
00303   aRange->GetEndOffset(&endIndx);
00304 
00305   // find first node in range
00306   nsIContent *cChild = startCon->GetChildAt(0);
00307 
00308   // short circuit when start node == end node
00309   if (startDOM == endDOM)
00310   {
00311     if (!cChild) // no children, must be a text node or empty container
00312     {
00313       mFirst = startCon;
00314       mLast = startCon;
00315       mCurNode = startCon;
00316       return NS_OK;
00317     }
00318     else
00319     {
00320       if (startIndx == endIndx)  // collapsed range
00321       {
00322         MakeEmpty();
00323         return NS_OK;
00324       }
00325     }
00326   }
00327 
00328   if (!cChild) // no children, must be a text node
00329   {
00330     mFirst = startCon;
00331   }
00332   else
00333   {
00334     cChild = startCon->GetChildAt(startIndx);
00335     if (!cChild)  // offset after last child, parent is first node
00336     {
00337       mFirst = startCon;
00338     }
00339     else
00340     {
00341       mFirst = GetDeepFirstChild(cChild);
00342       if (mGenIter)
00343       {
00344         mFirstIter = mGenIter;
00345         mFirstIterType = mIterType;
00346       }
00347     }
00348     // Does that first node really intersect the range?
00349     // the range could be collapsed, or the range could be
00350     // 'degenerate', ie not collapsed but still containing
00351     // no content.  In this case, we want the iterator to
00352     // be empty
00353 
00354     if (!nsRange::IsNodeIntersectsRange(mFirst, aRange))
00355     {
00356       MakeEmpty();
00357       return NS_OK;
00358     }
00359   }
00360 
00361   // find last node in range
00362   cChild = endCon->GetChildAt(0);
00363 
00364   if (!cChild) // no children, must be a text node
00365   {
00366     mLast = endCon;
00367   }
00368   else if (endIndx == 0) // before first child, parent is last node
00369   {
00370     mLast = endCon;
00371   }
00372   else
00373   {
00374     cChild = endCon->GetChildAt(--endIndx);
00375     if (!cChild)  // offset after last child, last child is last node
00376     {
00377       endIndx = (PRInt32)endCon->GetChildCount();
00378       cChild = endCon->GetChildAt(--endIndx);
00379       if (!cChild)
00380       {
00381         NS_NOTREACHED("nsGeneratedContentIterator::nsGeneratedContentIterator");
00382         return NS_ERROR_FAILURE;
00383       }
00384     }
00385     mLast = cChild;
00386   }
00387 
00388   mCurNode = mFirst;
00389   return NS_OK;
00390 }
00391 
00392 
00393 /******************************************************
00394  * Helper routines
00395  ******************************************************/
00396 
00397 void nsGeneratedContentIterator::MakeEmpty()
00398 {
00399   nsCOMPtr<nsIContent> noNode;
00400   mCurNode = noNode;
00401   mFirst = noNode;
00402   mLast = noNode;
00403   mCommonParent = noNode;
00404   mIsDone = PR_TRUE;
00405   mGenIter = 0;
00406   mFirstIter = 0;
00407   mIterType = nsIPresShell::Before;
00408 }
00409 
00410 nsCOMPtr<nsIContent> nsGeneratedContentIterator::GetDeepFirstChild(nsCOMPtr<nsIContent> aRoot)
00411 {
00412   nsCOMPtr<nsIContent> deepFirstChild;
00413 
00414   if (aRoot)
00415   {
00416     nsCOMPtr<nsIContent> cN = aRoot;
00417 
00418 #if DO_BEFORE
00419     //CHECK FOR BEFORESTUFF
00420     nsresult result = NS_ERROR_FAILURE;
00421     if (mPresShell)
00422       result = mPresShell->GetGeneratedContentIterator(cN,nsIPresShell::Before,getter_AddRefs(mGenIter));
00423     if (NS_SUCCEEDED(result) && mGenIter)
00424     { //ok we have a generated iter all bets are off
00425       mIterType = nsIPresShell::Before;
00426       mGenIter->First();
00427       return cN;
00428     }
00429 #endif
00430 
00431     nsIContent *cChild;
00432     while ((cChild = cN->GetChildAt(0)))
00433     {
00434       cN = cChild;
00435 
00436 #if DO_BEFORE
00437       //CHECK FOR BEFORESTUFF
00438       if (mPresShell)
00439         result = mPresShell->GetGeneratedContentIterator(cN,nsIPresShell::Before,getter_AddRefs(mGenIter));
00440       if (NS_SUCCEEDED(result) && mGenIter)
00441       { //ok we have a generated iter all bets are off
00442         mIterType = nsIPresShell::Before;
00443         mGenIter->First();
00444         return cN;
00445       }
00446 #endif
00447     }
00448 
00449     deepFirstChild = cN;
00450   }
00451 
00452   return deepFirstChild;
00453 }
00454 
00455 nsCOMPtr<nsIContent> nsGeneratedContentIterator::GetDeepLastChild(nsCOMPtr<nsIContent> aRoot)
00456 {
00457   nsCOMPtr<nsIContent> deepFirstChild;
00458 
00459   if (aRoot)
00460   {
00461     nsCOMPtr<nsIContent> cN = aRoot;
00462     nsCOMPtr<nsIContent> cChild;
00463 
00464 #if DO_AFTER
00465     //CHECK FOR AFTER STUFF
00466     nsresult result = NS_ERROR_FAILURE;
00467     if (mPresShell)
00468       result = mPresShell->GetGeneratedContentIterator(cN,nsIPresShell::After,getter_AddRefs(mGenIter));
00469     if (NS_SUCCEEDED(result) && mGenIter)
00470     { //ok we have a generated iter all bets are off
00471       mIterType = nsIPresShell::After;
00472       mGenIter->First();
00473       return cN;
00474     }
00475 #endif
00476 
00477     PRUint32 numChildren = cN->GetChildCount();
00478 
00479     while ( numChildren )
00480     {
00481       cChild = cN->GetChildAt(--numChildren);
00482       if (cChild)
00483       {
00484 #if DO_AFTER
00485         //CHECK FOR AFTER STUFF
00486         if (mPresShell)
00487           result = mPresShell->GetGeneratedContentIterator(cChild,nsIPresShell::After,getter_AddRefs(mGenIter));
00488         if (NS_SUCCEEDED(result) && mGenIter)
00489         { //ok we have a generated iter all bets are off
00490           mGenIter->Last();
00491           mIterType = nsIPresShell::After;
00492           return cChild;
00493         }
00494 #endif
00495         numChildren = cChild->GetChildCount();
00496         cN = cChild;
00497       }
00498       else
00499       {
00500         break;
00501       }
00502     }
00503     deepFirstChild = cN;
00504   }
00505 
00506   return deepFirstChild;
00507 }
00508 
00509 // Get the next sibling, or parents next sibling, or grandpa's next sibling...
00510 nsIContent *
00511 nsGeneratedContentIterator::GetNextSibling(nsIContent *aNode)
00512 {
00513   if (!aNode)
00514     return nsnull;
00515 
00516   nsIContent *parent = aNode->GetParent();
00517   if (!parent)
00518     return nsnull;
00519 
00520   PRInt32 indx = parent->IndexOf(aNode);
00521 
00522   nsIContent *sib = parent->GetChildAt(++indx);
00523 
00524   if (!sib)
00525   {
00526 #if DO_AFTER
00527     //CHECK FOR AFTERESTUFF
00528     if (mPresShell)
00529       mPresShell->GetGeneratedContentIterator(parent, nsIPresShell::After,
00530                                               getter_AddRefs(mGenIter));
00531     if (mGenIter)
00532     { //ok we have a generated iter all bets are off
00533       mGenIter->First();
00534       mIterType = nsIPresShell::After;
00535 
00536       return parent;
00537     }
00538 #endif
00539     if (parent != mCommonParent)
00540     {
00541       return GetNextSibling(parent);
00542     }
00543     else
00544     {
00545       sib = nsnull;
00546     }
00547   }
00548 
00549   return sib;
00550 }
00551 
00552 // Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
00553 nsIContent *
00554 nsGeneratedContentIterator::GetPrevSibling(nsIContent *aNode)
00555 {
00556   if (!aNode)
00557     return nsnull;
00558 
00559   nsIContent *parent = aNode->GetParent();
00560   if (!parent)
00561     return nsnull;
00562 
00563   PRInt32 indx = parent->IndexOf(aNode);
00564   nsIContent *sib = nsnull;
00565 
00566   if (indx < 1 || !(sib = parent->GetChildAt(--indx)))
00567   {
00568 #if DO_BEFORE
00569     //CHECK FOR BEFORESTUFF
00570     if (mPresShell)
00571       mPresShell->GetGeneratedContentIterator(parent, nsIPresShell::Before,
00572                                               getter_AddRefs(mGenIter));
00573     if (mGenIter)
00574     { //ok we have a generated iter all bets are off
00575       mGenIter->Last();
00576       mIterType = nsIPresShell::Before;
00577       return parent;
00578     }
00579     else
00580 #endif
00581     if (parent != mCommonParent)
00582     {
00583       return GetPrevSibling(parent);
00584     }
00585     else
00586     {
00587       sib = nsnull;
00588     }
00589   }
00590 
00591   return sib;
00592 }
00593 
00594 nsIContent *
00595 nsGeneratedContentIterator::NextNode(nsIContent *aNode)
00596 {
00597   if (!aNode)
00598     return nsnull;
00599 
00600   if (mGenIter)
00601   {
00602     if (mGenIter->IsDone())
00603       mGenIter = 0;
00604     else {
00605       mGenIter->Next();
00606 
00607       return nsnull;
00608     }
00609 
00610     if (nsIPresShell::After == mIterType)//answer is parent
00611     {
00612       //*ioNextNode = parent; leave it the same
00613       return nsnull;
00614     }
00615     nsIContent *cN = aNode->GetChildAt(0);
00616     if (cN)
00617     {
00618       return GetDeepFirstChild(cN);
00619     }
00620   }
00621 
00622   nsIContent *cN = aNode;
00623 
00624     // get next sibling if there is one
00625   nsIContent *parent = cN->GetParent();
00626   if (!parent)
00627   {
00628     // a little noise to catch some iterator usage bugs.
00629     NS_NOTREACHED("nsGeneratedContentIterator::NextNode() : no parent found");
00630     return nsnull;
00631   }
00632 
00633   PRInt32 indx = parent->IndexOf(cN);
00634 
00635   nsIContent *cSibling = parent->GetChildAt(++indx);
00636   if (cSibling)
00637   {
00638     // next node is siblings "deep left" child
00639     return GetDeepFirstChild(cSibling);
00640   }
00641 
00642   //CHECK FOR AFTERSTUFF
00643   if (mGenIter)//we allready had an afteriter. it must be done!
00644   {
00645     mGenIter = 0;
00646   }
00647   else//check for after node.
00648   {
00649     if (mPresShell)
00650       mPresShell->GetGeneratedContentIterator(parent, nsIPresShell::After,
00651                                               getter_AddRefs(mGenIter));
00652     if (mGenIter)
00653     { //ok we have a generated iter all bets are off
00654       mGenIter->First();
00655       mIterType = nsIPresShell::After;
00656     }
00657     else
00658       mGenIter = 0;
00659   }
00660 
00661   // else it's the parent
00662   return parent;
00663 }
00664 
00665 
00666 //THIS NEEDS TO USE A GENERATED SUBTREEITER HERE
00667 nsIContent *
00668 nsGeneratedContentIterator::PrevNode(nsIContent *aNode)
00669 {
00670   PRUint32 numChildren = aNode->GetChildCount();
00671 
00672   // if it has children then prev node is last child
00673   if (numChildren > 0)
00674   {
00675     return aNode->GetChildAt(--numChildren);
00676   }
00677 
00678   // else prev sibling is previous
00679   return GetPrevSibling(aNode);
00680 }
00681 
00682 /******************************************************
00683  * ContentIterator routines
00684  ******************************************************/
00685 
00686 void
00687 nsGeneratedContentIterator::First()
00688 {
00689   if (!mFirst) {
00690     mIsDone = PR_TRUE;
00691 
00692     return;
00693   }
00694 
00695   mIsDone = PR_FALSE;
00696 
00697   mCurNode = mFirst;
00698   mGenIter = mFirstIter;
00699   if (mGenIter)//set directionback to before...
00700     mGenIter->First();
00701 }
00702 
00703 
00704 void
00705 nsGeneratedContentIterator::Last()
00706 {
00707   if (!mLast) {
00708     mIsDone = PR_TRUE;
00709 
00710     return;
00711   }
00712 
00713   mIsDone = PR_FALSE;
00714 
00715   mGenIter = mLastIter;
00716   mCurNode = mLast;
00717 }
00718 
00719 
00720 void
00721 nsGeneratedContentIterator::Next()
00722 {
00723   if (mIsDone || !mCurNode)
00724     return;
00725 
00726   if (GetCurrentNode() == mLast)
00727   {
00728     mIsDone = PR_TRUE;
00729     return;
00730   }
00731 
00732   mCurNode = NextNode(mCurNode);
00733 }
00734 
00735 
00736 void
00737 nsGeneratedContentIterator::Prev()
00738 {
00739   if (mIsDone)
00740     return;
00741   if (!mCurNode)
00742     return;
00743   if (mCurNode == mFirst)
00744   {
00745     mIsDone = PR_TRUE;
00746     return;
00747   }
00748 
00749   mCurNode = PrevNode(mCurNode);
00750 }
00751 
00752 
00753 PRBool
00754 nsGeneratedContentIterator::IsDone()
00755 {
00756   return mIsDone;
00757 }
00758 
00759 
00760 nsresult
00761 nsGeneratedContentIterator::PositionAt(nsIContent* aCurNode)
00762 {
00763   // XXX need to confirm that aCurNode is within range
00764   if (!aCurNode)
00765     return NS_ERROR_NULL_POINTER;
00766   mCurNode = aCurNode;
00767   mIsDone = PR_FALSE;
00768   return NS_OK;
00769 }
00770 
00771 
00772 nsIContent *
00773 nsGeneratedContentIterator::GetCurrentNode()
00774 {
00775   if (!mCurNode || mIsDone) {
00776     return nsnull;
00777   }
00778 
00779   if (mGenIter) {
00780     return mGenIter->GetCurrentNode();
00781   }
00782 
00783   NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
00784 
00785   return mCurNode;
00786 }
00787 
00788 
00789 
00790 
00791 
00792 /*====================================================================================*/
00793 //SUBTREE ITERATOR
00794 /*====================================================================================*/
00795 /******************************************************
00796  * nsGeneratedSubtreeIterator
00797  ******************************************************/
00798 
00799 
00800 /*
00801  *  A simple iterator class for traversing the content in "top subtree" order
00802  */
00803 class nsGeneratedSubtreeIterator : public nsGeneratedContentIterator
00804 {
00805 public:
00806   nsGeneratedSubtreeIterator() {};
00807   virtual ~nsGeneratedSubtreeIterator() {};
00808 
00809   // nsContentIterator overrides ------------------------------
00810 
00811   virtual nsresult Init(nsIContent* aRoot);
00812 
00813   virtual nsresult Init(nsIDOMRange* aRange);
00814 
00815   virtual void Next();
00816 
00817   virtual void Prev();
00818 
00819   virtual nsresult PositionAt(nsIContent* aCurNode);
00820 
00821   //nsIGeneratedContentIterator
00822   virtual nsresult Init(nsIPresShell *aShell, nsIDOMRange* aRange);
00823   virtual nsresult Init(nsIPresShell *aShell, nsIContent* aContent);
00824 protected:
00825 
00826   nsresult GetTopAncestorInRange( nsCOMPtr<nsIContent> aNode,
00827                                   nsCOMPtr<nsIContent> *outAnestor);
00828 
00829   // no copy's or assigns  FIX ME
00830   nsGeneratedSubtreeIterator(const nsGeneratedSubtreeIterator&);
00831   nsGeneratedSubtreeIterator& operator=(const nsGeneratedSubtreeIterator&);
00832   nsCOMPtr<nsIDOMRange> mRange;
00833 };
00834 
00835 nsresult NS_NewGenSubtreeIterator(nsIContentIterator** aInstancePtrResult);
00836 
00837 
00838 
00839 
00840 /******************************************************
00841  * repository cruft
00842  ******************************************************/
00843 
00844 nsresult NS_NewGenSubtreeIterator(nsIContentIterator** aInstancePtrResult)
00845 {
00846   nsGeneratedSubtreeIterator * iter = new nsGeneratedSubtreeIterator();
00847   if (!iter) {
00848     return NS_ERROR_OUT_OF_MEMORY;
00849   }
00850 
00851   NS_ADDREF(*aInstancePtrResult = iter);
00852 
00853   return NS_OK;
00854 }
00855 
00856 
00857 
00858 /******************************************************
00859  * Init routines
00860  ******************************************************/
00861 
00862 
00863 nsresult
00864 nsGeneratedSubtreeIterator::Init(nsIContent* aRoot)
00865 {
00866   return NS_ERROR_NOT_IMPLEMENTED;
00867 }
00868 
00869 nsresult
00870 nsGeneratedSubtreeIterator::Init(nsIPresShell *aShell, nsIDOMRange* aRange)
00871 {
00872   mPresShell = aShell;
00873   return Init(aRange);
00874 }
00875 
00876 nsresult
00877 nsGeneratedSubtreeIterator::Init(nsIPresShell *aShell, nsIContent* aContent)
00878 {
00879   mPresShell = aShell;
00880   return Init(aContent);
00881 }
00882 
00883 nsresult
00884 nsGeneratedSubtreeIterator::Init(nsIDOMRange* aRange)
00885 {
00886   if (!aRange)
00887     return NS_ERROR_NULL_POINTER;
00888 
00889   mIsDone = PR_FALSE;
00890 
00891   mRange = aRange;
00892 
00893   // get the start node and offset, convert to nsIContent
00894   nsCOMPtr<nsIDOMNode> commonParent;
00895   nsCOMPtr<nsIDOMNode> startParent;
00896   nsCOMPtr<nsIDOMNode> endParent;
00897   nsCOMPtr<nsIContent> cStartP;
00898   nsCOMPtr<nsIContent> cEndP;
00899   nsCOMPtr<nsIContent> cN;
00900   nsCOMPtr<nsIContent> firstCandidate;
00901   nsCOMPtr<nsIContent> lastCandidate;
00902   nsCOMPtr<nsIDOMNode> dChild;
00903   nsCOMPtr<nsIContent> cChild;
00904   PRInt32 indx, startIndx, endIndx;
00905   PRInt32 numChildren;
00906 
00907   // get common content parent
00908   if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent))) || !commonParent)
00909     return NS_ERROR_FAILURE;
00910   mCommonParent = do_QueryInterface(commonParent);
00911 
00912   // get start content parent
00913   if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(startParent))) || !startParent)
00914     return NS_ERROR_FAILURE;
00915   cStartP = do_QueryInterface(startParent);
00916   aRange->GetStartOffset(&startIndx);
00917 
00918   // get end content parent
00919   if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(endParent))) || !endParent)
00920     return NS_ERROR_FAILURE;
00921   cEndP = do_QueryInterface(endParent);
00922   aRange->GetEndOffset(&endIndx);
00923 
00924   // short circuit when start node == end node
00925   if (startParent == endParent)
00926   {
00927     cChild = cStartP->GetChildAt(0);
00928 
00929     if (!cChild) // no children, must be a text node or empty container
00930     {
00931       // all inside one text node - empty subtree iterator
00932       MakeEmpty();
00933       return NS_OK;
00934     }
00935     else
00936     {
00937       if (startIndx == endIndx)  // collapsed range
00938       {
00939         MakeEmpty();
00940         return NS_OK;
00941       }
00942     }
00943   }
00944 
00945   // find first node in range
00946   aRange->GetStartOffset(&indx);
00947   numChildren = GetNumChildren(startParent);
00948 
00949   if (!numChildren) // no children, must be a text node
00950   {
00951     cN = cStartP;
00952   }
00953   else
00954   {
00955     dChild = GetChildAt(startParent, indx);
00956     cChild = do_QueryInterface(dChild);
00957     if (!cChild)  // offset after last child
00958     {
00959       cN = cStartP;
00960     }
00961     else
00962     {
00963       firstCandidate = cChild;
00964     }
00965   }
00966 
00967   if (!firstCandidate)
00968   {
00969     // then firstCandidate is next node after cN
00970     firstCandidate = GetNextSibling(cN);
00971 
00972     if (!firstCandidate)
00973     {
00974       MakeEmpty();
00975       return NS_OK;
00976     }
00977   }
00978   if (mGenIter)
00979   {
00980     mFirstIter = mGenIter;
00981     mFirstIterType = mIterType;
00982   }
00983   if (!mFirstIter)
00984   {
00985     firstCandidate = GetDeepFirstChild(firstCandidate);
00986     if (mGenIter)
00987     {
00988       mFirstIter = mGenIter;
00989       mFirstIterType = mIterType;
00990     }
00991   }
00992   // confirm that this first possible contained node
00993   // is indeed contained.  Else we have a range that
00994   // does not fully contain any node.
00995 
00996   PRBool nodeBefore(PR_FALSE), nodeAfter(PR_FALSE);
00997   if (!mFirstIter &&
00998       NS_FAILED(nsRange::CompareNodeToRange(firstCandidate, aRange,
00999                                             &nodeBefore, &nodeAfter)))
01000     return NS_ERROR_FAILURE;
01001 
01002   if (nodeBefore || nodeAfter)
01003   {
01004     MakeEmpty();
01005     return NS_OK;
01006   }
01007 
01008   // cool, we have the first node in the range.  Now we walk
01009   // up it's ancestors to find the most senior that is still
01010   // in the range.  That's the real first node.
01011   if (NS_SUCCEEDED(GetTopAncestorInRange(firstCandidate, address_of(mFirst))))
01012   {
01013     mFirstIter = 0;//ancestor has one no
01014     mGenIter = 0;
01015   }
01016   else if (!mFirstIter) //something bad happened and its not generated content iterators fault
01017     return NS_ERROR_FAILURE;
01018   else
01019     mFirst = firstCandidate;//setting last candidate to parent of generated content this is ok
01020 
01021 
01022 
01023   // now to find the last node
01024   aRange->GetEndOffset(&indx);
01025   numChildren = GetNumChildren(endParent);
01026 
01027   if (indx > numChildren) indx = numChildren;
01028   if (!indx)
01029   {
01030     cN = cEndP;
01031   }
01032   else
01033   {
01034     if (!numChildren) // no children, must be a text node
01035     {
01036       cN = cEndP;
01037     }
01038     else
01039     {
01040       dChild = GetChildAt(endParent, --indx);
01041       cChild = do_QueryInterface(dChild);
01042       if (!cChild)  // shouldn't happen
01043       {
01044         NS_ASSERTION(0,"tree traversal trouble in nsGeneratedSubtreeIterator::Init");
01045         return NS_ERROR_FAILURE;
01046       }
01047       else
01048       {
01049         lastCandidate = cChild;
01050       }
01051     }
01052   }
01053 
01054   if (!lastCandidate)
01055   {
01056     // then lastCandidate is prev node before cN
01057     lastCandidate = GetPrevSibling(cN);
01058 
01059     if (!lastCandidate)
01060     {
01061       MakeEmpty();
01062       return NS_OK;
01063     }
01064   }
01065   if (mGenIter)
01066   {
01067     mLastIter = mGenIter;
01068     mLastIterType = mIterType;
01069   }
01070   if (!mLastIter)//dont ever set last candidate to a generated node!
01071   {
01072     lastCandidate = GetDeepLastChild(lastCandidate);
01073     if (mGenIter)
01074     {
01075       mLastIter = mGenIter;
01076       mLastIterType = mIterType;
01077     }
01078   }
01079 
01080   // confirm that this first possible contained node
01081   // is indeed contained.  Else we have a range that
01082   // does not fully contain any node.
01083 
01084   if (!mLastIter &&
01085       NS_FAILED(nsRange::CompareNodeToRange(lastCandidate, aRange, &nodeBefore,
01086                                             &nodeAfter)))
01087     return NS_ERROR_FAILURE;
01088 
01089   if (nodeBefore || nodeAfter)
01090   {
01091     MakeEmpty();
01092     return NS_OK;
01093   }
01094 
01095   // cool, we have the last node in the range.  Now we walk
01096   // up it's ancestors to find the most senior that is still
01097   // in the range.  That's the real first node.
01098   if (NS_SUCCEEDED(GetTopAncestorInRange(lastCandidate, address_of(mLast))))
01099   {
01100     mLastIter = 0;//ancestor has one no
01101     mGenIter = 0;
01102   }
01103   else if (!mLastIter) //something bad happened and its not generated content iterators fault
01104     return NS_ERROR_FAILURE;
01105   else
01106     mLast = lastCandidate;//setting last candidate to parent of generated content this is ok
01107 
01108   mCurNode = mFirst;
01109   mGenIter = mFirstIter;
01110   mIterType = mFirstIterType ;
01111   return NS_OK;
01112 }
01113 
01114 
01115 /****************************************************************
01116  * nsGeneratedSubtreeIterator overrides of ContentIterator routines
01117  ****************************************************************/
01118 
01119 void
01120 nsGeneratedSubtreeIterator::Next()
01121 {
01122   if (mIsDone)
01123     return;
01124   nsCOMPtr<nsIContent> curnode;
01125   nsCOMPtr<nsIContent> nextNode;
01126   if (mGenIter)
01127   {
01128     if (mGenIter->IsDone())
01129     {
01130       mGenIter = 0;
01131 
01132       if (mIterType == nsIPresShell::After)
01133       {
01134         nextNode = GetNextSibling(mCurNode);
01135 
01136         if (!nextNode)
01137         {
01138           mIsDone = PR_TRUE;
01139 
01140           return;
01141         }
01142       }
01143       else
01144       {
01145         nextNode = mCurNode->GetChildAt(0);
01146       }
01147     }
01148     else {
01149        mGenIter->Next();
01150 
01151        return;
01152     }
01153   }
01154   else
01155   {
01156     if (mCurNode == mLast)
01157     {
01158       mIsDone = PR_TRUE;
01159       return;
01160     }
01161     nextNode = GetNextSibling(mCurNode);
01162 
01163     if (!nextNode)
01164     {
01165       mIsDone = PR_TRUE;
01166 
01167       return;
01168     }
01169   }
01170 
01171   if (!mGenIter)
01172     nextNode = GetDeepFirstChild(nextNode);
01173   if (NS_SUCCEEDED(GetTopAncestorInRange(nextNode, address_of(mCurNode))))
01174   {
01175     mGenIter = 0;
01176   }
01177   else if (!mGenIter) //something bad happened and its not generated content iterators fault
01178     return;
01179   else
01180     mCurNode = nextNode;//setting last candidate to parent of generated content this is ok
01181 }
01182 
01183 
01184 void
01185 nsGeneratedSubtreeIterator::Prev()
01186 {
01187 //notimplemented
01188   NS_ERROR("Not implemented!");
01189 }
01190 
01191 nsresult
01192 nsGeneratedSubtreeIterator::PositionAt(nsIContent* aCurNode)
01193 {
01194   NS_ERROR("Not implemented!");
01195 
01196   return NS_ERROR_NOT_IMPLEMENTED;
01197 }
01198 
01199 /****************************************************************
01200  * nsGeneratedSubtreeIterator helper routines
01201  ****************************************************************/
01202 
01203 nsresult nsGeneratedSubtreeIterator::GetTopAncestorInRange(
01204                                        nsCOMPtr<nsIContent> aNode,
01205                                        nsCOMPtr<nsIContent> *outAnestor)
01206 {
01207   if (!aNode)
01208     return NS_ERROR_NULL_POINTER;
01209   if (!outAnestor)
01210     return NS_ERROR_NULL_POINTER;
01211 
01212 
01213   // sanity check: aNode is itself in the range
01214   PRBool nodeBefore, nodeAfter;
01215   if (NS_FAILED(nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore,
01216                                             &nodeAfter)))
01217     return NS_ERROR_FAILURE;
01218 
01219   if (nodeBefore || nodeAfter)
01220     return NS_ERROR_FAILURE;
01221 
01222   nsCOMPtr<nsIContent> parent;
01223   while (aNode)
01224   {
01225     parent = aNode->GetParent();
01226     if (!parent)
01227       return NS_ERROR_FAILURE;
01228     if (NS_FAILED(nsRange::CompareNodeToRange(parent, mRange, &nodeBefore,
01229                                               &nodeAfter)))
01230       return NS_ERROR_FAILURE;
01231 
01232     if (nodeBefore || nodeAfter)
01233     {
01234       *outAnestor = aNode;
01235       return NS_OK;
01236     }
01237     aNode = parent;
01238   }
01239   return NS_ERROR_FAILURE;
01240 }
01241 
01242 
01243 
01244 
01245 
01246