--- /dev/null 2008-05-09 09:59:47.390392120 +0300 +++ content/base/public/nsINodeIterator.h 2008-05-09 12:56:09.000000000 +0300 @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Olli Pettay (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nsINodeIterator_h___ +#define __nsINsodeIterator_h___ +#include "nsIContentIterator.h" +class nsINode; + +#define NS_INODEITERATOR_IID \ + { 0xc1f346ac, 0x2a7c, 0x430a, \ + { 0xae, 0x7f, 0xa5, 0x8c, 0x38, 0x34, 0x5e, 0xf2 } } + +class nsINodeIterator : public nsIContentIterator +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODEITERATOR_IID) + + /** + * Initializes an iterator for the subtree rooted by the node aRoot + */ + virtual nsresult Init(nsINode* aRoot) = 0; + virtual nsresult Init(nsIContent* aRoot) = 0; + virtual nsresult Init(nsIDOMRange* aRange) = 0; + + /** + * CurrentItem will return the current item, or null if the list is empty + * @return the current node + */ + virtual nsINode* GetCurrent() = 0; + + /** + * PositionAt will position the iterator to the supplied node + */ + virtual nsresult PositionAt(nsINode* aCurNode) = 0; + virtual nsresult PositionAt(nsIContent* aCurNode) = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsINodeIterator, NS_INODEITERATOR_IID) + +#endif // __nsINodeIterator_h___ + ? content/base/public/nsINodeIterator.h ? content/base/test/test_bug Index: content/base/public/Makefile.in =================================================================== RCS file: /cvsroot/mozilla/content/base/public/Makefile.in,v retrieving revision 1.67 diff -u -8 -p -r1.67 Makefile.in --- content/base/public/Makefile.in 25 Jul 2007 04:29:47 -0000 1.67 +++ content/base/public/Makefile.in 9 May 2008 10:03:30 -0000 @@ -45,16 +45,17 @@ MODULE = content XPIDL_MODULE = content_base GRE_MODULE = 1 EXPORTS = \ mozFlushType.h \ nsIContent.h \ nsIAttribute.h \ nsIContentIterator.h \ +nsINodeIterator.h \ nsContentErrors.h \ nsContentPolicyUtils.h \ nsContentUtils.h \ nsIDocument.h \ nsIDocumentObserver.h \ nsIMutationObserver.h \ nsINameSpaceManager.h \ nsINode.h \ Index: content/base/public/nsIContentIterator.h =================================================================== RCS file: /cvsroot/mozilla/content/base/public/nsIContentIterator.h,v retrieving revision 1.15 diff -u -8 -p -r1.15 nsIContentIterator.h --- content/base/public/nsIContentIterator.h 25 Oct 2006 20:24:00 -0000 1.15 +++ content/base/public/nsIContentIterator.h 9 May 2008 10:03:30 -0000 @@ -42,16 +42,18 @@ class nsIContent; class nsIDOMRange; #define NS_ICONTENTITERTOR_IID \ {0xa6cf90e4, 0x15b3, 0x11d2, \ {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } +// Note, if you need to iterate through all kinds of nodes, you may want to use +// nsINodeIterator, which most of the content iterators implement. class nsIContentIterator : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTITERTOR_IID) /* Initializes an iterator for the subtree rooted by the node aRoot */ virtual nsresult Init(nsIContent* aRoot) = 0; Index: content/base/src/nsContentIterator.cpp =================================================================== RCS file: /cvsroot/mozilla/content/base/src/nsContentIterator.cpp,v retrieving revision 1.79 diff -u -8 -p -r1.79 nsContentIterator.cpp --- content/base/src/nsContentIterator.cpp 19 Mar 2008 23:23:59 -0000 1.79 +++ content/base/src/nsContentIterator.cpp 9 May 2008 10:03:30 -0000 @@ -33,17 +33,17 @@ * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsISupports.h" #include "nsIDOMNodeList.h" -#include "nsIContentIterator.h" +#include "nsINodeIterator.h" #include "nsRange.h" #include "nsIContent.h" #include "nsIDOMText.h" #include "nsCOMPtr.h" #include "nsPresContext.h" #include "nsIComponentManager.h" #include "nsContentCID.h" #include "nsLayoutCID.h" @@ -60,128 +60,147 @@ static NS_DEFINE_IID(kISupportsIID, NS_I // static inline PRBool NodeHasChildren(nsINode *aNode) { return aNode->GetChildCount() > 0; } /////////////////////////////////////////////////////////////////////////// -// ContentToParentOffset: returns the content node's parent and offset. +// NodeToParentOffset: returns the node's parent and offset. // -static nsIContent* -ContentToParentOffset(nsIContent *aContent, PRInt32 *aOffset) +static nsINode* +NodeToParentOffset(nsINode *aNode, PRInt32 *aOffset) { *aOffset = 0; - nsIContent* parent = aContent->GetParent(); + nsINode* parent = aNode->GetNodeParent(); if (parent) { - *aOffset = parent->IndexOf(aContent); + *aOffset = parent->IndexOf(aNode); } return parent; } /////////////////////////////////////////////////////////////////////////// -// ContentIsInTraversalRange: returns true if content is visited during +// NodeIsInTraversalRange: returns true if content is visited during // the traversal of the range in the specified mode. // static PRBool -ContentIsInTraversalRange(nsIContent *aContent, PRBool aIsPreMode, - nsINode *aStartNode, PRInt32 aStartOffset, - nsINode *aEndNode, PRInt32 aEndOffset) +NodeIsInTraversalRange(nsINode *aNode, PRBool aIsPreMode, + nsINode *aStartNode, PRInt32 aStartOffset, + nsINode *aEndNode, PRInt32 aEndOffset) { - if (!aStartNode || !aEndNode || !aContent) + if (!aStartNode || !aEndNode || !aNode) return PR_FALSE; // If a chardata node contains an end point of the traversal range, // it is always in the traversal range. - if (aContent->IsNodeOfType(nsINode::eDATA_NODE) && - (aContent == aStartNode || aContent == aEndNode)) { + if (aNode->IsNodeOfType(nsINode::eDATA_NODE) && + (aNode == aStartNode || aNode == aEndNode)) { return PR_TRUE; } - nsIContent* parent = aContent->GetParent(); + nsINode* parent = aNode->GetNodeParent(); if (!parent) return PR_FALSE; - PRInt32 indx = parent->IndexOf(aContent); + PRInt32 indx = parent->IndexOf(aNode); if (!aIsPreMode) ++indx; return (nsContentUtils::ComparePoints(aStartNode, aStartOffset, parent, indx) <= 0) && (nsContentUtils::ComparePoints(aEndNode, aEndOffset, parent, indx) >= 0); } /* * A simple iterator class for traversing the content in "close tag" order */ -class nsContentIterator : public nsIContentIterator //, public nsIEnumerator +class nsContentIterator : public nsINodeIterator //, public nsIEnumerator { public: NS_DECL_ISUPPORTS nsContentIterator(); virtual ~nsContentIterator(); // nsIContentIterator interface methods ------------------------------ - virtual nsresult Init(nsIContent* aRoot); + virtual nsresult Init(nsIContent* aRoot) + { + return Init(static_cast(aRoot)); + } virtual nsresult Init(nsIDOMRange* aRange); virtual void First(); virtual void Last(); virtual void Next(); virtual void Prev(); - virtual nsIContent *GetCurrentNode(); + virtual nsIContent *GetCurrentNode() + { + nsINode* current = GetCurrent(); + return (current && current->IsNodeOfType(nsINode::eCONTENT)) ? + static_cast(current) : nsnull; + } virtual PRBool IsDone(); - virtual nsresult PositionAt(nsIContent* aCurNode); + virtual nsresult PositionAt(nsIContent* aCurNode) + { + return PositionAt(static_cast(aCurNode)); + } + + // nsINodeIterator interface methods ------------------------------ + + virtual nsresult Init(nsINode* aRoot); + + virtual nsINode* GetCurrent(); + + virtual nsresult PositionAt(nsINode* aCurNode); // nsIEnumertor interface methods ------------------------------ //NS_IMETHOD CurrentItem(nsISupports **aItem); protected: - nsIContent *GetDeepFirstChild(nsIContent *aRoot, nsVoidArray *aIndexes); - nsIContent *GetDeepLastChild(nsIContent *aRoot, nsVoidArray *aIndexes); + nsINode* GetDeepFirstChild(nsINode *aRoot, nsVoidArray *aIndexes); + nsINode* GetDeepLastChild(nsINode *aRoot, nsVoidArray *aIndexes); // Get the next sibling of aNode. Note that this will generally return null // if aNode happens not to be a content node. That's OK. - nsIContent *GetNextSibling(nsINode *aNode, nsVoidArray *aIndexes); + nsINode* GetNextSibling(nsINode *aNode, nsVoidArray *aIndexes); // Get the prev sibling of aNode. Note that this will generally return null // if aNode happens not to be a content node. That's OK. - nsIContent *GetPrevSibling(nsINode *aNode, nsVoidArray *aIndexes); + nsINode* GetPrevSibling(nsINode *aNode, nsVoidArray *aIndexes); - nsIContent *NextNode(nsIContent *aNode, nsVoidArray *aIndexes); - nsIContent *PrevNode(nsIContent *aNode, nsVoidArray *aIndexes); + nsINode* NextNode(nsINode *aNode, nsVoidArray *aIndexes); + nsINode* PrevNode(nsINode *aNode, nsVoidArray *aIndexes); // WARNING: This function is expensive nsresult RebuildIndexStack(); void MakeEmpty(); - nsCOMPtr mCurNode; - nsCOMPtr mFirst; - nsCOMPtr mLast; + nsCOMPtr mCurNode; + nsCOMPtr mFirst; + nsCOMPtr mLast; nsCOMPtr mCommonParent; // used by nsContentIterator to cache indices nsAutoVoidArray mIndexes; // used by nsSubtreeIterator to cache indices. Why put them in the base class? // Because otherwise I have to duplicate the routines GetNextSibling etc across both classes, // with slight variations for caching. Or alternately, create a base class for the cache @@ -252,17 +271,17 @@ nsresult NS_NewPreContentIterator(nsICon return NS_OK; } /****************************************************** * XPCOM cruft ******************************************************/ -NS_IMPL_ISUPPORTS1(nsContentIterator, nsIContentIterator) +NS_IMPL_ISUPPORTS2(nsContentIterator, nsIContentIterator, nsINodeIterator) /****************************************************** * constructor/destructor ******************************************************/ nsContentIterator::nsContentIterator() : // don't need to explicitly initialize |nsCOMPtr|s, they will automatically be NULL @@ -277,20 +296,21 @@ nsContentIterator::~nsContentIterator() /****************************************************** * Init routines ******************************************************/ nsresult -nsContentIterator::Init(nsIContent* aRoot) +nsContentIterator::Init(nsINode* aRoot) { if (!aRoot) return NS_ERROR_NULL_POINTER; + mIsDone = PR_FALSE; mIndexes.Clear(); if (mPre) { mFirst = aRoot; mLast = GetDeepLastChild(aRoot, nsnull); } @@ -383,18 +403,18 @@ nsContentIterator::Init(nsIDOMRange* aRa { mFirst = GetNextSibling(startNode, nsnull); // Does mFirst node really intersect the range? // The range could be 'degenerate', ie not collapsed // but still contain no content. if (mFirst && - !ContentIsInTraversalRange(mFirst, mPre, startNode, startIndx, - endNode, endIndx)) { + !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx, + endNode, endIndx)) { mFirst = nsnull; } } else { NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT), "Data node that's not content?"); mFirst = static_cast(startNode); @@ -418,18 +438,18 @@ nsContentIterator::Init(nsIDOMRange* aRa { mFirst = GetDeepFirstChild(cChild, nsnull); // Does mFirst node really intersect the range? // The range could be 'degenerate', ie not collapsed // but still contain no content. if (mFirst && - !ContentIsInTraversalRange(mFirst, mPre, startNode, startIndx, - endNode, endIndx)) + !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx, + endNode, endIndx)) mFirst = nsnull; } } // Find last node in range. PRBool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE); @@ -449,18 +469,18 @@ nsContentIterator::Init(nsIDOMRange* aRa // XXX: In the future, if end offset is before the first // character in the cdata node, should we set mLast to // the prev sibling? if (!endIsData) { mLast = GetPrevSibling(endNode, nsnull); - if (!ContentIsInTraversalRange(mLast, mPre, startNode, startIndx, - endNode, endIndx)) + if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, + endNode, endIndx)) mLast = nsnull; } else { NS_ASSERTION(endNode->IsNodeOfType(nsINode::eCONTENT), "Data node that's not content?"); mLast = static_cast(endNode); } @@ -477,18 +497,18 @@ nsContentIterator::Init(nsIDOMRange* aRa NS_NOTREACHED("nsContentIterator::nsContentIterator"); return NS_ERROR_FAILURE; } if (mPre) { mLast = GetDeepLastChild(cChild, nsnull); - if (!ContentIsInTraversalRange(mLast, mPre, startNode, startIndx, - endNode, endIndx)) { + if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, + endNode, endIndx)) { mLast = nsnull; } } else { // post-order mLast = cChild; } } @@ -517,28 +537,28 @@ nsContentIterator::Init(nsIDOMRange* aRa * Helper routines ******************************************************/ // WARNING: This function is expensive nsresult nsContentIterator::RebuildIndexStack() { // Make sure we start at the right indexes on the stack! Build array up // to common parent of start and end. Perhaps it's too many entries, but // that's far better than too few. - nsIContent* parent; - nsIContent* current; + nsINode* parent; + nsINode* current; mIndexes.Clear(); current = mCurNode; if (!current) { return NS_OK; } while (current != mCommonParent) { - parent = current->GetParent(); + parent = current->GetNodeParent(); if (!parent) return NS_ERROR_FAILURE; mIndexes.InsertElementAt(NS_INT32_TO_PTR(parent->IndexOf(current)), 0); current = parent; } @@ -551,72 +571,72 @@ nsContentIterator::MakeEmpty() mCurNode = nsnull; mFirst = nsnull; mLast = nsnull; mCommonParent = nsnull; mIsDone = PR_TRUE; mIndexes.Clear(); } -nsIContent * -nsContentIterator::GetDeepFirstChild(nsIContent *aRoot, nsVoidArray *aIndexes) +nsINode* +nsContentIterator::GetDeepFirstChild(nsINode *aRoot, nsVoidArray *aIndexes) { if (!aRoot) { return nsnull; } - nsIContent *cN = aRoot; - nsIContent *cChild = cN->GetChildAt(0); + nsINode *n = aRoot; + nsINode *nChild = n->GetChildAt(0); - while (cChild) + while (nChild) { if (aIndexes) { // Add this node to the stack of indexes aIndexes->AppendElement(NS_INT32_TO_PTR(0)); } - cN = cChild; - cChild = cN->GetChildAt(0); + n = nChild; + nChild = n->GetChildAt(0); } - return cN; + return n; } -nsIContent * -nsContentIterator::GetDeepLastChild(nsIContent *aRoot, nsVoidArray *aIndexes) +nsINode* +nsContentIterator::GetDeepLastChild(nsINode *aRoot, nsVoidArray *aIndexes) { if (!aRoot) { return nsnull; } - nsIContent *deepLastChild = aRoot; + nsINode *deepLastChild = aRoot; - nsIContent *cN = aRoot; - PRInt32 numChildren = cN->GetChildCount(); + nsINode *n = aRoot; + PRInt32 numChildren = n->GetChildCount(); while (numChildren) { - nsIContent *cChild = cN->GetChildAt(--numChildren); + nsINode *nChild = n->GetChildAt(--numChildren); if (aIndexes) { // Add this node to the stack of indexes aIndexes->AppendElement(NS_INT32_TO_PTR(numChildren)); } - numChildren = cChild->GetChildCount(); - cN = cChild; + numChildren = nChild->GetChildCount(); + n = nChild; - deepLastChild = cN; + deepLastChild = n; } return deepLastChild; } // Get the next sibling, or parents next sibling, or grandpa's next sibling... -nsIContent * +nsINode * nsContentIterator::GetNextSibling(nsINode *aNode, nsVoidArray *aIndexes) { if (!aNode) return nsnull; nsINode *parent = aNode->GetNodeParent(); if (!parent) @@ -631,17 +651,17 @@ nsContentIterator::GetNextSibling(nsINod indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]); } else indx = mCachedIndex; // reverify that the index of the current node hasn't changed. // not super cheap, but a lot cheaper than IndexOf(), and still O(1). // ignore result this time - the index may now be out of range. - nsIContent *sib = parent->GetChildAt(indx); + nsINode* sib = parent->GetChildAt(indx); if (sib != aNode) { // someone changed our index - find the new index the painful way indx = parent->IndexOf(aNode); } // indx is now canonically correct if ((sib = parent->GetChildAt(++indx))) @@ -670,17 +690,17 @@ nsContentIterator::GetNextSibling(nsINod // ok to leave cache out of date here if parent == mCommonParent? sib = GetNextSibling(parent, aIndexes); } return sib; } // Get the prev sibling, or parents prev sibling, or grandpa's prev sibling... -nsIContent * +nsINode* nsContentIterator::GetPrevSibling(nsINode *aNode, nsVoidArray *aIndexes) { if (!aNode) return nsnull; nsINode *parent = aNode->GetNodeParent(); if (!parent) @@ -694,17 +714,17 @@ nsContentIterator::GetPrevSibling(nsINod // use the last entry on the Indexes array for the current index indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]); } else indx = mCachedIndex; // reverify that the index of the current node hasn't changed // ignore result this time - the index may now be out of range. - nsIContent *sib = parent->GetChildAt(indx); + nsINode *sib = parent->GetChildAt(indx); if (sib != aNode) { // someone changed our index - find the new index the painful way indx = parent->IndexOf(aNode); } // indx is now canonically correct if (indx > 0 && (sib = parent->GetChildAt(--indx))) @@ -724,83 +744,83 @@ nsContentIterator::GetPrevSibling(nsINod aIndexes->RemoveElementAt(aIndexes->Count()-1); } return GetPrevSibling(parent, aIndexes); } return sib; } -nsIContent * -nsContentIterator::NextNode(nsIContent *aNode, nsVoidArray *aIndexes) +nsINode* +nsContentIterator::NextNode(nsINode *aNode, nsVoidArray *aIndexes) { - nsIContent *cN = aNode; - nsIContent *nextNode = nsnull; + nsINode *n = aNode; + nsINode *nextNode = nsnull; if (mPre) // if we are a Pre-order iterator, use pre-order { // if it has children then next node is first child - if (NodeHasChildren(cN)) + if (NodeHasChildren(n)) { - nsIContent *cFirstChild = cN->GetChildAt(0); + nsINode *nFirstChild = n->GetChildAt(0); // update cache if (aIndexes) { // push an entry on the index stack aIndexes->AppendElement(NS_INT32_TO_PTR(0)); } else mCachedIndex = 0; - return cFirstChild; + return nFirstChild; } // else next sibling is next - nextNode = GetNextSibling(cN, aIndexes); + nextNode = GetNextSibling(n, aIndexes); } else // post-order { - nsIContent *parent = cN->GetParent(); - nsIContent *cSibling = nsnull; + nsINode *parent = n->GetParent(); + nsINode *nSibling = nsnull; PRInt32 indx; // get the cached index if (aIndexes) { NS_ASSERTION(aIndexes->Count() > 0, "ContentIterator stack underflow"); // use the last entry on the Indexes array for the current index indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]); } else indx = mCachedIndex; // reverify that the index of the current node hasn't changed. // not super cheap, but a lot cheaper than IndexOf(), and still O(1). // ignore result this time - the index may now be out of range. if (indx >= 0) - cSibling = parent->GetChildAt(indx); - if (cSibling != cN) + nSibling = parent->GetChildAt(indx); + if (nSibling != n) { // someone changed our index - find the new index the painful way - indx = parent->IndexOf(cN); + indx = parent->IndexOf(n); } // indx is now canonically correct - cSibling = parent->GetChildAt(++indx); - if (cSibling) + nSibling = parent->GetChildAt(++indx); + if (nSibling) { // update cache if (aIndexes) { // replace an entry on the index stack aIndexes->ReplaceElementAt(NS_INT32_TO_PTR(indx),aIndexes->Count()-1); } else mCachedIndex = indx; // next node is siblings "deep left" child - return GetDeepFirstChild(cSibling, aIndexes); + return GetDeepFirstChild(nSibling, aIndexes); } // else it's the parent // update cache if (aIndexes) { // pop an entry off the index stack // Don't leave the index empty, especially if we're @@ -810,96 +830,96 @@ nsContentIterator::NextNode(nsIContent * } else mCachedIndex = 0; // this might be wrong, but we are better off guessing nextNode = parent; } return nextNode; } -nsIContent * -nsContentIterator::PrevNode(nsIContent *aNode, nsVoidArray *aIndexes) +nsINode* +nsContentIterator::PrevNode(nsINode *aNode, nsVoidArray *aIndexes) { - nsIContent *prevNode = nsnull; - nsIContent *cN = aNode; + nsINode *prevNode = nsnull; + nsINode *n = aNode; if (mPre) // if we are a Pre-order iterator, use pre-order { - nsIContent *parent = cN->GetParent(); - nsIContent *cSibling = nsnull; + nsINode *parent = n->GetParent(); + nsINode *nSibling = nsnull; PRInt32 indx; // get the cached index if (aIndexes) { NS_ASSERTION(aIndexes->Count() > 0, "ContentIterator stack underflow"); // use the last entry on the Indexes array for the current index indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]); } else indx = mCachedIndex; // reverify that the index of the current node hasn't changed. // not super cheap, but a lot cheaper than IndexOf(), and still O(1). // ignore result this time - the index may now be out of range. if (indx >= 0) - cSibling = parent->GetChildAt(indx); + nSibling = parent->GetChildAt(indx); - if (cSibling != cN) + if (nSibling != n) { // someone changed our index - find the new index the painful way - indx = parent->IndexOf(cN); + indx = parent->IndexOf(n); } // indx is now canonically correct - if (indx && (cSibling = parent->GetChildAt(--indx))) + if (indx && (nSibling = parent->GetChildAt(--indx))) { // update cache if (aIndexes) { // replace an entry on the index stack aIndexes->ReplaceElementAt(NS_INT32_TO_PTR(indx),aIndexes->Count()-1); } else mCachedIndex = indx; // prev node is siblings "deep right" child - return GetDeepLastChild(cSibling, aIndexes); + return GetDeepLastChild(nSibling, aIndexes); } // else it's the parent // update cache if (aIndexes) { // pop an entry off the index stack aIndexes->RemoveElementAt(aIndexes->Count()-1); } else mCachedIndex = 0; // this might be wrong, but we are better off guessing prevNode = parent; } else // post-order { - PRInt32 numChildren = cN->GetChildCount(); + PRInt32 numChildren = n->GetChildCount(); // if it has children then prev node is last child if (numChildren) { - nsIContent *cLastChild = cN->GetChildAt(--numChildren); + nsINode *nLastChild = n->GetChildAt(--numChildren); // update cache if (aIndexes) { // push an entry on the index stack aIndexes->AppendElement(NS_INT32_TO_PTR(numChildren)); } else mCachedIndex = numChildren; - return cLastChild; + return nLastChild; } // else prev sibling is previous - prevNode = GetPrevSibling(cN, aIndexes); + prevNode = GetPrevSibling(n, aIndexes); } return prevNode; } /****************************************************** * ContentIterator routines ******************************************************/ @@ -977,69 +997,69 @@ nsContentIterator::IsDone() { return mIsDone; } // Keeping arrays of indexes for the stack of nodes makes PositionAt // interesting... nsresult -nsContentIterator::PositionAt(nsIContent* aCurNode) +nsContentIterator::PositionAt(nsINode* aCurNode) { if (!aCurNode) return NS_ERROR_NULL_POINTER; - nsIContent *newCurNode = aCurNode; - nsIContent *tempNode = mCurNode; + nsINode *newCurNode = aCurNode; + nsINode *tempNode = mCurNode; mCurNode = aCurNode; // take an early out if this doesn't actually change the position if (mCurNode == tempNode) { mIsDone = PR_FALSE; // paranoia return NS_OK; } // Check to see if the node falls within the traversal range. - nsIContent* firstNode = mFirst; - nsIContent* lastNode = mLast; + nsINode* firstNode = mFirst; + nsINode* lastNode = mLast; PRInt32 firstOffset=0, lastOffset=0; if (firstNode && lastNode) { if (mPre) { - firstNode = ContentToParentOffset(mFirst, &firstOffset); + firstNode = NodeToParentOffset(mFirst, &firstOffset); if (lastNode->GetChildCount()) lastOffset = 0; else { - lastNode = ContentToParentOffset(mLast, &lastOffset); + lastNode = NodeToParentOffset(mLast, &lastOffset); ++lastOffset; } } else { PRUint32 numChildren = firstNode->GetChildCount(); if (numChildren) firstOffset = numChildren; else - firstNode = ContentToParentOffset(mFirst, &firstOffset); + firstNode = NodeToParentOffset(mFirst, &firstOffset); - lastNode = ContentToParentOffset(mLast, &lastOffset); + lastNode = NodeToParentOffset(mLast, &lastOffset); ++lastOffset; } } if (!firstNode || !lastNode || - !ContentIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset, - lastNode, lastOffset)) + !NodeIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset, + lastNode, lastOffset)) { mIsDone = PR_TRUE; return NS_ERROR_FAILURE; } // We can be at ANY node in the sequence. // Need to regenerate the array of indexes back to the root or common parent! nsAutoVoidArray oldParentStack; @@ -1061,17 +1081,17 @@ nsContentIterator::PositionAt(nsIContent // sure we include mCommonParent in the oldParentStack, for use in the next // for loop, and mIndexes only has entries for nodes from tempNode up through // an ancestor of tempNode that's a child of mCommonParent. for (PRInt32 i = mIndexes.Count()+1; i > 0 && tempNode; i--) { // Insert at head since we're walking up oldParentStack.InsertElementAt(tempNode,0); - nsIContent *parent = tempNode->GetParent(); + nsINode *parent = tempNode->GetNodeParent(); if (!parent) // this node has no parent, and thus no index break; if (parent == mCurNode) { // The position was moved to a parent of the current position. // All we need to do is drop some indexes. Shortcut here. @@ -1081,17 +1101,17 @@ nsContentIterator::PositionAt(nsIContent return NS_OK; } tempNode = parent; } // Ok. We have the array of old parents. Look for a match. while (newCurNode) { - nsIContent *parent = newCurNode->GetParent(); + nsINode *parent = newCurNode->GetNodeParent(); if (!parent) // this node has no parent, and thus no index break; PRInt32 indx = parent->IndexOf(newCurNode); // insert at the head! newIndexes.InsertElementAt(NS_INT32_TO_PTR(indx),0); @@ -1116,19 +1136,18 @@ nsContentIterator::PositionAt(nsIContent } // phew! mIsDone = PR_FALSE; return NS_OK; } - -nsIContent * -nsContentIterator::GetCurrentNode() +nsINode* +nsContentIterator::GetCurrent() { if (mIsDone) { return nsnull; } NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!"); return mCurNode; @@ -1157,36 +1176,48 @@ nsContentIterator::GetCurrentNode() class nsContentSubtreeIterator : public nsContentIterator { public: nsContentSubtreeIterator() {} virtual ~nsContentSubtreeIterator() {} // nsContentIterator overrides ------------------------------ - virtual nsresult Init(nsIContent* aRoot); + virtual nsresult Init(nsIContent* aRoot) + { + return Init(static_cast(aRoot)); + } virtual nsresult Init(nsIDOMRange* aRange); virtual void Next(); virtual void Prev(); - virtual nsresult PositionAt(nsIContent* aCurNode); + virtual nsresult PositionAt(nsIContent* aCurNode) + { + return PositionAt(static_cast(aCurNode)); + } // Must override these because we don't do PositionAt virtual void First(); // Must override these because we don't do PositionAt virtual void Last(); + // nsINodeIterator interface methods ------------------------------ + + virtual nsresult Init(nsINode* aRoot); + + virtual nsresult PositionAt(nsINode* aCurNode); + protected: - nsresult GetTopAncestorInRange(nsIContent *aNode, - nsCOMPtr *outAnestor); + nsresult GetTopAncestorInRange(nsINode *aNode, + nsCOMPtr *outAnestor); // no copy's or assigns FIX ME nsContentSubtreeIterator(const nsContentSubtreeIterator&); nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&); nsCOMPtr mRange; // these arrays all typically are used and have elements #if 0 @@ -1221,72 +1252,65 @@ nsresult NS_NewContentSubtreeIterator(ns /****************************************************** * Init routines ******************************************************/ -nsresult nsContentSubtreeIterator::Init(nsIContent* aRoot) +nsresult nsContentSubtreeIterator::Init(nsINode* aRoot) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult nsContentSubtreeIterator::Init(nsIDOMRange* aRange) { if (!aRange) return NS_ERROR_NULL_POINTER; mIsDone = PR_FALSE; mRange = aRange; - // get the start node and offset, convert to nsIContent + // get the start node and offset, convert to nsINode nsCOMPtr commonParent; nsCOMPtr startParent; nsCOMPtr endParent; - nsCOMPtr cStartP; - nsCOMPtr cEndP; - nsCOMPtr cN; - nsIContent *firstCandidate = nsnull; - nsIContent *lastCandidate = nsnull; + nsCOMPtr nStartP; + nsCOMPtr nEndP; + nsCOMPtr n; + nsINode *firstCandidate = nsnull; + nsINode *lastCandidate = nsnull; PRInt32 indx, startIndx, endIndx; // get common content parent if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent))) || !commonParent) return NS_ERROR_FAILURE; mCommonParent = do_QueryInterface(commonParent); // get start content parent if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(startParent))) || !startParent) return NS_ERROR_FAILURE; - cStartP = do_QueryInterface(startParent); + nStartP = do_QueryInterface(startParent); aRange->GetStartOffset(&startIndx); // get end content parent if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(endParent))) || !endParent) return NS_ERROR_FAILURE; - cEndP = do_QueryInterface(endParent); + nEndP = do_QueryInterface(endParent); aRange->GetEndOffset(&endIndx); - if (!cStartP || !cEndP) - { - // XXX Hack to account for the fact that not everything QIs to nsIContent. - // See bug 302775 - return NS_ERROR_FAILURE; - } - // short circuit when start node == end node if (startParent == endParent) { - nsIContent* cChild = cStartP->GetChildAt(0); + nsINode* nChild = nStartP->GetChildAt(0); - if (!cChild) // no children, must be a text node or empty container + if (!nChild) // no children, must be a text node or empty container { // all inside one text node - empty subtree iterator MakeEmpty(); return NS_OK; } else { if (startIndx == endIndx) // collapsed range @@ -1303,37 +1327,37 @@ nsresult nsContentSubtreeIterator::Init( &mStartNodes, &mStartOffsets); #endif nsContentUtils::GetAncestorsAndOffsets(endParent, endIndx, &mEndNodes, &mEndOffsets); // find first node in range aRange->GetStartOffset(&indx); - if (!cStartP->GetChildCount()) // no children, start at the node itself + if (!nStartP->GetChildCount()) // no children, start at the node itself { - cN = cStartP; + n = nStartP; } else { - nsIContent* cChild = cStartP->GetChildAt(indx); - if (!cChild) // offset after last child + nsINode* nChild = nStartP->GetChildAt(indx); + if (!nChild) // offset after last child { - cN = cStartP; + n = nStartP; } else { - firstCandidate = cChild; + firstCandidate = nChild; } } if (!firstCandidate) { // then firstCandidate is next node after cN - firstCandidate = GetNextSibling(cN, nsnull); + firstCandidate = GetNextSibling(n, nsnull); if (!firstCandidate) { MakeEmpty(); return NS_OK; } } @@ -1357,41 +1381,41 @@ nsresult nsContentSubtreeIterator::Init( // cool, we have the first node in the range. Now we walk // up it's ancestors to find the most senior that is still // in the range. That's the real first node. if (NS_FAILED(GetTopAncestorInRange(firstCandidate, address_of(mFirst)))) return NS_ERROR_FAILURE; // now to find the last node aRange->GetEndOffset(&indx); - PRInt32 numChildren = cEndP->GetChildCount(); + PRInt32 numChildren = nEndP->GetChildCount(); if (indx > numChildren) indx = numChildren; if (!indx) { - cN = cEndP; + n = nEndP; } else { if (!numChildren) // no children, must be a text node { - cN = cEndP; + n = nEndP; } else { - lastCandidate = cEndP->GetChildAt(--indx); + lastCandidate = nEndP->GetChildAt(--indx); NS_ASSERTION(lastCandidate, "tree traversal trouble in nsContentSubtreeIterator::Init"); } } if (!lastCandidate) { - // then lastCandidate is prev node before cN - lastCandidate = GetPrevSibling(cN, nsnull); + // then lastCandidate is prev node before n + lastCandidate = GetPrevSibling(n, nsnull); } lastCandidate = GetDeepLastChild(lastCandidate, nsnull); // confirm that this last possible contained node // is indeed contained. Else we have a range that // does not fully contain any node. @@ -1447,17 +1471,17 @@ nsContentSubtreeIterator::Next() return; if (mCurNode == mLast) { mIsDone = PR_TRUE; return; } - nsIContent *nextNode = GetNextSibling(mCurNode, nsnull); + nsINode *nextNode = GetNextSibling(mCurNode, nsnull); NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!"); /* nextNode = GetDeepFirstChild(nextNode); return GetTopAncestorInRange(nextNode, address_of(mCurNode)); */ PRInt32 i = mEndNodes.IndexOf(nextNode); while (i != -1) @@ -1494,80 +1518,80 @@ nsContentSubtreeIterator::Prev() return; if (mCurNode == mFirst) { mIsDone = PR_TRUE; return; } - nsIContent *prevNode = PrevNode(GetDeepFirstChild(mCurNode, nsnull), nsnull); + nsINode *prevNode = PrevNode(GetDeepFirstChild(mCurNode, nsnull), nsnull); prevNode = GetDeepLastChild(prevNode, nsnull); GetTopAncestorInRange(prevNode, address_of(mCurNode)); // This shouldn't be needed, but since our selection code can put us // in a situation where mFirst is in generated content, we need this // to stop the iterator when we've walked past past the first node! mIsDone = mCurNode == nsnull; } nsresult -nsContentSubtreeIterator::PositionAt(nsIContent* aCurNode) +nsContentSubtreeIterator::PositionAt(nsINode* aCurNode) { NS_ERROR("Not implemented!"); return NS_ERROR_NOT_IMPLEMENTED; } /**************************************************************** * nsContentSubtreeIterator helper routines ****************************************************************/ nsresult -nsContentSubtreeIterator::GetTopAncestorInRange(nsIContent *aNode, - nsCOMPtr *outAnestor) +nsContentSubtreeIterator::GetTopAncestorInRange(nsINode *aNode, + nsCOMPtr *outAncestor) { if (!aNode) return NS_ERROR_NULL_POINTER; - if (!outAnestor) + if (!outAncestor) return NS_ERROR_NULL_POINTER; // sanity check: aNode is itself in the range PRBool nodeBefore, nodeAfter; if (NS_FAILED(nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter))) return NS_ERROR_FAILURE; if (nodeBefore || nodeAfter) return NS_ERROR_FAILURE; - nsCOMPtr parent, tmp; + nsCOMPtr parent, tmp; while (aNode) { - parent = aNode->GetParent(); + parent = aNode->GetNodeParent(); if (!parent) { if (tmp) { - *outAnestor = tmp; + *outAncestor = tmp; return NS_OK; } else return NS_ERROR_FAILURE; } if (NS_FAILED(nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter))) return NS_ERROR_FAILURE; if (nodeBefore || nodeAfter) { - *outAnestor = aNode; + *outAncestor = aNode; return NS_OK; } tmp = aNode; aNode = parent; } return NS_ERROR_FAILURE; } Index: content/base/src/nsRange.cpp =================================================================== RCS file: /cvsroot/mozilla/content/base/src/nsRange.cpp,v retrieving revision 1.229 diff -u -8 -p -r1.229 nsRange.cpp --- content/base/src/nsRange.cpp 13 Mar 2008 10:12:51 -0000 1.229 +++ content/base/src/nsRange.cpp 9 May 2008 10:03:31 -0000 @@ -47,17 +47,17 @@ #include "nsIDOMNode.h" #include "nsIDOMDocument.h" #include "nsIDOMNSDocument.h" #include "nsIDOMDocumentFragment.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMText.h" #include "nsDOMError.h" -#include "nsIContentIterator.h" +#include "nsINodeIterator.h" #include "nsIDOMNodeList.h" #include "nsGkAtoms.h" #include "nsContentUtils.h" nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult); nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult); /****************************************************** @@ -83,29 +83,29 @@ nsresult NS_NewContentSubtreeIterator(ns // If outNodeBefore is returned true, then the node starts before the range does. // If outNodeAfter is returned true, then the node ends after the range does. // Note that both of the above might be true. // If neither are true, the node is contained inside of the range. // XXX - callers responsibility to ensure node in same doc as range! // static nsresult -nsRange::CompareNodeToRange(nsIContent* aNode, nsIDOMRange* aRange, +nsRange::CompareNodeToRange(nsINode* aNode, nsIDOMRange* aRange, PRBool *outNodeBefore, PRBool *outNodeAfter) { nsresult rv; nsCOMPtr range = do_QueryInterface(aRange, &rv); NS_ENSURE_SUCCESS(rv, rv); return CompareNodeToRange(aNode, range, outNodeBefore, outNodeAfter); } // static nsresult -nsRange::CompareNodeToRange(nsIContent* aNode, nsIRange* aRange, +nsRange::CompareNodeToRange(nsINode* aNode, nsIRange* aRange, PRBool *outNodeBefore, PRBool *outNodeAfter) { NS_ENSURE_STATE(aNode); // create a pair of dom points that expresses location of node: // NODE(start), NODE(end) // Let incoming range be: // {RANGE(start), RANGE(end)} // if (RANGE(start) <= NODE(start)) and (RANGE(end) => NODE(end)) @@ -793,17 +793,17 @@ class RangeSubtreeIterator { private: enum RangeSubtreeIterState { eDone=0, eUseStartCData, eUseIterator, eUseEndCData }; - nsCOMPtr mIter; + nsCOMPtr mIter; RangeSubtreeIterState mIterState; nsCOMPtr mStartCData; nsCOMPtr mEndCData; public: RangeSubtreeIterator() @@ -860,18 +860,21 @@ RangeSubtreeIterator::Init(nsIDOMRange * mEndCData = nsnull; } else { // Now create a Content Subtree Iterator to be used // for the subtrees between the end points! - res = NS_NewContentSubtreeIterator(getter_AddRefs(mIter)); + nsCOMPtr iter; + res = NS_NewContentSubtreeIterator(getter_AddRefs(iter)); if (NS_FAILED(res)) return res; + mIter = do_QueryInterface(mIter); + NS_ENSURE_STATE(mIter); res = mIter->Init(aRange); if (NS_FAILED(res)) return res; if (mIter->IsDone()) { // The subtree iterator thinks there's nothing // to iterate over, so just free it up so we @@ -895,20 +898,20 @@ RangeSubtreeIterator::GetCurrentNode() nsIDOMNode *node = nsnull; if (mIterState == eUseStartCData && mStartCData) { NS_ADDREF(node = mStartCData); } else if (mIterState == eUseEndCData && mEndCData) NS_ADDREF(node = mEndCData); else if (mIterState == eUseIterator && mIter) { - nsIContent *content = mIter->GetCurrentNode(); + nsINode* n = mIter->GetCurrent(); - if (content) { - CallQueryInterface(content, &node); + if (n) { + CallQueryInterface(n, &node); } } return node; } void RangeSubtreeIterator::First() @@ -1719,44 +1722,46 @@ nsresult nsRange::ToString(nsAString& aR return NS_OK; } } /* complex case: mStartParent != mEndParent, or mStartParent not a text node revisit - there are potential optimizations here and also tradeoffs. */ - nsCOMPtr iter; - NS_NewContentIterator(getter_AddRefs(iter)); + nsCOMPtr contentIter; + NS_NewContentIterator(getter_AddRefs(contentIter)); + nsCOMPtr iter = do_QueryInterface(contentIter); + NS_ENSURE_STATE(iter); nsresult rv = iter->Init(this); NS_ENSURE_SUCCESS(rv, rv); nsString tempString; // loop through the content iterator, which returns nodes in the range in // close tag order, and grab the text from any text node while (!iter->IsDone()) { - nsIContent *cN = iter->GetCurrentNode(); + nsINode *n = iter->GetCurrent(); #ifdef DEBUG_range // If debug, dump it: - cN->List(stdout); + n->List(stdout); #endif /* DEBUG */ - nsCOMPtr textNode( do_QueryInterface(cN) ); + nsCOMPtr textNode(do_QueryInterface(n)); if (textNode) // if it's a text node, get the text { - if (cN == mStartParent) // only include text past start offset + if (n == mStartParent) // only include text past start offset { PRUint32 strLength; textNode->GetLength(&strLength); textNode->SubstringData(mStartOffset,strLength-mStartOffset,tempString); aReturn += tempString; } - else if (cN == mEndParent) // only include text before end offset + else if (n == mEndParent) // only include text before end offset { textNode->SubstringData(0,mEndOffset,tempString); aReturn += tempString; } else // grab the whole kit-n-kaboodle { textNode->GetData(tempString); aReturn += tempString; Index: content/base/src/nsRange.h =================================================================== RCS file: /cvsroot/mozilla/content/base/src/nsRange.h,v retrieving revision 1.60 diff -u -8 -p -r1.60 nsRange.h --- content/base/src/nsRange.h 24 Feb 2008 12:46:09 -0000 1.60 +++ content/base/src/nsRange.h 9 May 2008 10:03:31 -0000 @@ -122,20 +122,20 @@ private: public: /****************************************************************************** * Utility routine to detect if a content node starts before a range and/or * ends after a range. If neither it is contained inside the range. * * XXX - callers responsibility to ensure node in same doc as range! * *****************************************************************************/ - static nsresult CompareNodeToRange(nsIContent* aNode, nsIDOMRange* aRange, + static nsresult CompareNodeToRange(nsINode* aNode, nsIDOMRange* aRange, PRBool *outNodeBefore, PRBool *outNodeAfter); - static nsresult CompareNodeToRange(nsIContent* aNode, nsIRange* aRange, + static nsresult CompareNodeToRange(nsINode* aNode, nsIRange* aRange, PRBool *outNodeBefore, PRBool *outNodeAfter); protected: void DoSetRange(nsINode* aStartN, PRInt32 aStartOffset, nsINode* aEndN, PRInt32 aEndOffset, nsINode* aRoot); };