Back to index

lightning-sunbird  0.9+nobinonly
nsTreeWalker.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is this file as it was released on May 1 2001.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Jonas Sicking.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Jonas Sicking <sicking@bigfoot.com> (Original Author)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /*
00041  * nsTreeWalker.cpp: Implementation of the nsIDOMTreeWalker object.
00042  */
00043 
00044 #include "nsTreeWalker.h"
00045 
00046 #include "nsIDOMNode.h"
00047 #include "nsIDOMNodeList.h"
00048 #include "nsIDOMEntityReference.h"
00049 #include "nsDOMError.h"
00050 
00051 #include "nsIContent.h"
00052 #include "nsIDocument.h"
00053 
00054 #include "nsContentUtils.h"
00055 #include "nsMemory.h"
00056 
00057 /*
00058  * Factories, constructors and destructors
00059  */
00060 
00061 nsresult
00062 NS_NewTreeWalker(nsIDOMNode *aRoot,
00063                  PRUint32 aWhatToShow,
00064                  nsIDOMNodeFilter *aFilter,
00065                  PRBool aEntityReferenceExpansion,
00066                  nsIDOMTreeWalker **aInstancePtrResult) {
00067 
00068     NS_ENSURE_ARG_POINTER(aInstancePtrResult);
00069 
00070     NS_ENSURE_TRUE(aRoot, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
00071 
00072     nsTreeWalker* walker = new nsTreeWalker(aRoot,
00073                                             aWhatToShow,
00074                                             aFilter,
00075                                             aEntityReferenceExpansion);
00076     NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY);
00077 
00078     return CallQueryInterface(walker, aInstancePtrResult);
00079 }
00080 
00081 nsTreeWalker::nsTreeWalker(nsIDOMNode *aRoot,
00082                            PRUint32 aWhatToShow,
00083                            nsIDOMNodeFilter *aFilter,
00084                            PRBool aExpandEntityReferences) :
00085     mRoot(aRoot),
00086     mWhatToShow(aWhatToShow),
00087     mExpandEntityReferences(aExpandEntityReferences),
00088     mCurrentNode(aRoot),
00089     mPossibleIndexesPos(-1)
00090 {
00091     mFilter.Set(aFilter, this);
00092 
00093     NS_ASSERTION(aRoot, "invalid root in call to nsTreeWalker constructor");
00094 }
00095 
00096 nsTreeWalker::~nsTreeWalker()
00097 {
00098     /* destructor code */
00099 }
00100 
00101 /*
00102  * nsISupports stuff
00103  */
00104 
00105 // QueryInterface implementation for nsTreeWalker
00106 NS_INTERFACE_MAP_BEGIN(nsTreeWalker)
00107     NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
00108     NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
00109     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
00110     NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(TreeWalker)
00111 NS_INTERFACE_MAP_END
00112 
00113 NS_IMPL_ADDREF(nsTreeWalker)
00114 NS_IMPL_RELEASE(nsTreeWalker)
00115 
00116 /*
00117  * nsIDOMTreeWalker Getters/Setters
00118  */
00119 
00120 /* readonly attribute nsIDOMNode root; */
00121 NS_IMETHODIMP nsTreeWalker::GetRoot(nsIDOMNode * *aRoot)
00122 {
00123     NS_ENSURE_ARG_POINTER(aRoot);
00124     *aRoot = mRoot;
00125     NS_ADDREF(*aRoot);
00126     return NS_OK;
00127 }
00128 
00129 /* readonly attribute unsigned long whatToShow; */
00130 NS_IMETHODIMP nsTreeWalker::GetWhatToShow(PRUint32 *aWhatToShow)
00131 {
00132     *aWhatToShow = mWhatToShow;
00133     return NS_OK;
00134 }
00135 
00136 /* readonly attribute nsIDOMNodeFilter filter; */
00137 NS_IMETHODIMP nsTreeWalker::GetFilter(nsIDOMNodeFilter * *aFilter)
00138 {
00139     NS_ENSURE_ARG_POINTER(aFilter);
00140 
00141     nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
00142     filter.swap((*aFilter = nsnull));
00143 
00144     return NS_OK;
00145 }
00146 
00147 /* readonly attribute boolean expandEntityReferences; */
00148 NS_IMETHODIMP
00149 nsTreeWalker::GetExpandEntityReferences(PRBool *aExpandEntityReferences)
00150 {
00151     *aExpandEntityReferences = mExpandEntityReferences;
00152     return NS_OK;
00153 }
00154 
00155 /* attribute nsIDOMNode currentNode; */
00156 NS_IMETHODIMP nsTreeWalker::GetCurrentNode(nsIDOMNode * *aCurrentNode)
00157 {
00158     NS_ENSURE_ARG_POINTER(aCurrentNode);
00159     *aCurrentNode = mCurrentNode;
00160     NS_ADDREF(*aCurrentNode);
00161     return NS_OK;
00162 }
00163 NS_IMETHODIMP nsTreeWalker::SetCurrentNode(nsIDOMNode * aCurrentNode)
00164 {
00165     NS_ENSURE_TRUE(aCurrentNode, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
00166 
00167     nsresult rv = nsContentUtils::CheckSameOrigin(mRoot, aCurrentNode);
00168     if(NS_FAILED(rv))
00169         return rv;
00170 
00171     mCurrentNode = aCurrentNode;
00172     return NS_OK;
00173 }
00174 
00175 /*
00176  * nsIDOMTreeWalker functions
00177  */
00178 
00179 /* nsIDOMNode parentNode (); */
00180 NS_IMETHODIMP nsTreeWalker::ParentNode(nsIDOMNode **_retval)
00181 {
00182     NS_ENSURE_ARG_POINTER(_retval);
00183     
00184     nsCOMPtr<nsIDOMNode> node(mCurrentNode);
00185     nsresult rv;
00186 
00187     PRInt32 indexPos = mPossibleIndexesPos;
00188     
00189     while (node && node != mRoot) {
00190         nsCOMPtr<nsIDOMNode> tmp(node);
00191         rv = tmp->GetParentNode(getter_AddRefs(node));
00192         NS_ENSURE_SUCCESS(rv, rv);
00193         
00194         indexPos--;
00195 
00196         if (node) {
00197             PRInt16 filtered;
00198             rv = TestNode(node, &filtered);
00199             NS_ENSURE_SUCCESS(rv, rv);
00200             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
00201                 mCurrentNode = node;
00202                 mPossibleIndexesPos = indexPos >= 0 ? indexPos : -1;
00203                 *_retval = node;
00204                 NS_ADDREF(*_retval);
00205 
00206                 return NS_OK;
00207             }
00208         }
00209     }
00210 
00211     *_retval = nsnull;
00212     return NS_OK;
00213 }
00214 
00215 /* nsIDOMNode firstChild (); */
00216 NS_IMETHODIMP nsTreeWalker::FirstChild(nsIDOMNode **_retval)
00217 {
00218     NS_ENSURE_ARG_POINTER(_retval);
00219     return FirstChildOf(mCurrentNode,
00220                         PR_FALSE,
00221                         mPossibleIndexesPos+1,
00222                         _retval);
00223 }
00224 
00225 /* nsIDOMNode lastChild (); */
00226 NS_IMETHODIMP nsTreeWalker::LastChild(nsIDOMNode **_retval)
00227 {
00228     NS_ENSURE_ARG_POINTER(_retval);
00229     return FirstChildOf(mCurrentNode,
00230                         PR_TRUE,
00231                         mPossibleIndexesPos+1,
00232                         _retval);
00233 }
00234 
00235 /* nsIDOMNode previousSibling (); */
00236 NS_IMETHODIMP nsTreeWalker::PreviousSibling(nsIDOMNode **_retval)
00237 {
00238     NS_ENSURE_ARG_POINTER(_retval);
00239     return NextSiblingOf(mCurrentNode,
00240                          PR_TRUE,
00241                          mPossibleIndexesPos,
00242                          _retval);
00243 }
00244 
00245 /* nsIDOMNode nextSibling (); */
00246 NS_IMETHODIMP nsTreeWalker::NextSibling(nsIDOMNode **_retval)
00247 {
00248     NS_ENSURE_ARG_POINTER(_retval);
00249     return NextSiblingOf(mCurrentNode,
00250                          PR_FALSE,
00251                          mPossibleIndexesPos,
00252                          _retval);
00253 }
00254 
00255 /* nsIDOMNode previousNode (); */
00256 NS_IMETHODIMP nsTreeWalker::PreviousNode(nsIDOMNode **_retval)
00257 {
00258     NS_ENSURE_ARG_POINTER(_retval);
00259     return NextInDocumentOrderOf(mCurrentNode,
00260                                  PR_TRUE,
00261                                  mPossibleIndexesPos,
00262                                  _retval);
00263 }
00264 
00265 /* nsIDOMNode nextNode (); */
00266 NS_IMETHODIMP nsTreeWalker::NextNode(nsIDOMNode **_retval)
00267 {
00268     NS_ENSURE_ARG_POINTER(_retval);
00269     return NextInDocumentOrderOf(mCurrentNode,
00270                                  PR_FALSE,
00271                                  mPossibleIndexesPos,
00272                                  _retval);
00273 }
00274 
00275 /*
00276  * nsIDOMGCParticipant functions
00277  */
00278 /* virtual */ nsIDOMGCParticipant*
00279 nsTreeWalker::GetSCCIndex()
00280 {
00281     return this;
00282 }
00283 
00284 /* virtual */ void
00285 nsTreeWalker::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
00286 {
00287     nsCOMPtr<nsIDOMGCParticipant> gcp;
00288     
00289     gcp = do_QueryInterface(mRoot);
00290     if (gcp)
00291         aArray.AppendObject(gcp);
00292 
00293     gcp = do_QueryInterface(mCurrentNode);
00294     if (gcp)
00295         aArray.AppendObject(gcp);
00296 }
00297 
00298 /*
00299  * nsTreeWalker helper functions
00300  */
00301 
00302 /*
00303  * Finds the first child of aNode and returns it. If a child is
00304  * found, mCurrentNode is set to that child.
00305  * @param aNode     Node to search for children.
00306  * @param aReversed Reverses search to find the last child instead
00307  *                  of first.
00308  * @param aIndexPos Position of aNode in mPossibleIndexes.
00309  * @param _retval   Returned node. Null if no child is found
00310  * @returns         Errorcode
00311  */
00312 nsresult
00313 nsTreeWalker::FirstChildOf(nsIDOMNode* aNode,
00314                            PRBool aReversed,
00315                            PRInt32 aIndexPos,
00316                            nsIDOMNode** _retval)
00317 {
00318     nsresult rv;
00319 
00320     // Don't step into entity references if expandEntityReferences = false
00321     if (!mExpandEntityReferences) {
00322         nsCOMPtr<nsIDOMEntityReference> ent(do_QueryInterface(aNode));
00323 
00324         if (ent) {
00325             *_retval = nsnull;
00326             return NS_OK;
00327         }
00328     }
00329 
00330     nsCOMPtr<nsIDOMNodeList> childNodes;
00331 
00332     PRInt32 start;
00333     if (!aReversed) {
00334         start = -1;
00335     }
00336     else {
00337         rv = aNode->GetChildNodes(getter_AddRefs(childNodes));
00338         NS_ENSURE_SUCCESS(rv, rv);
00339         NS_ENSURE_TRUE(childNodes, NS_ERROR_UNEXPECTED);
00340 
00341         rv = childNodes->GetLength((PRUint32*)&start);
00342         NS_ENSURE_SUCCESS(rv, rv);
00343     }
00344 
00345     return ChildOf(aNode, start, aReversed, aIndexPos, _retval);
00346 }
00347 
00348 /*
00349  * Finds the following sibling of aNode and returns it. If a sibling
00350  * is found, mCurrentNode is set to that node.
00351  * @param aNode     Node to start search at.
00352  * @param aReversed Reverses search to find the previous sibling
00353  *                  instead of next.
00354  * @param aIndexPos Position of aNode in mPossibleIndexes.
00355  * @param _retval   Returned node. Null if no sibling is found
00356  * @returns         Errorcode
00357  */
00358 nsresult
00359 nsTreeWalker::NextSiblingOf(nsIDOMNode* aNode,
00360                             PRBool aReversed,
00361                             PRInt32 aIndexPos,
00362                             nsIDOMNode** _retval)
00363 {
00364     nsresult rv;
00365     nsCOMPtr<nsIDOMNode> node(aNode);
00366     PRInt16 filtered;
00367     PRInt32 childNum;
00368 
00369     if (node == mRoot) {
00370         *_retval = nsnull;
00371         return NS_OK;
00372     }
00373 
00374     while (1) {
00375         nsCOMPtr<nsIDOMNode> parent;
00376 
00377         // Get our index in the parent
00378         rv = node->GetParentNode(getter_AddRefs(parent));
00379         NS_ENSURE_SUCCESS(rv, rv);
00380 
00381         if (!parent)
00382             break;
00383 
00384         rv = IndexOf(parent, node, aIndexPos, &childNum);
00385         NS_ENSURE_SUCCESS(rv, rv);
00386 
00387         // Search siblings
00388         ChildOf(parent, childNum, aReversed, aIndexPos, _retval);
00389         NS_ENSURE_SUCCESS(rv, rv);
00390 
00391         if (*_retval)
00392             return NS_OK;
00393 
00394         // Is parent the root?
00395         if (parent == mRoot)
00396             break;
00397 
00398         // Is parent transparent in filtered view?
00399         rv = TestNode(parent, &filtered);
00400         NS_ENSURE_SUCCESS(rv, rv);
00401         if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT)
00402             break;
00403 
00404         node = parent;
00405         aIndexPos = aIndexPos < 0 ? -1 : aIndexPos-1;
00406     }
00407 
00408     *_retval = nsnull;
00409     return NS_OK;
00410 }
00411 
00412 /*
00413  * Finds the next node in document order of aNode and returns it.
00414  * If a node is found, mCurrentNode is set to that node.
00415  * @param aNode     Node to start search at.
00416  * @param aReversed Reverses search to find the preceding node
00417  *                  instead of next.
00418  * @param aIndexPos Position of aNode in mPossibleIndexes.
00419  * @param _retval   Returned node. Null if no node is found
00420  * @returns         Errorcode
00421  */
00422 nsresult
00423 nsTreeWalker::NextInDocumentOrderOf(nsIDOMNode* aNode,
00424                                     PRBool aReversed,
00425                                     PRInt32 aIndexPos,
00426                                     nsIDOMNode** _retval)
00427 {
00428     nsresult rv;
00429 
00430     if (!aReversed) {
00431         rv = FirstChildOf(aNode, aReversed, aIndexPos+1, _retval);
00432         NS_ENSURE_SUCCESS(rv, rv);
00433 
00434         if (*_retval)
00435             return NS_OK;
00436     }
00437 
00438     if (aNode == mRoot){
00439         *_retval = nsnull;
00440         return NS_OK;
00441     }
00442 
00443     nsCOMPtr<nsIDOMNode> node(aNode);
00444     nsCOMPtr<nsIDOMNode> currentNodeBackup(mCurrentNode);
00445     PRInt16 filtered;
00446     PRInt32 childNum;
00447 
00448     while (1) {
00449         nsCOMPtr<nsIDOMNode> parent;
00450 
00451         // Get our index in the parent
00452         rv = node->GetParentNode(getter_AddRefs(parent));
00453         NS_ENSURE_SUCCESS(rv, rv);
00454 
00455         if (!parent)
00456             break;
00457 
00458         rv = IndexOf(parent, node, aIndexPos, &childNum);
00459         NS_ENSURE_SUCCESS(rv, rv);
00460 
00461         // Search siblings
00462         nsCOMPtr<nsIDOMNode> sibling;
00463         ChildOf(parent, childNum, aReversed, aIndexPos, getter_AddRefs(sibling));
00464         NS_ENSURE_SUCCESS(rv, rv);
00465 
00466         if (sibling) {
00467             if (aReversed) {
00468                 // in reversed walking we first test if there are
00469                 // any children. I don't like this piece of code :(
00470                 nsCOMPtr<nsIDOMNode> child(sibling);
00471                 while(child) {
00472                     sibling = child;
00473                     rv = FirstChildOf(sibling,
00474                                       PR_TRUE,
00475                                       aIndexPos,
00476                                       getter_AddRefs(child));
00477                     if (NS_FAILED(rv)) {
00478                         // ChildOf set mCurrentNode and then something
00479                         // failed. Restore the old value before returning
00480                         mCurrentNode = currentNodeBackup;
00481                         mPossibleIndexesPos = -1;
00482                         return rv;
00483                     }
00484                 }
00485             }
00486             *_retval = sibling;
00487             NS_ADDREF(*_retval);
00488             return NS_OK;
00489         }
00490 
00491         aIndexPos = aIndexPos < 0 ? -1 : aIndexPos-1;
00492 
00493         if (aReversed) {
00494             // Is parent transparent in filtered view?
00495             rv = TestNode(parent, &filtered);
00496             NS_ENSURE_SUCCESS(rv, rv);
00497             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
00498                 mCurrentNode = parent;
00499                 mPossibleIndexesPos = aIndexPos;
00500                 *_retval = parent;
00501                 NS_ADDREF(*_retval);
00502                 return NS_OK;
00503             }
00504         }
00505 
00506         // Is parent the root?
00507         if (parent == mRoot)
00508             break;
00509 
00510         node = parent;
00511     }
00512 
00513     *_retval = nsnull;
00514     return NS_OK;
00515 }
00516 
00517 /*
00518  * Finds the first child of aNode after child N and returns it. If a
00519  * child is found, mCurrentNode is set to that child
00520  * @param aNode     Node to search for children
00521  * @param childNum  Child number to start search from. The child with
00522  *                  this number is not searched
00523  * @param aReversed Reverses search to find the last child instead
00524  *                  of first
00525  * @param aIndexPos Position of aNode in mPossibleIndexes
00526  * @param _retval   Returned node. Null if no child is found
00527  * @returns         Errorcode
00528  */
00529 nsresult
00530 nsTreeWalker::ChildOf(nsIDOMNode* aNode,
00531                       PRInt32 childNum,
00532                       PRBool aReversed,
00533                       PRInt32 aIndexPos,
00534                       nsIDOMNode** _retval)
00535 {
00536     PRInt16 filtered;
00537     nsresult rv;
00538     nsCOMPtr<nsIDOMNodeList> childNodes;
00539 
00540     rv = aNode->GetChildNodes(getter_AddRefs(childNodes));
00541     NS_ENSURE_SUCCESS(rv, rv);
00542     NS_ENSURE_TRUE(childNodes, NS_ERROR_UNEXPECTED);
00543 
00544     PRInt32 dir, end;
00545     if (!aReversed) {
00546         dir = 1;
00547         rv = childNodes->GetLength((PRUint32*)&end);
00548         NS_ENSURE_SUCCESS(rv, rv);
00549     }
00550     else {
00551         dir = -1;
00552         end = -1;
00553     }
00554 
00555     // Step through all children
00556     PRInt32 i;
00557     for (i = childNum+dir; i != end; i += dir) {
00558         nsCOMPtr<nsIDOMNode> child;
00559         rv = childNodes->Item(i, getter_AddRefs(child));
00560         NS_ENSURE_SUCCESS(rv, rv);
00561 
00562         rv = TestNode(child, &filtered);
00563         NS_ENSURE_SUCCESS(rv, rv);
00564 
00565         switch (filtered) {
00566             case nsIDOMNodeFilter::FILTER_ACCEPT:
00567                 // Child found
00568                 mCurrentNode = child;
00569                 mPossibleIndexesPos = aIndexPos;
00570                 *_retval = child;
00571                 NS_ADDREF(*_retval);
00572 
00573                 SetChildIndex(aIndexPos, i);
00574 
00575                 return NS_OK;
00576 
00577             case nsIDOMNodeFilter::FILTER_SKIP:
00578                 // Search children
00579                 rv = FirstChildOf(child, aReversed, aIndexPos+1, _retval);
00580                 NS_ENSURE_SUCCESS(rv, rv);
00581 
00582                 if (*_retval) {
00583                     SetChildIndex(aIndexPos, i);
00584                     return NS_OK;
00585                 }
00586                 break;
00587 
00588             case nsIDOMNodeFilter::FILTER_REJECT:
00589                 // Keep searching
00590                 break;
00591 
00592             default:
00593                 return NS_ERROR_UNEXPECTED;
00594         }
00595     }
00596 
00597     *_retval = nsnull;
00598     return NS_OK;
00599 }
00600 
00601 /*
00602  * Tests if and how a node should be filtered. Uses mWhatToShow and
00603  * mFilter to test the node.
00604  * @param aNode     Node to test
00605  * @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
00606  * @returns         Errorcode
00607  */
00608 nsresult nsTreeWalker::TestNode(nsIDOMNode* aNode, PRInt16* _filtered)
00609 {
00610     nsresult rv;
00611     PRUint16 nodeType;
00612     PRUint32 mask = 1;
00613 
00614     rv = aNode->GetNodeType(&nodeType);
00615     NS_ENSURE_SUCCESS(rv, rv);
00616 
00617     if (nodeType <= 12 && !((mask << (nodeType-1)) & mWhatToShow)) {
00618         *_filtered = nsIDOMNodeFilter::FILTER_SKIP;
00619 
00620         return NS_OK;
00621     }
00622 
00623     nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
00624     if (filter)
00625         return filter->AcceptNode(aNode, _filtered);
00626 
00627     *_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
00628     return NS_OK;
00629 }
00630 
00631 /*
00632  * Gets the child index of a node within it's parent. Gets a possible index
00633  * from mPossibleIndexes to gain speed. If the value in mPossibleIndexes
00634  * isn't correct it'll get the index the usual way
00635  * @param aParent   in which to get the index
00636  * @param aChild    node to get the index of
00637  * @param aIndexPos position in mPossibleIndexes that contains the possible.
00638  *                  index
00639  * @param _childNum returned index
00640  * @returns         Errorcode
00641  */
00642 nsresult nsTreeWalker::IndexOf(nsIDOMNode* aParent,
00643                                nsIDOMNode* aChild,
00644                                PRInt32 aIndexPos,
00645                                PRInt32* _childNum)
00646 {
00647     PRInt32 possibleIndex = -1;
00648     if (aIndexPos >= 0)
00649         possibleIndex = NS_PTR_TO_INT32(mPossibleIndexes[aIndexPos]);
00650 
00651     nsCOMPtr<nsIContent> contParent(do_QueryInterface(aParent));
00652     if (contParent) {
00653         nsCOMPtr<nsIContent> child(do_QueryInterface(aChild));
00654 
00655         if (possibleIndex >= 0) {
00656             if (child == contParent->GetChildAt(possibleIndex)) {
00657                 *_childNum = possibleIndex;
00658                 return NS_OK;
00659             }
00660         }
00661 
00662         *_childNum = contParent->IndexOf(child);
00663 
00664         return *_childNum >= 0 ? NS_OK : NS_ERROR_UNEXPECTED;
00665     }
00666 
00667     nsCOMPtr<nsIDocument> docParent(do_QueryInterface(aParent));
00668     if (docParent) {
00669         nsCOMPtr<nsIContent> child(do_QueryInterface(aChild));
00670 
00671         if (possibleIndex >= 0) {
00672             if (child == docParent->GetChildAt(possibleIndex)) {
00673                 *_childNum = possibleIndex;
00674                 return NS_OK;
00675             }
00676         }
00677 
00678         *_childNum = docParent->IndexOf(child);
00679 
00680         return *_childNum >= 0 ? NS_OK : NS_ERROR_UNEXPECTED;
00681     }
00682 
00683     nsresult rv;
00684     PRUint32 i, len;
00685     nsCOMPtr<nsIDOMNodeList> childNodes;
00686 
00687     rv = aParent->GetChildNodes(getter_AddRefs(childNodes));
00688     NS_ENSURE_SUCCESS(rv, rv);
00689     NS_ENSURE_TRUE(childNodes, NS_ERROR_UNEXPECTED);
00690 
00691     if (possibleIndex >= 0) {
00692         nsCOMPtr<nsIDOMNode> tmp;
00693         childNodes->Item(possibleIndex, getter_AddRefs(tmp));
00694         if (tmp == aChild) {
00695             *_childNum = possibleIndex;
00696             return NS_OK;
00697         }
00698     }
00699 
00700     rv = childNodes->GetLength(&len);
00701     NS_ENSURE_SUCCESS(rv, rv);
00702 
00703     for (i = 0; i < len; ++i) {
00704         nsCOMPtr<nsIDOMNode> node;
00705         rv = childNodes->Item(i, getter_AddRefs(node));
00706         NS_ENSURE_SUCCESS(rv, rv);
00707 
00708         if (node == aChild) {
00709             *_childNum = i;
00710             return NS_OK;
00711         }
00712     }
00713 
00714     return NS_ERROR_UNEXPECTED;
00715 }
00716 
00717 /*
00718  * Sets the child index at the specified level. It doesn't matter if this
00719  * fails since mPossibleIndexes should only be considered a hint
00720  * @param aIndexPos   position in mPossibleIndexes to set
00721  * @param aChildIndex child index at specified position
00722  */
00723 void nsTreeWalker::SetChildIndex(PRInt32 aIndexPos, PRInt32 aChildIndex)
00724 {
00725     mPossibleIndexes.ReplaceElementAt(NS_INT32_TO_PTR(aChildIndex), aIndexPos);
00726 }