Don't try to use ranges to represent chunks of the flattened tree, becauseranges can't have endpoints that are anonymous wrt the other endpoint. Bug374873, r+sr=rbs

This commit is contained in:
bzbarsky@mit.edu 2007-04-18 13:05:42 -07:00
parent ff22fdf79c
commit f792615997
2 changed files with 88 additions and 66 deletions

View File

@ -106,12 +106,9 @@ class nsFindContentIterator : public nsIContentIterator
{
public:
nsFindContentIterator(PRBool aFindBackward)
: mOuterIterator(nsnull)
, mInnerIterator(nsnull)
, mRange(nsnull)
, mStartOuterNode(nsnull)
, mEndOuterNode(nsnull)
, mFindBackward(aFindBackward)
: mStartOffset(0),
mEndOffset(0),
mFindBackward(aFindBackward)
{
}
@ -128,7 +125,14 @@ public:
NS_NOTREACHED("internal error");
return NS_ERROR_NOT_IMPLEMENTED;
}
virtual nsresult Init(nsIDOMRange* aRange);
virtual nsresult Init(nsIDOMRange* aRange)
{
NS_NOTREACHED("internal error");
return NS_ERROR_NOT_IMPLEMENTED;
}
// Not a range because one of the endpoints may be anonymous.
nsresult Init(nsIDOMNode* aStartNode, PRInt32 aStartOffset,
nsIDOMNode* aEndNode, PRInt32 aEndOffset);
virtual void First();
virtual void Last();
virtual void Next();
@ -140,7 +144,13 @@ public:
private:
nsCOMPtr<nsIContentIterator> mOuterIterator;
nsCOMPtr<nsIContentIterator> mInnerIterator;
nsCOMPtr<nsIDOMRange> mRange;
// Can't use a range here, since we want to represent part of the
// flattened tree, including native anonymous content.
nsCOMPtr<nsIDOMNode> mStartNode;
PRInt32 mStartOffset;
nsCOMPtr<nsIDOMNode> mEndNode;
PRInt32 mEndOffset;
nsCOMPtr<nsIDOMNode> mStartOuterNode;
nsCOMPtr<nsIDOMNode> mEndOuterNode;
PRBool mFindBackward;
@ -153,7 +163,8 @@ private:
NS_IMPL_ISUPPORTS1(nsFindContentIterator, nsIContentIterator)
nsresult
nsFindContentIterator::Init(nsIDOMRange* aRange)
nsFindContentIterator::Init(nsIDOMNode* aStartNode, PRInt32 aStartOffset,
nsIDOMNode* aEndNode, PRInt32 aEndOffset)
{
if (!mOuterIterator) {
if (mFindBackward) {
@ -171,8 +182,13 @@ nsFindContentIterator::Init(nsIDOMRange* aRange)
NS_ENSURE_ARG_POINTER(mOuterIterator);
}
// mRange is the search range that we will examine
return aRange->CloneRange(getter_AddRefs(mRange));
// Set up the search "range" that we will examine
mStartNode = aStartNode;
mStartOffset = aStartOffset;
mEndNode = aEndNode;
mEndOffset = aEndOffset;
return NS_OK;
}
void
@ -263,31 +279,37 @@ nsFindContentIterator::Reset()
// initialized with a selection inside a <textarea> or a text <input>.
// see if the start node is an anonymous text node inside a text control
nsCOMPtr<nsIDOMNode> startNode;
mRange->GetStartContainer(getter_AddRefs(startNode));
nsCOMPtr<nsIContent> startContent(do_QueryInterface(startNode));
nsCOMPtr<nsIContent> startContent(do_QueryInterface(mStartNode));
for ( ; startContent; startContent = startContent->GetParent()) {
if (!startContent->IsNativeAnonymous()) {
if (!startContent->IsNativeAnonymous() &&
(!startContent->GetBindingParent() ||
!startContent->GetBindingParent()->IsNativeAnonymous())) {
mStartOuterNode = do_QueryInterface(startContent);
break;
}
}
// see if the end node is an anonymous text node inside a text control
nsCOMPtr<nsIDOMNode> endNode;
mRange->GetEndContainer(getter_AddRefs(endNode));
nsCOMPtr<nsIContent> endContent(do_QueryInterface(endNode));
nsCOMPtr<nsIContent> endContent(do_QueryInterface(mEndNode));
for ( ; endContent; endContent = endContent->GetParent()) {
if (!endContent->IsNativeAnonymous()) {
if (!endContent->IsNativeAnonymous() &&
(!endContent->GetBindingParent() ||
!endContent->GetBindingParent()->IsNativeAnonymous())) {
mEndOuterNode = do_QueryInterface(endContent);
break;
}
}
mOuterIterator->Init(mRange);
// Note: OK to just set up the outer iterator here; if our range has an
// anonymous endpoint we'll end up setting up an inner iterator, and
// reset the outer one in the process.
nsCOMPtr<nsIDOMRange> range (do_CreateInstance(kRangeCID));
range->SetStart(mStartNode, mStartOffset);
range->SetEnd(mEndNode, mEndOffset);
mOuterIterator->Init(range);
if (!mFindBackward) {
if (mStartOuterNode != startNode) {
if (mStartOuterNode != mStartNode) {
// the start node was an anonymous text node
SetupInnerIterator(startContent);
if (mInnerIterator)
@ -296,7 +318,7 @@ nsFindContentIterator::Reset()
mOuterIterator->First();
}
else {
if (mEndOuterNode != endNode) {
if (mEndOuterNode != mEndNode) {
// the end node was an anonymous text node
SetupInnerIterator(endContent);
if (mInnerIterator)
@ -378,53 +400,57 @@ nsFindContentIterator::SetupInnerIterator(nsIContent* aContent)
editor->GetRootElement(getter_AddRefs(rootElement));
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement));
nsCOMPtr<nsIDOMRange> innerRange(do_CreateInstance(kRangeCID));
nsCOMPtr<nsIDOMRange> outerRange(do_CreateInstance(kRangeCID));
if (!innerRange || !outerRange) {
return;
}
// now create the inner-iterator
mInnerIterator = do_CreateInstance(kCPreContentIteratorCID);
if (mInnerIterator) {
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(rootContent));
nsCOMPtr<nsIDOMRange> range(do_CreateInstance(kRangeCID));
range->SelectNodeContents(node);
{
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(rootContent));
innerRange->SelectNodeContents(node);
}
// fix up the inner bounds, we may have to only lookup a portion
// of the text control if the current node is a boundary point
PRInt32 offset;
nsCOMPtr<nsIDOMNode> outerNode(do_QueryInterface(aContent));
if (outerNode == mStartOuterNode) {
mRange->GetStartOffset(&offset);
mRange->GetStartContainer(getter_AddRefs(node));
range->SetStart(node, offset);
innerRange->SetStart(mStartNode, mStartOffset);
}
if (outerNode == mEndOuterNode) {
mRange->GetEndOffset(&offset);
mRange->GetEndContainer(getter_AddRefs(node));
range->SetEnd(node, offset);
innerRange->SetEnd(mEndNode, mEndOffset);
}
// Note: we just init here. We do First() or Last() later.
mInnerIterator->Init(range);
mInnerIterator->Init(innerRange);
// make sure to place the outer-iterator outside
// the text control so that we don't go there again.
nsresult res;
mRange->CloneRange(getter_AddRefs(range));
if (!mFindBackward) { // find forward
// cut the outer-iterator after the current node
res = range->SetStartAfter(outerNode);
res = outerRange->SetEnd(mEndNode, mEndOffset);
res |= outerRange->SetStartAfter(outerNode);
}
else { // find backward
// cut the outer-iterator before the current node
res = range->SetEndBefore(outerNode);
res = outerRange->SetStart(mStartNode, mStartOffset);
res |= outerRange->SetEndBefore(outerNode);
}
if (NS_FAILED(res)) {
// we are done with the outer-iterator, the
// inner-iterator will traverse what we want
range->Collapse(PR_TRUE);
outerRange->Collapse(PR_TRUE);
}
// Note: we just re-init here, using the segment of mRange that is
// yet to be visited. Thus when we later do mOuterIterator->First()
// [or mOuterIterator->Last()], we will effectively be on the next
// node [or the previous node] _with respect to_ mRange.
mOuterIterator->Init(range);
// Note: we just re-init here, using the segment of our search range that
// is yet to be visited. Thus when we later do mOuterIterator->First() [or
// mOuterIterator->Last()], we will effectively be on the next node [or
// the previous node] _with respect to_ the search range.
mOuterIterator->Init(outerRange);
}
}
@ -532,23 +558,24 @@ static void DumpRange(nsIDOMRange* aRange)
#endif
nsresult
nsFind::InitIterator(nsIDOMRange* aSearchRange)
nsFind::InitIterator(nsIDOMNode* aStartNode, PRInt32 aStartOffset,
nsIDOMNode* aEndNode, PRInt32 aEndOffset)
{
nsresult rv;
if (!mIterator)
{
rv = NS_NewFindContentIterator(mFindBackward, getter_AddRefs(mIterator));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG_POINTER(mIterator);
mIterator = new nsFindContentIterator(mFindBackward);
NS_ENSURE_TRUE(mIterator, NS_ERROR_OUT_OF_MEMORY);
}
NS_ENSURE_ARG_POINTER(aSearchRange);
NS_ENSURE_ARG_POINTER(aStartNode);
NS_ENSURE_ARG_POINTER(aEndNode);
#ifdef DEBUG_FIND
printf("InitIterator search range:\n"); DumpRange(aSearchRange);
#endif
rv = mIterator->Init(aSearchRange);
nsresult rv =
mIterator->Init(aStartNode, aStartOffset, aEndNode, aEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (mFindBackward) {
mIterator->Last();
@ -636,18 +663,17 @@ nsFind::NextNode(nsIDOMRange* aSearchRange,
if (!mIterator || aContinueOk)
{
// If we are continuing, that means we have a match in progress.
// In that case, we want to continue from the end point
// (where we are now) to the beginning/end of the search range.
nsCOMPtr<nsIDOMRange> newRange (do_CreateInstance(kRangeCID));
// If we are continuing, that means we have a match in progress.
// In that case, we want to continue from the end point
// (where we are now) to the beginning/end of the search range.
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
if (aContinueOk)
{
#ifdef DEBUG_FIND
printf("Match in progress: continuing past endpoint\n");
#endif
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
if (mFindBackward) {
aSearchRange->GetStartContainer(getter_AddRefs(startNode));
aSearchRange->GetStartOffset(&startOffset);
@ -659,14 +685,9 @@ nsFind::NextNode(nsIDOMRange* aSearchRange,
aSearchRange->GetEndContainer(getter_AddRefs(endNode));
aSearchRange->GetEndOffset(&endOffset);
}
newRange->SetStart(startNode, startOffset);
newRange->SetEnd(endNode, endOffset);
}
else // Normal, not continuing
{
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
if (mFindBackward) {
aSearchRange->GetStartContainer(getter_AddRefs(startNode));
aSearchRange->GetStartOffset(&startOffset);
@ -685,11 +706,9 @@ nsFind::NextNode(nsIDOMRange* aSearchRange,
aEndPoint->GetEndContainer(getter_AddRefs(endNode));
aEndPoint->GetEndOffset(&endOffset);
}
newRange->SetStart(startNode, startOffset);
newRange->SetEnd(endNode, endOffset);
}
rv = InitIterator(newRange);
rv = InitIterator(startNode, startOffset, endNode, endOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (!aStartPoint)
aStartPoint = aSearchRange;

View File

@ -56,6 +56,8 @@ class nsIAtom;
#define NS_FIND_CID \
{0x471f4944, 0x1dd2, 0x11b2, {0x87, 0xac, 0x90, 0xbe, 0x0a, 0x51, 0xd6, 0x09}}
class nsFindContentIterator;
class nsFind : public nsIFind
{
public:
@ -109,8 +111,9 @@ protected:
void ResetAll();
// The iterator we use to move through the document:
nsresult InitIterator(nsIDOMRange* aSearchRange);
nsCOMPtr<nsIContentIterator> mIterator;
nsresult InitIterator(nsIDOMNode* aStartNode, PRInt32 aStartOffset,
nsIDOMNode* aEndNode, PRInt32 aEndOffset);
nsCOMPtr<nsFindContentIterator> mIterator;
};
#endif // nsFind_h__