/* -*- Mode: C++; tab-width: 2; 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 * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf * * 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 ***** */ #include "nsISupports.h" #include "nsIDOMNodeList.h" #include "nsIContentIterator.h" #include "nsRange.h" #include "nsIContent.h" #include "nsIDOMText.h" #include "nsISupportsArray.h" #include "nsCOMPtr.h" #include "nsPresContext.h" #include "nsIComponentManager.h" #include "nsContentCID.h" #include "nsIPresShell.h" #define DO_AFTER 1 #define DO_BEFORE 1 /////////////////////////////////////////////////////////////////////////// // GetNumChildren: returns the number of things inside aNode. // static PRUint32 GetNumChildren(nsIDOMNode *aNode) { PRUint32 numChildren = 0; if (!aNode) return 0; PRBool hasChildNodes; aNode->HasChildNodes(&hasChildNodes); if (hasChildNodes) { nsCOMPtrnodeList; nsresult res = aNode->GetChildNodes(getter_AddRefs(nodeList)); if (NS_SUCCEEDED(res) && nodeList) nodeList->GetLength(&numChildren); } return numChildren; } /////////////////////////////////////////////////////////////////////////// // GetChildAt: returns the node at this position index in the parent // static nsCOMPtr GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset) { nsCOMPtr resultNode; if (!aParent) return resultNode; PRBool hasChildNodes; aParent->HasChildNodes(&hasChildNodes); if (PR_TRUE==hasChildNodes) { nsCOMPtrnodeList; nsresult res = aParent->GetChildNodes(getter_AddRefs(nodeList)); if (NS_SUCCEEDED(res) && nodeList) nodeList->Item(aOffset, getter_AddRefs(resultNode)); } return resultNode; } /* * A simple iterator class for traversing the generated content in "close tag" order */ class nsGeneratedContentIterator : public nsIContentIterator, public nsIGeneratedContentIterator { public: NS_DECL_ISUPPORTS nsGeneratedContentIterator(); virtual ~nsGeneratedContentIterator(); // nsIContentIterator interface methods ------------------------------ virtual nsresult Init(nsIContent* aRoot); virtual nsresult Init(nsIDOMRange* aRange); virtual void First(); virtual void Last(); virtual void Next(); virtual void Prev(); virtual nsIContent *GetCurrentNode(); virtual PRBool IsDone(); virtual nsresult PositionAt(nsIContent* aCurNode); // nsIEnumertor interface methods ------------------------------ //NS_IMETHOD CurrentItem(nsISupports **aItem); //nsIGeneratedContentIterator virtual nsresult Init(nsIPresShell *aShell, nsIDOMRange* aRange); virtual nsresult Init(nsIPresShell *aShell, nsIContent* aContent); protected: // Do these cause too much refcounting??? nsCOMPtr GetDeepFirstChild(nsCOMPtr aRoot); nsCOMPtr GetDeepLastChild(nsCOMPtr aRoot); nsIContent *GetNextSibling(nsIContent *aNode); nsIContent *GetPrevSibling(nsIContent *aNode); nsIContent *NextNode(nsIContent *aNode); nsIContent *PrevNode(nsIContent *aNode); void MakeEmpty(); nsCOMPtr mCurNode; nsCOMPtr mFirst; nsCOMPtr mLast; nsCOMPtr mCommonParent; nsCOMPtr mFirstIter; nsCOMPtr mLastIter; nsCOMPtr mGenIter; nsIPresShell::GeneratedContentType mIterType; nsIPresShell::GeneratedContentType mFirstIterType; nsIPresShell::GeneratedContentType mLastIterType; nsCOMPtr mPresShell; PRBool mIsDone; private: // no copy's or assigns FIX ME nsGeneratedContentIterator(const nsGeneratedContentIterator&); nsGeneratedContentIterator& operator=(const nsGeneratedContentIterator&); }; /****************************************************** * repository cruft ******************************************************/ nsresult NS_NewGenRegularIterator(nsIContentIterator ** aInstancePtrResult) { nsGeneratedContentIterator * iter = new nsGeneratedContentIterator(); if (!iter) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(*aInstancePtrResult = iter); return NS_OK; } /****************************************************** * XPCOM cruft ******************************************************/ NS_IMPL_ISUPPORTS2(nsGeneratedContentIterator, nsIGeneratedContentIterator, nsIContentIterator) /****************************************************** * constructor/destructor ******************************************************/ nsGeneratedContentIterator::nsGeneratedContentIterator() : mIsDone(PR_FALSE) { } nsGeneratedContentIterator::~nsGeneratedContentIterator() { } /****************************************************** * Init routines ******************************************************/ nsresult nsGeneratedContentIterator::Init(nsIContent* aRoot) { if (!aRoot) return NS_ERROR_NULL_POINTER; mIsDone = PR_FALSE; nsCOMPtr root(aRoot); mFirst = GetDeepFirstChild(root); if (mGenIter)//we have generated { mFirstIter = mGenIter; mFirstIterType = mIterType; } mLast = root; mCommonParent = root; mCurNode = mFirst; return NS_OK; } nsresult nsGeneratedContentIterator::Init(nsIPresShell *aShell, nsIDOMRange* aRange) { mPresShell = aShell; return Init(aRange); } nsresult nsGeneratedContentIterator::Init(nsIPresShell *aShell, nsIContent* aContent) { mPresShell = aShell; return Init(aContent); } nsresult nsGeneratedContentIterator::Init(nsIDOMRange* aRange) { if (!aRange) return NS_ERROR_NULL_POINTER; nsCOMPtr dN; nsCOMPtr startCon; nsCOMPtr startDOM; nsCOMPtr endCon; nsCOMPtr endDOM; PRInt32 startIndx; PRInt32 endIndx; mIsDone = PR_FALSE; // get common content parent if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(dN))) || !dN) return NS_ERROR_FAILURE; mCommonParent = do_QueryInterface(dN); // get the start node and offset, convert to nsIContent aRange->GetStartContainer(getter_AddRefs(startDOM)); if (!startDOM) return NS_ERROR_ILLEGAL_VALUE; startCon = do_QueryInterface(startDOM); if (!startCon) return NS_ERROR_FAILURE; aRange->GetStartOffset(&startIndx); // get the end node and offset, convert to nsIContent aRange->GetEndContainer(getter_AddRefs(endDOM)); if (!endDOM) return NS_ERROR_ILLEGAL_VALUE; endCon = do_QueryInterface(endDOM); if (!endCon) return NS_ERROR_FAILURE; aRange->GetEndOffset(&endIndx); // find first node in range nsIContent *cChild = startCon->GetChildAt(0); // short circuit when start node == end node if (startDOM == endDOM) { if (!cChild) // no children, must be a text node or empty container { mFirst = startCon; mLast = startCon; mCurNode = startCon; return NS_OK; } else { if (startIndx == endIndx) // collapsed range { MakeEmpty(); return NS_OK; } } } if (!cChild) // no children, must be a text node { mFirst = startCon; } else { cChild = startCon->GetChildAt(startIndx); if (!cChild) // offset after last child, parent is first node { mFirst = startCon; } else { mFirst = GetDeepFirstChild(cChild); if (mGenIter) { mFirstIter = mGenIter; mFirstIterType = mIterType; } } // Does that first node really intersect the range? // the range could be collapsed, or the range could be // 'degenerate', ie not collapsed but still containing // no content. In this case, we want the iterator to // be empty if (!nsRange::IsNodeIntersectsRange(mFirst, aRange)) { MakeEmpty(); return NS_OK; } } // find last node in range cChild = endCon->GetChildAt(0); if (!cChild) // no children, must be a text node { mLast = endCon; } else if (endIndx == 0) // before first child, parent is last node { mLast = endCon; } else { cChild = endCon->GetChildAt(--endIndx); if (!cChild) // offset after last child, last child is last node { endIndx = (PRInt32)endCon->GetChildCount(); cChild = endCon->GetChildAt(--endIndx); if (!cChild) { NS_NOTREACHED("nsGeneratedContentIterator::nsGeneratedContentIterator"); return NS_ERROR_FAILURE; } } mLast = cChild; } mCurNode = mFirst; return NS_OK; } /****************************************************** * Helper routines ******************************************************/ void nsGeneratedContentIterator::MakeEmpty() { nsCOMPtr noNode; mCurNode = noNode; mFirst = noNode; mLast = noNode; mCommonParent = noNode; mIsDone = PR_TRUE; mGenIter = 0; mFirstIter = 0; mIterType = nsIPresShell::Before; } nsCOMPtr nsGeneratedContentIterator::GetDeepFirstChild(nsCOMPtr aRoot) { nsCOMPtr deepFirstChild; if (aRoot) { nsCOMPtr cN = aRoot; #if DO_BEFORE //CHECK FOR BEFORESTUFF nsresult result = NS_ERROR_FAILURE; if (mPresShell) result = mPresShell->GetGeneratedContentIterator(cN,nsIPresShell::Before,getter_AddRefs(mGenIter)); if (NS_SUCCEEDED(result) && mGenIter) { //ok we have a generated iter all bets are off mIterType = nsIPresShell::Before; mGenIter->First(); return cN; } #endif nsIContent *cChild; while ((cChild = cN->GetChildAt(0))) { cN = cChild; #if DO_BEFORE //CHECK FOR BEFORESTUFF if (mPresShell) result = mPresShell->GetGeneratedContentIterator(cN,nsIPresShell::Before,getter_AddRefs(mGenIter)); if (NS_SUCCEEDED(result) && mGenIter) { //ok we have a generated iter all bets are off mIterType = nsIPresShell::Before; mGenIter->First(); return cN; } #endif } deepFirstChild = cN; } return deepFirstChild; } nsCOMPtr nsGeneratedContentIterator::GetDeepLastChild(nsCOMPtr aRoot) { nsCOMPtr deepFirstChild; if (aRoot) { nsCOMPtr cN = aRoot; nsCOMPtr cChild; #if DO_AFTER //CHECK FOR AFTER STUFF nsresult result = NS_ERROR_FAILURE; if (mPresShell) result = mPresShell->GetGeneratedContentIterator(cN,nsIPresShell::After,getter_AddRefs(mGenIter)); if (NS_SUCCEEDED(result) && mGenIter) { //ok we have a generated iter all bets are off mIterType = nsIPresShell::After; mGenIter->First(); return cN; } #endif PRUint32 numChildren = cN->GetChildCount(); while ( numChildren ) { cChild = cN->GetChildAt(--numChildren); if (cChild) { #if DO_AFTER //CHECK FOR AFTER STUFF if (mPresShell) result = mPresShell->GetGeneratedContentIterator(cChild,nsIPresShell::After,getter_AddRefs(mGenIter)); if (NS_SUCCEEDED(result) && mGenIter) { //ok we have a generated iter all bets are off mGenIter->Last(); mIterType = nsIPresShell::After; return cChild; } #endif numChildren = cChild->GetChildCount(); cN = cChild; } else { break; } } deepFirstChild = cN; } return deepFirstChild; } // Get the next sibling, or parents next sibling, or grandpa's next sibling... nsIContent * nsGeneratedContentIterator::GetNextSibling(nsIContent *aNode) { if (!aNode) return nsnull; nsIContent *parent = aNode->GetParent(); if (!parent) return nsnull; PRInt32 indx = parent->IndexOf(aNode); nsIContent *sib = parent->GetChildAt(++indx); if (!sib) { #if DO_AFTER //CHECK FOR AFTERESTUFF if (mPresShell) mPresShell->GetGeneratedContentIterator(parent, nsIPresShell::After, getter_AddRefs(mGenIter)); if (mGenIter) { //ok we have a generated iter all bets are off mGenIter->First(); mIterType = nsIPresShell::After; return parent; } #endif if (parent != mCommonParent) { return GetNextSibling(parent); } else { sib = nsnull; } } return sib; } // Get the prev sibling, or parents prev sibling, or grandpa's prev sibling... nsIContent * nsGeneratedContentIterator::GetPrevSibling(nsIContent *aNode) { if (!aNode) return nsnull; nsIContent *parent = aNode->GetParent(); if (!parent) return nsnull; PRInt32 indx = parent->IndexOf(aNode); nsIContent *sib = nsnull; if (indx < 1 || !(sib = parent->GetChildAt(--indx))) { #if DO_BEFORE //CHECK FOR BEFORESTUFF if (mPresShell) mPresShell->GetGeneratedContentIterator(parent, nsIPresShell::Before, getter_AddRefs(mGenIter)); if (mGenIter) { //ok we have a generated iter all bets are off mGenIter->Last(); mIterType = nsIPresShell::Before; return parent; } else #endif if (parent != mCommonParent) { return GetPrevSibling(parent); } else { sib = nsnull; } } return sib; } nsIContent * nsGeneratedContentIterator::NextNode(nsIContent *aNode) { if (!aNode) return nsnull; if (mGenIter) { if (mGenIter->IsDone()) mGenIter = 0; else { mGenIter->Next(); return nsnull; } if (nsIPresShell::After == mIterType)//answer is parent { //*ioNextNode = parent; leave it the same return nsnull; } nsIContent *cN = aNode->GetChildAt(0); if (cN) { return GetDeepFirstChild(cN); } } nsIContent *cN = aNode; // get next sibling if there is one nsIContent *parent = cN->GetParent(); if (!parent) { // a little noise to catch some iterator usage bugs. NS_NOTREACHED("nsGeneratedContentIterator::NextNode() : no parent found"); return nsnull; } PRInt32 indx = parent->IndexOf(cN); nsIContent *cSibling = parent->GetChildAt(++indx); if (cSibling) { // next node is siblings "deep left" child return GetDeepFirstChild(cSibling); } //CHECK FOR AFTERSTUFF if (mGenIter)//we allready had an afteriter. it must be done! { mGenIter = 0; } else//check for after node. { if (mPresShell) mPresShell->GetGeneratedContentIterator(parent, nsIPresShell::After, getter_AddRefs(mGenIter)); if (mGenIter) { //ok we have a generated iter all bets are off mGenIter->First(); mIterType = nsIPresShell::After; } else mGenIter = 0; } // else it's the parent return parent; } //THIS NEEDS TO USE A GENERATED SUBTREEITER HERE nsIContent * nsGeneratedContentIterator::PrevNode(nsIContent *aNode) { PRUint32 numChildren = aNode->GetChildCount(); // if it has children then prev node is last child if (numChildren > 0) { return aNode->GetChildAt(--numChildren); } // else prev sibling is previous return GetPrevSibling(aNode); } /****************************************************** * ContentIterator routines ******************************************************/ void nsGeneratedContentIterator::First() { if (!mFirst) { mIsDone = PR_TRUE; return; } mIsDone = PR_FALSE; mCurNode = mFirst; mGenIter = mFirstIter; if (mGenIter)//set directionback to before... mGenIter->First(); } void nsGeneratedContentIterator::Last() { if (!mLast) { mIsDone = PR_TRUE; return; } mIsDone = PR_FALSE; mGenIter = mLastIter; mCurNode = mLast; } void nsGeneratedContentIterator::Next() { if (mIsDone || !mCurNode) return; if (GetCurrentNode() == mLast) { mIsDone = PR_TRUE; return; } mCurNode = NextNode(mCurNode); } void nsGeneratedContentIterator::Prev() { if (mIsDone) return; if (!mCurNode) return; if (mCurNode == mFirst) { mIsDone = PR_TRUE; return; } mCurNode = PrevNode(mCurNode); } PRBool nsGeneratedContentIterator::IsDone() { return mIsDone; } nsresult nsGeneratedContentIterator::PositionAt(nsIContent* aCurNode) { // XXX need to confirm that aCurNode is within range if (!aCurNode) return NS_ERROR_NULL_POINTER; mCurNode = aCurNode; mIsDone = PR_FALSE; return NS_OK; } nsIContent * nsGeneratedContentIterator::GetCurrentNode() { if (!mCurNode || mIsDone) { return nsnull; } if (mGenIter) { return mGenIter->GetCurrentNode(); } NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!"); return mCurNode; } /*====================================================================================*/ //SUBTREE ITERATOR /*====================================================================================*/ /****************************************************** * nsGeneratedSubtreeIterator ******************************************************/ /* * A simple iterator class for traversing the content in "top subtree" order */ class nsGeneratedSubtreeIterator : public nsGeneratedContentIterator { public: nsGeneratedSubtreeIterator() {}; virtual ~nsGeneratedSubtreeIterator() {}; // nsContentIterator overrides ------------------------------ virtual nsresult Init(nsIContent* aRoot); virtual nsresult Init(nsIDOMRange* aRange); virtual void Next(); virtual void Prev(); virtual nsresult PositionAt(nsIContent* aCurNode); //nsIGeneratedContentIterator virtual nsresult Init(nsIPresShell *aShell, nsIDOMRange* aRange); virtual nsresult Init(nsIPresShell *aShell, nsIContent* aContent); protected: nsresult GetTopAncestorInRange( nsCOMPtr aNode, nsCOMPtr *outAnestor); // no copy's or assigns FIX ME nsGeneratedSubtreeIterator(const nsGeneratedSubtreeIterator&); nsGeneratedSubtreeIterator& operator=(const nsGeneratedSubtreeIterator&); nsCOMPtr mRange; }; nsresult NS_NewGenSubtreeIterator(nsIContentIterator** aInstancePtrResult); /****************************************************** * repository cruft ******************************************************/ nsresult NS_NewGenSubtreeIterator(nsIContentIterator** aInstancePtrResult) { nsGeneratedSubtreeIterator * iter = new nsGeneratedSubtreeIterator(); if (!iter) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(*aInstancePtrResult = iter); return NS_OK; } /****************************************************** * Init routines ******************************************************/ nsresult nsGeneratedSubtreeIterator::Init(nsIContent* aRoot) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult nsGeneratedSubtreeIterator::Init(nsIPresShell *aShell, nsIDOMRange* aRange) { mPresShell = aShell; return Init(aRange); } nsresult nsGeneratedSubtreeIterator::Init(nsIPresShell *aShell, nsIContent* aContent) { mPresShell = aShell; return Init(aContent); } nsresult nsGeneratedSubtreeIterator::Init(nsIDOMRange* aRange) { if (!aRange) return NS_ERROR_NULL_POINTER; mIsDone = PR_FALSE; mRange = aRange; // get the start node and offset, convert to nsIContent nsCOMPtr commonParent; nsCOMPtr startParent; nsCOMPtr endParent; nsCOMPtr cStartP; nsCOMPtr cEndP; nsCOMPtr cN; nsCOMPtr firstCandidate; nsCOMPtr lastCandidate; nsCOMPtr dChild; nsCOMPtr cChild; PRInt32 indx, startIndx, endIndx; PRInt32 numChildren; // 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); aRange->GetStartOffset(&startIndx); // get end content parent if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(endParent))) || !endParent) return NS_ERROR_FAILURE; cEndP = do_QueryInterface(endParent); aRange->GetEndOffset(&endIndx); // short circuit when start node == end node if (startParent == endParent) { cChild = cStartP->GetChildAt(0); if (!cChild) // 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 { MakeEmpty(); return NS_OK; } } } // find first node in range aRange->GetStartOffset(&indx); numChildren = GetNumChildren(startParent); if (!numChildren) // no children, must be a text node { cN = cStartP; } else { dChild = GetChildAt(startParent, indx); cChild = do_QueryInterface(dChild); if (!cChild) // offset after last child { cN = cStartP; } else { firstCandidate = cChild; } } if (!firstCandidate) { // then firstCandidate is next node after cN firstCandidate = GetNextSibling(cN); if (!firstCandidate) { MakeEmpty(); return NS_OK; } } if (mGenIter) { mFirstIter = mGenIter; mFirstIterType = mIterType; } if (!mFirstIter) { firstCandidate = GetDeepFirstChild(firstCandidate); if (mGenIter) { mFirstIter = mGenIter; mFirstIterType = mIterType; } } // confirm that this first possible contained node // is indeed contained. Else we have a range that // does not fully contain any node. PRBool nodeBefore(PR_FALSE), nodeAfter(PR_FALSE); if (!mFirstIter && NS_FAILED(nsRange::CompareNodeToRange(firstCandidate, aRange, &nodeBefore, &nodeAfter))) return NS_ERROR_FAILURE; if (nodeBefore || nodeAfter) { MakeEmpty(); return NS_OK; } // 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_SUCCEEDED(GetTopAncestorInRange(firstCandidate, address_of(mFirst)))) { mFirstIter = 0;//ancestor has one no mGenIter = 0; } else if (!mFirstIter) //something bad happened and its not generated content iterators fault return NS_ERROR_FAILURE; else mFirst = firstCandidate;//setting last candidate to parent of generated content this is ok // now to find the last node aRange->GetEndOffset(&indx); numChildren = GetNumChildren(endParent); if (indx > numChildren) indx = numChildren; if (!indx) { cN = cEndP; } else { if (!numChildren) // no children, must be a text node { cN = cEndP; } else { dChild = GetChildAt(endParent, --indx); cChild = do_QueryInterface(dChild); if (!cChild) // shouldn't happen { NS_ASSERTION(0,"tree traversal trouble in nsGeneratedSubtreeIterator::Init"); return NS_ERROR_FAILURE; } else { lastCandidate = cChild; } } } if (!lastCandidate) { // then lastCandidate is prev node before cN lastCandidate = GetPrevSibling(cN); if (!lastCandidate) { MakeEmpty(); return NS_OK; } } if (mGenIter) { mLastIter = mGenIter; mLastIterType = mIterType; } if (!mLastIter)//don't ever set last candidate to a generated node! { lastCandidate = GetDeepLastChild(lastCandidate); if (mGenIter) { mLastIter = mGenIter; mLastIterType = mIterType; } } // confirm that this first possible contained node // is indeed contained. Else we have a range that // does not fully contain any node. if (!mLastIter && NS_FAILED(nsRange::CompareNodeToRange(lastCandidate, aRange, &nodeBefore, &nodeAfter))) return NS_ERROR_FAILURE; if (nodeBefore || nodeAfter) { MakeEmpty(); return NS_OK; } // cool, we have the last 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_SUCCEEDED(GetTopAncestorInRange(lastCandidate, address_of(mLast)))) { mLastIter = 0;//ancestor has one no mGenIter = 0; } else if (!mLastIter) //something bad happened and its not generated content iterators fault return NS_ERROR_FAILURE; else mLast = lastCandidate;//setting last candidate to parent of generated content this is ok mCurNode = mFirst; mGenIter = mFirstIter; mIterType = mFirstIterType ; return NS_OK; } /**************************************************************** * nsGeneratedSubtreeIterator overrides of ContentIterator routines ****************************************************************/ void nsGeneratedSubtreeIterator::Next() { if (mIsDone) return; nsCOMPtr curnode; nsCOMPtr nextNode; if (mGenIter) { if (mGenIter->IsDone()) { mGenIter = 0; if (mIterType == nsIPresShell::After) { nextNode = GetNextSibling(mCurNode); if (!nextNode) { mIsDone = PR_TRUE; return; } } else { nextNode = mCurNode->GetChildAt(0); } } else { mGenIter->Next(); return; } } else { if (mCurNode == mLast) { mIsDone = PR_TRUE; return; } nextNode = GetNextSibling(mCurNode); if (!nextNode) { mIsDone = PR_TRUE; return; } } if (!mGenIter) nextNode = GetDeepFirstChild(nextNode); if (NS_SUCCEEDED(GetTopAncestorInRange(nextNode, address_of(mCurNode)))) { mGenIter = 0; } else if (!mGenIter) //something bad happened and its not generated content iterators fault return; else mCurNode = nextNode;//setting last candidate to parent of generated content this is ok } void nsGeneratedSubtreeIterator::Prev() { //notimplemented NS_ERROR("Not implemented!"); } nsresult nsGeneratedSubtreeIterator::PositionAt(nsIContent* aCurNode) { NS_ERROR("Not implemented!"); return NS_ERROR_NOT_IMPLEMENTED; } /**************************************************************** * nsGeneratedSubtreeIterator helper routines ****************************************************************/ nsresult nsGeneratedSubtreeIterator::GetTopAncestorInRange( nsCOMPtr aNode, nsCOMPtr *outAnestor) { if (!aNode) return NS_ERROR_NULL_POINTER; if (!outAnestor) 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; while (aNode) { parent = aNode->GetParent(); if (!parent) return NS_ERROR_FAILURE; if (NS_FAILED(nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter))) return NS_ERROR_FAILURE; if (nodeBefore || nodeAfter) { *outAnestor = aNode; return NS_OK; } aNode = parent; } return NS_ERROR_FAILURE; }