gecko-dev/content/base/src/nsContentIterator.cpp

860 lines
20 KiB
C++
Raw Normal View History

1998-12-14 23:16:31 +00:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* nsContentIterator.cpp: Implementation of the nsContentIterator object.
* This ite
1998-12-14 23:16:31 +00:00
*/
#include "nsISupports.h"
1999-02-12 08:20:40 +00:00
//#include "nsIEnumerator.h"
#include "nsIContentIterator.h"
1999-02-16 15:48:13 +00:00
#include "nsRange.h"
1998-12-14 23:16:31 +00:00
#include "nsIContent.h"
#include "nsIDOMText.h"
#include "nsISupportsArray.h"
1998-12-14 23:16:31 +00:00
#include "nsCOMPtr.h"
1998-12-14 23:16:31 +00:00
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
/*
* A simple iterator class for traversing the content in "close tag" order
*/
1999-02-12 08:20:40 +00:00
class nsContentIterator : public nsIContentIterator //, public nsIEnumerator
1998-12-14 23:16:31 +00:00
{
public:
NS_DECL_ISUPPORTS
nsContentIterator();
virtual ~nsContentIterator();
// nsIContentIterator interface methods ------------------------------
NS_IMETHOD Init(nsIContent* aRoot);
NS_IMETHOD Init(nsIDOMRange* aRange);
NS_IMETHOD First();
NS_IMETHOD Last();
NS_IMETHOD Next();
NS_IMETHOD Prev();
NS_IMETHOD CurrentNode(nsIContent **aNode);
NS_IMETHOD IsDone();
// nsIEnumertor interface methods ------------------------------
1999-02-12 08:20:40 +00:00
//NS_IMETHOD CurrentItem(nsISupports **aItem);
protected:
static nsCOMPtr<nsIContent> GetDeepFirstChild(nsCOMPtr<nsIContent> aRoot);
static nsCOMPtr<nsIContent> GetDeepLastChild(nsCOMPtr<nsIContent> aRoot);
nsresult GetNextSibling(nsCOMPtr<nsIContent> aNode, nsCOMPtr<nsIContent> *aSibling);
nsresult GetPrevSibling(nsCOMPtr<nsIContent> aNode, nsCOMPtr<nsIContent> *aSibling);
nsresult NextNode(nsCOMPtr<nsIContent> *ioNextNode);
nsresult PrevNode(nsCOMPtr<nsIContent> *ioPrevNode);
void MakeEmpty();
nsCOMPtr<nsIContent> mCurNode;
nsCOMPtr<nsIContent> mFirst;
nsCOMPtr<nsIContent> mLast;
nsCOMPtr<nsIContent> mCommonParent;
PRBool mIsDone;
private:
// no copy's or assigns FIX ME
nsContentIterator(const nsContentIterator&);
nsContentIterator& operator=(const nsContentIterator&);
};
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
/******************************************************
* repository cruft
******************************************************/
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult)
{
nsContentIterator * iter = new nsContentIterator();
1999-03-03 19:48:57 +00:00
return iter->QueryInterface(nsIContentIterator::GetIID(), (void**) aInstancePtrResult);
1998-12-14 23:16:31 +00:00
}
/******************************************************
* XPCOM cruft
******************************************************/
NS_IMPL_ADDREF(nsContentIterator)
NS_IMPL_RELEASE(nsContentIterator)
nsresult nsContentIterator::QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)
1998-12-14 23:16:31 +00:00
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
if (nsnull == aInstancePtrResult)
{
return NS_ERROR_NULL_POINTER;
1998-12-14 23:16:31 +00:00
}
if (aIID.Equals(kISupportsIID))
{
*aInstancePtrResult = (void*)(nsISupports*)(nsIContentIterator*)this;
NS_ADDREF_THIS();
return NS_OK;
}
1999-03-03 19:48:57 +00:00
/* if (aIID.Equals(nsIEnumerator::GetIID()))
{
*aInstancePtrResult = (void*)(nsIEnumerator*)this;
NS_ADDREF_THIS();
return NS_OK;
1999-02-12 08:20:40 +00:00
} */
1999-03-03 19:48:57 +00:00
if (aIID.Equals(nsIContentIterator::GetIID()))
{
*aInstancePtrResult = (void*)(nsIContentIterator*)this;
NS_ADDREF_THIS();
return NS_OK;
}
return !NS_OK;
}
/******************************************************
* constructor/destructor
******************************************************/
nsContentIterator::nsContentIterator() :
// don't need to explicitly initialize |nsCOMPtr|s, they will automatically be NULL
mIsDone(PR_FALSE)
{
NS_INIT_REFCNT();
}
nsContentIterator::~nsContentIterator()
{
}
/******************************************************
* Init routines
******************************************************/
nsresult nsContentIterator::Init(nsIContent* aRoot)
{
if (!aRoot)
return NS_ERROR_NULL_POINTER;
1998-12-14 23:16:31 +00:00
nsCOMPtr<nsIContent> root( do_QueryInterface(aRoot) );
mFirst = GetDeepFirstChild(root);
mLast = root;
mCommonParent = root;
1998-12-14 23:16:31 +00:00
mCurNode = mFirst;
return NS_OK;
1998-12-14 23:16:31 +00:00
}
nsresult nsContentIterator::Init(nsIDOMRange* aRange)
1998-12-14 23:16:31 +00:00
{
if (!aRange)
return NS_ERROR_NULL_POINTER;
1998-12-14 23:16:31 +00:00
nsCOMPtr<nsIContent> cN;
nsCOMPtr<nsIDOMNode> dN;
// get common content parent
if (!NS_SUCCEEDED(aRange->GetCommonParent(getter_AddRefs(dN))) || !dN)
return NS_ERROR_FAILURE;
mCommonParent = do_QueryInterface(dN);
// get the start node and offset, convert to nsIContent
aRange->GetStartParent(getter_AddRefs(dN));
if (!dN)
return NS_ERROR_ILLEGAL_VALUE;
cN = do_QueryInterface(dN);
if (!cN)
return NS_ERROR_FAILURE;
1998-12-14 23:16:31 +00:00
PRInt32 indx;
aRange->GetStartOffset(&indx);
// find first node in range
nsCOMPtr<nsIContent> cChild;
cN->ChildAt(0,*getter_AddRefs(cChild));
1998-12-14 23:16:31 +00:00
if (!cChild) // no children, must be a text node
{
mFirst = cN;
1998-12-14 23:16:31 +00:00
}
else
{
cN->ChildAt(indx,*getter_AddRefs(cChild));
1998-12-14 23:16:31 +00:00
if (!cChild) // offset after last child, parent is first node
{
mFirst = cN;
1998-12-14 23:16:31 +00:00
}
else
{
mFirst = GetDeepFirstChild(cChild);
1998-12-14 23:16:31 +00:00
}
1999-02-16 15:48:13 +00:00
// 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
1998-12-14 23:16:31 +00:00
1999-02-16 15:48:13 +00:00
if (!IsNodeIntersectsRange(mFirst, aRange))
{
MakeEmpty();
1999-02-16 15:48:13 +00:00
return NS_OK;
}
}
aRange->GetEndParent(getter_AddRefs(dN));
if (!dN)
return NS_ERROR_ILLEGAL_VALUE;
cN = do_QueryInterface(dN);
if (!cN)
return NS_ERROR_FAILURE;
1998-12-14 23:16:31 +00:00
aRange->GetEndOffset(&indx);
// find last node in range
cN->ChildAt(0,*getter_AddRefs(cChild));
1998-12-14 23:16:31 +00:00
if (!cChild) // no children, must be a text node
{
mLast = cN;
1998-12-14 23:16:31 +00:00
}
else if (indx == 0) // before first child, parent is last node
{
mLast = cN;
1998-12-14 23:16:31 +00:00
}
else
{
cN->ChildAt(--indx,*getter_AddRefs(cChild));
1998-12-14 23:16:31 +00:00
if (!cChild) // offset after last child, last child is last node
{
cN->ChildCount(indx);
cN->ChildAt(--indx,*getter_AddRefs(cChild));
1998-12-14 23:16:31 +00:00
if (!cChild)
{
NS_NOTREACHED("nsContentIterator::nsContentIterator");
return NS_ERROR_FAILURE;
1998-12-14 23:16:31 +00:00
}
}
mLast = cChild;
1998-12-14 23:16:31 +00:00
}
mCurNode = mFirst;
return NS_OK;
1998-12-14 23:16:31 +00:00
}
/******************************************************
* Helper routines
******************************************************/
void nsContentIterator::MakeEmpty()
{
nsCOMPtr<nsIContent> noNode;
mCurNode = noNode;
mFirst = noNode;
mLast = noNode;
mCommonParent = noNode;
mIsDone = PR_TRUE;
}
nsCOMPtr<nsIContent> nsContentIterator::GetDeepFirstChild(nsCOMPtr<nsIContent> aRoot)
1998-12-14 23:16:31 +00:00
{
1999-03-09 19:21:30 +00:00
nsCOMPtr<nsIContent> deepFirstChild;
if (aRoot)
{
nsCOMPtr<nsIContent> cN = aRoot;
nsCOMPtr<nsIContent> cChild;
cN->ChildAt(0,*getter_AddRefs(cChild));
1999-03-09 19:21:30 +00:00
while ( cChild )
{
cN = cChild;
cN->ChildAt(0,*getter_AddRefs(cChild));
}
deepFirstChild = cN;
}
1999-03-09 19:21:30 +00:00
return deepFirstChild;
1998-12-14 23:16:31 +00:00
}
nsCOMPtr<nsIContent> nsContentIterator::GetDeepLastChild(nsCOMPtr<nsIContent> aRoot)
{
1999-03-09 19:21:30 +00:00
nsCOMPtr<nsIContent> deepFirstChild;
1999-03-09 19:21:30 +00:00
if (aRoot)
{
nsCOMPtr<nsIContent> cN = aRoot;
nsCOMPtr<nsIContent> cChild;
PRInt32 numChildren;
cN->ChildCount(numChildren);
1999-03-09 19:21:30 +00:00
while ( numChildren )
{
1999-03-09 19:21:30 +00:00
cN->ChildAt(--numChildren,*getter_AddRefs(cChild));
if (cChild)
{
cChild->ChildCount(numChildren);
cN = cChild;
}
else
{
break;
}
}
1999-03-09 19:21:30 +00:00
deepFirstChild = cN;
}
1999-03-09 19:21:30 +00:00
return deepFirstChild;
}
// Get the next sibling, or parents next sibling, or grandpa's next sibling...
nsresult nsContentIterator::GetNextSibling(nsCOMPtr<nsIContent> aNode, nsCOMPtr<nsIContent> *aSibling)
{
if (!aNode)
return NS_ERROR_NULL_POINTER;
if (!aSibling)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIContent> sib;
nsCOMPtr<nsIContent> parent;
PRInt32 indx;
if (!NS_SUCCEEDED(aNode->GetParent(*getter_AddRefs(parent))))
return NS_ERROR_FAILURE;
if (!NS_SUCCEEDED(parent->IndexOf(aNode, indx)))
return NS_ERROR_FAILURE;
if (NS_SUCCEEDED(parent->ChildAt(++indx, *getter_AddRefs(sib))) && sib)
{
*aSibling = sib;
}
else if (parent != mCommonParent)
{
return GetNextSibling(parent, aSibling);
}
else
{
*aSibling = nsCOMPtr<nsIContent>();
}
return NS_OK;
}
// Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
nsresult nsContentIterator::GetPrevSibling(nsCOMPtr<nsIContent> aNode, nsCOMPtr<nsIContent> *aSibling)
{
if (!aNode)
return NS_ERROR_NULL_POINTER;
if (!aSibling)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIContent> sib;
nsCOMPtr<nsIContent> parent;
PRInt32 indx;
if (!NS_SUCCEEDED(aNode->GetParent(*getter_AddRefs(parent))))
return NS_ERROR_FAILURE;
if (!NS_SUCCEEDED(parent->IndexOf(aNode, indx)))
return NS_ERROR_FAILURE;
if (indx && NS_SUCCEEDED(parent->ChildAt(--indx, *getter_AddRefs(sib))) && sib)
{
*aSibling = sib;
}
else if (parent != mCommonParent)
{
return GetPrevSibling(parent, aSibling);
}
else
{
*aSibling = nsCOMPtr<nsIContent>();
}
return NS_OK;
}
1999-02-16 15:48:13 +00:00
nsresult nsContentIterator::NextNode(nsCOMPtr<nsIContent> *ioNextNode)
{
if (!ioNextNode)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIContent> cN = *ioNextNode;
nsCOMPtr<nsIContent> cSibling;
nsCOMPtr<nsIContent> parent;
PRInt32 indx;
// get next sibling if there is one
if (!NS_SUCCEEDED(cN->GetParent(*getter_AddRefs(parent))))
return NS_ERROR_FAILURE;
if (!NS_SUCCEEDED(parent->IndexOf(cN, indx)))
return NS_ERROR_FAILURE;
if (NS_SUCCEEDED(parent->ChildAt(++indx,*getter_AddRefs(cSibling))) && cSibling)
1999-02-16 15:48:13 +00:00
{
// next node is siblings "deep left" child
*ioNextNode = GetDeepFirstChild(cSibling);
1999-02-16 15:48:13 +00:00
return NS_OK;
}
// else it's the parent
*ioNextNode = parent;
1999-02-16 15:48:13 +00:00
return NS_OK;
}
nsresult nsContentIterator::PrevNode(nsCOMPtr<nsIContent> *ioNextNode)
{
if (!ioNextNode)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIContent> cN = *ioNextNode;
nsCOMPtr<nsIContent> cLastChild;
1999-02-16 15:48:13 +00:00
PRInt32 numChildren;
cN->ChildCount(numChildren);
// if it has children then prev node is last child
1999-02-16 15:48:13 +00:00
if (numChildren)
{
cN->ChildAt(--numChildren,*getter_AddRefs(cLastChild));
if (!cLastChild)
return NS_ERROR_FAILURE;
*ioNextNode = cLastChild;
1999-02-16 15:48:13 +00:00
return NS_OK;
}
// else prev sibling is previous
return GetPrevSibling(cN, ioNextNode);
1999-02-16 15:48:13 +00:00
}
/******************************************************
* ContentIterator routines
******************************************************/
1998-12-14 23:16:31 +00:00
nsresult nsContentIterator::First()
{
if (!mFirst)
return NS_ERROR_FAILURE;
mIsDone = PR_FALSE;
if (mFirst == mCurNode)
return NS_OK;
1998-12-14 23:16:31 +00:00
mCurNode = mFirst;
return NS_OK;
}
nsresult nsContentIterator::Last()
{
if (!mLast)
return NS_ERROR_FAILURE;
mIsDone = PR_FALSE;
if (mLast == mCurNode)
return NS_OK;
1998-12-14 23:16:31 +00:00
mCurNode = mLast;
return NS_OK;
}
nsresult nsContentIterator::Next()
{
if (mIsDone)
return NS_ERROR_FAILURE;
if (!mCurNode)
return NS_OK;
1999-01-28 23:55:53 +00:00
if (mCurNode == mLast)
{
mIsDone = PR_TRUE;
1999-01-28 23:55:53 +00:00
return NS_ERROR_FAILURE;
}
1998-12-14 23:16:31 +00:00
1999-02-16 15:48:13 +00:00
return NextNode(&mCurNode);
1998-12-14 23:16:31 +00:00
}
nsresult nsContentIterator::Prev()
{
if (mIsDone)
return NS_ERROR_FAILURE;
if (!mCurNode)
return NS_OK;
if (mCurNode == mFirst)
{
mIsDone = PR_TRUE;
return NS_ERROR_FAILURE;
}
return PrevNode(&mCurNode);
1998-12-14 23:16:31 +00:00
}
nsresult nsContentIterator::IsDone()
{
if (mIsDone)
return NS_OK;
else
return NS_COMFALSE;
}
1998-12-14 23:16:31 +00:00
nsresult nsContentIterator::CurrentNode(nsIContent **aNode)
{
if (!mCurNode)
return NS_ERROR_FAILURE;
if (mIsDone)
return NS_ERROR_FAILURE;
1999-03-03 19:48:57 +00:00
return mCurNode->QueryInterface(nsIContent::GetIID(), (void**) aNode);
1998-12-14 23:16:31 +00:00
}
/*====================================================================================*/
/*====================================================================================*/
/******************************************************
* nsContentSubtreeIterator
******************************************************/
/*
* A simple iterator class for traversing the content in "top subtree" order
*/
class nsContentSubtreeIterator : public nsContentIterator
{
public:
nsContentSubtreeIterator() {};
virtual ~nsContentSubtreeIterator() {};
// nsContentIterator overrides ------------------------------
NS_IMETHOD Init(nsIContent* aRoot);
NS_IMETHOD Init(nsIDOMRange* aRange);
NS_IMETHOD Next();
NS_IMETHOD Prev();
protected:
nsresult GetTopAncestorInRange( nsCOMPtr<nsIContent> aNode,
nsCOMPtr<nsIContent> *outAnestor);
// no copy's or assigns FIX ME
nsContentSubtreeIterator(const nsContentSubtreeIterator&);
nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
nsCOMPtr<nsIDOMRange> mRange;
};
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
/******************************************************
* repository cruft
******************************************************/
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult)
{
nsContentIterator * iter = new nsContentSubtreeIterator();
1999-03-03 19:48:57 +00:00
return iter->QueryInterface(nsIContentIterator::GetIID(), (void**) aInstancePtrResult);
}
/******************************************************
* Init routines
******************************************************/
nsresult nsContentSubtreeIterator::Init(nsIContent* aRoot)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
1998-12-14 23:16:31 +00:00
{
1999-02-16 15:48:13 +00:00
if (!aRange)
return NS_ERROR_NULL_POINTER;
mRange = do_QueryInterface(aRange);
1999-02-16 15:48:13 +00:00
// get the start node and offset, convert to nsIContent
nsCOMPtr<nsIDOMNode> commonParent;
nsCOMPtr<nsIDOMNode> startParent;
nsCOMPtr<nsIDOMNode> endParent;
nsCOMPtr<nsIContent> cStartP;
nsCOMPtr<nsIContent> cEndP;
1999-02-16 15:48:13 +00:00
nsCOMPtr<nsIContent> cN;
nsCOMPtr<nsIContent> firstCandidate;
nsCOMPtr<nsIContent> lastCandidate;
// get common content parent
if (!NS_SUCCEEDED(aRange->GetCommonParent(getter_AddRefs(commonParent))) || !commonParent)
return NS_ERROR_FAILURE;
mCommonParent = do_QueryInterface(commonParent);
// get start content parent
if (!NS_SUCCEEDED(aRange->GetStartParent(getter_AddRefs(startParent))) || !startParent)
return NS_ERROR_FAILURE;
cStartP = do_QueryInterface(startParent);
// get end content parent
if (!NS_SUCCEEDED(aRange->GetEndParent(getter_AddRefs(endParent))) || !endParent)
1999-02-16 15:48:13 +00:00
return NS_ERROR_FAILURE;
cEndP = do_QueryInterface(endParent);
1999-02-16 15:48:13 +00:00
// find first node in range
1999-02-16 15:48:13 +00:00
PRInt32 indx;
aRange->GetStartOffset(&indx);
nsCOMPtr<nsIContent> cChild;
PRInt32 numChildren;
cStartP->ChildCount(numChildren);
1999-02-16 15:48:13 +00:00
if (!numChildren) // no children, must be a text node
1999-02-16 15:48:13 +00:00
{
cN = cStartP;
1999-02-16 15:48:13 +00:00
}
else
{
cStartP->ChildAt(indx,*getter_AddRefs(cChild));
if (!cChild) // offset after last child
1999-02-16 15:48:13 +00:00
{
cN = cStartP;
1999-02-16 15:48:13 +00:00
}
else
{
firstCandidate = cChild;
1999-02-16 15:48:13 +00:00
}
}
if (!firstCandidate)
1999-02-16 15:48:13 +00:00
{
// then firstCandidate is next node after cN
if (!NS_SUCCEEDED(GetNextSibling(cN, &firstCandidate)))
{
MakeEmpty();
return NS_OK;
}
1999-02-16 15:48:13 +00:00
}
firstCandidate = GetDeepFirstChild(firstCandidate);
// confirm that this first possible contained node
// is indeed contained. Else we have a range that
// does not fully contain any node.
PRBool nodeBefore, nodeAfter;
if (!NS_SUCCEEDED(CompareNodeToRange(firstCandidate, aRange, &nodeBefore, &nodeAfter)))
return NS_ERROR_FAILURE;
if (nodeBefore || nodeAfter)
1999-02-16 15:48:13 +00:00
{
MakeEmpty();
1999-02-16 15:48:13 +00:00
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, &mFirst)))
return NS_ERROR_FAILURE;
1999-02-16 15:48:13 +00:00
// now to find the last node
aRange->GetEndOffset(&indx);
if (!indx)
1999-02-16 15:48:13 +00:00
{
cN = cEndP;
1999-02-16 15:48:13 +00:00
}
else
{
cEndP->ChildCount(numChildren);
if (!numChildren) // no children, must be a text node
1999-02-16 15:48:13 +00:00
{
cN = cEndP;
}
else
{
cEndP->ChildAt(--indx,*getter_AddRefs(cChild));
if (!cChild) // shouldn't happen
1999-02-16 15:48:13 +00:00
{
NS_ASSERTION(0,"tree traversal trouble in nsContentSubtreeIterator::Init");
return NS_ERROR_FAILURE;
}
else
{
lastCandidate = cChild;
1999-02-16 15:48:13 +00:00
}
}
}
if (!lastCandidate)
1999-02-16 15:48:13 +00:00
{
// then lastCandidate is prev node before cN
if (!NS_SUCCEEDED(GetPrevSibling(cN, &lastCandidate)))
{
MakeEmpty();
return NS_OK;
}
}
lastCandidate = GetDeepLastChild(lastCandidate);
// confirm that this first possible contained node
// is indeed contained. Else we have a range that
// does not fully contain any node.
if (!NS_SUCCEEDED(CompareNodeToRange(lastCandidate, aRange, &nodeBefore, &nodeAfter)))
return NS_ERROR_FAILURE;
if (nodeBefore || nodeAfter)
{
MakeEmpty();
return NS_OK;
1999-02-16 15:48:13 +00:00
}
// 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, &mLast)))
return NS_ERROR_FAILURE;
1999-02-16 15:48:13 +00:00
mCurNode = mFirst;
1999-02-16 15:48:13 +00:00
return NS_OK;
1998-12-14 23:16:31 +00:00
}
/****************************************************************
* nsContentSubtreeIterator overrides of ContentIterator routines
****************************************************************/
nsresult nsContentSubtreeIterator::Next()
{
if (mIsDone)
return NS_ERROR_FAILURE;
if (!mCurNode)
return NS_OK;
if (mCurNode == mLast)
{
mIsDone = PR_TRUE;
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> nextNode;
if (!NS_SUCCEEDED(GetNextSibling(mCurNode, &nextNode)))
return NS_ERROR_FAILURE;
nextNode = GetDeepFirstChild(nextNode);
return GetTopAncestorInRange(nextNode, &mCurNode);
}
nsresult nsContentSubtreeIterator::Prev()
{
if (mIsDone)
return NS_ERROR_FAILURE;
if (!mCurNode)
return NS_OK;
if (mCurNode == mFirst)
{
mIsDone = PR_TRUE;
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> prevNode;
prevNode = GetDeepFirstChild(mCurNode);
if (!NS_SUCCEEDED(PrevNode(&prevNode)))
return NS_ERROR_FAILURE;
prevNode = GetDeepLastChild(prevNode);
return GetTopAncestorInRange(prevNode, &mCurNode);
}
/****************************************************************
* nsContentSubtreeIterator helper routines
****************************************************************/
nsresult nsContentSubtreeIterator::GetTopAncestorInRange(
nsCOMPtr<nsIContent> aNode,
nsCOMPtr<nsIContent> *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_SUCCEEDED(CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter)))
return NS_ERROR_FAILURE;
if (nodeBefore || nodeAfter)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> parent;
while (aNode)
{
if (!NS_SUCCEEDED(aNode->GetParent(*getter_AddRefs(parent))))
return NS_ERROR_FAILURE;
if (!NS_SUCCEEDED(CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter)))
return NS_ERROR_FAILURE;
if (nodeBefore || nodeAfter)
{
*outAnestor = aNode;
return NS_OK;
}
aNode = parent;
}
return NS_ERROR_FAILURE;
}