1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
23
* Pierre Phaneuf <pp@ludusdesign.com>
26
* Alternatively, the contents of this file may be used under the terms of
27
* either the GNU General Public License Version 2 or later (the "GPL"), or
28
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29
* in which case the provisions of the GPL or the LGPL are applicable instead
30
* of those above. If you wish to allow use of your version of this file only
31
* under the terms of either the GPL or the LGPL, and not to allow others to
32
* use your version of this file under the terms of the NPL, indicate your
33
* decision by deleting the provisions above and replace them with the notice
34
* and other provisions required by the GPL or the LGPL. If you do not delete
35
* the provisions above, a recipient may use your version of this file under
36
* the terms of any one of the NPL, the GPL or the LGPL.
38
* ***** END LICENSE BLOCK ***** */
41
* nsContentIterator.cpp: Implementation of the nsContentIterator object.
45
#include "nsISupports.h"
46
#include "nsIDOMNodeList.h"
47
#include "nsIContentIterator.h"
49
#include "nsIContent.h"
50
#include "nsIDOMText.h"
51
#include "nsISupportsArray.h"
52
#include "nsIFocusTracker.h"
54
#include "nsIPresContext.h"
55
#include "nsIComponentManager.h"
56
#include "nsContentCID.h"
57
#include "nsLayoutCID.h"
58
#include "nsVoidArray.h"
59
#include "nsContentUtils.h"
61
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
63
// couple of utility static functs
65
///////////////////////////////////////////////////////////////////////////
66
// GetNumChildren: returns the number of things inside aNode.
69
GetNumChildren(nsIDOMNode *aNode)
74
PRUint32 numChildren = 0;
76
aNode->HasChildNodes(&hasChildNodes);
79
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
82
return content->GetChildCount();
84
nsCOMPtr<nsIDOMNodeList>nodeList;
85
aNode->GetChildNodes(getter_AddRefs(nodeList));
87
nodeList->GetLength(&numChildren);
93
///////////////////////////////////////////////////////////////////////////
94
// GetChildAt: returns the node at this position index in the parent
96
static nsCOMPtr<nsIDOMNode>
97
GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset)
99
nsCOMPtr<nsIDOMNode> resultNode;
104
nsCOMPtr<nsIContent> content(do_QueryInterface(aParent));
107
resultNode = do_QueryInterface(content->GetChildAt(aOffset));
108
} else if (aParent) {
109
PRBool hasChildNodes;
110
aParent->HasChildNodes(&hasChildNodes);
113
nsCOMPtr<nsIDOMNodeList>nodeList;
114
aParent->GetChildNodes(getter_AddRefs(nodeList));
116
nodeList->Item(aOffset, getter_AddRefs(resultNode));
123
///////////////////////////////////////////////////////////////////////////
124
// ContentHasChildren: returns true if the content has children
127
ContentHasChildren(nsIContent *aContent)
129
return aContent->GetChildCount() > 0;
132
///////////////////////////////////////////////////////////////////////////
133
// ContentToParentOffset: returns the content node's parent and offset.
137
ContentToParentOffset(nsIContent *aContent, nsIDOMNode **aParent,
143
nsIContent* parent = aContent->GetParent();
148
*aOffset = parent->IndexOf(aContent);
150
CallQueryInterface(parent, aParent);
153
///////////////////////////////////////////////////////////////////////////
154
// ContentIsInTraversalRange: returns true if content is visited during
155
// the traversal of the range in the specified mode.
158
ContentIsInTraversalRange(nsIContent *aContent, PRBool aIsPreMode,
159
nsIDOMNode *aStartNode, PRInt32 aStartOffset,
160
nsIDOMNode *aEndNode, PRInt32 aEndOffset)
162
if (!aStartNode || !aEndNode || !aContent)
165
nsCOMPtr<nsIDOMCharacterData> cData(do_QueryInterface(aContent));
169
// If a chardata node contains an end point of the traversal range,
170
// it is always in the traversal range.
172
nsCOMPtr<nsIContent> startContent(do_QueryInterface(aStartNode));
173
nsCOMPtr<nsIContent> endContent(do_QueryInterface(aEndNode));
175
if (aContent == startContent || aContent == endContent)
179
nsCOMPtr<nsIDOMNode> parentNode;
182
ContentToParentOffset(aContent, getter_AddRefs(parentNode), &indx);
190
return (ComparePoints(aStartNode, aStartOffset, parentNode, indx) <= 0) &&
191
(ComparePoints(aEndNode, aEndOffset, parentNode, indx) >= 0);
197
* A simple iterator class for traversing the content in "close tag" order
199
class nsContentIterator : public nsIContentIterator //, public nsIEnumerator
205
virtual ~nsContentIterator();
207
// nsIContentIterator interface methods ------------------------------
209
virtual nsresult Init(nsIContent* aRoot);
211
virtual nsresult Init(nsIDOMRange* aRange);
213
virtual void First();
221
virtual nsIContent *GetCurrentNode();
223
virtual PRBool IsDone();
225
virtual nsresult PositionAt(nsIContent* aCurNode);
227
// nsIEnumertor interface methods ------------------------------
229
//NS_IMETHOD CurrentItem(nsISupports **aItem);
233
nsIContent *GetDeepFirstChild(nsIContent *aRoot, nsVoidArray *aIndexes);
234
nsIContent *GetDeepLastChild(nsIContent *aRoot, nsVoidArray *aIndexes);
236
nsIContent *GetNextSibling(nsIContent *aNode, nsVoidArray *aIndexes);
237
nsIContent *GetPrevSibling(nsIContent *aNode, nsVoidArray *aIndexes);
239
nsIContent *NextNode(nsIContent *aNode, nsVoidArray *aIndexes);
240
nsIContent *PrevNode(nsIContent *aNode, nsVoidArray *aIndexes);
242
// WARNING: This function is expensive
243
nsresult RebuildIndexStack();
247
nsCOMPtr<nsIContent> mCurNode;
248
nsCOMPtr<nsIContent> mFirst;
249
nsCOMPtr<nsIContent> mLast;
250
nsCOMPtr<nsIContent> mCommonParent;
252
// used by nsContentIterator to cache indices
253
nsAutoVoidArray mIndexes;
255
// used by nsSubtreeIterator to cache indices. Why put them in the base class?
256
// Because otherwise I have to duplicate the routines GetNextSibling etc across both classes,
257
// with slight variations for caching. Or alternately, create a base class for the cache
258
// itself and have all the cache manipulation go through a vptr.
259
// I think this is the best space and speed combo, even though it's ugly.
260
PRInt32 mCachedIndex;
261
// another note about mCachedIndex: why should the subtree iterator use a trivial cached index
262
// instead of the mre robust array of indicies (which is what the basic content iterator uses)?
263
// The reason is that subtree iterators do not do much transitioning between parents and children.
264
// They tend to stay at the same level. In fact, you can prove (though I won't attempt it here)
265
// that they change levels at most n+m times, where n is the height of the parent heirarchy from the
266
// range start to the common ancestor, and m is the the height of the parent heirarchy from the
267
// range end to the common ancestor. If we used the index array, we would pay the price up front
268
// for n, and then pay the cost for m on the fly later on. With the simple cache, we only "pay
269
// as we go". Either way, we call IndexOf() once for each change of level in the heirarchy.
270
// Since a trivial index is much simpler, we use it for the subtree iterator.
277
// no copy's or assigns FIX ME
278
nsContentIterator(const nsContentIterator&);
279
nsContentIterator& operator=(const nsContentIterator&);
285
* A simple iterator class for traversing the content in "open tag" order
288
class nsPreContentIterator : public nsContentIterator
291
nsPreContentIterator() { mPre = PR_TRUE; }
296
/******************************************************
298
******************************************************/
300
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult)
302
nsContentIterator * iter = new nsContentIterator();
304
return NS_ERROR_OUT_OF_MEMORY;
307
NS_ADDREF(*aInstancePtrResult = iter);
313
nsresult NS_NewPreContentIterator(nsIContentIterator** aInstancePtrResult)
315
nsContentIterator * iter = new nsPreContentIterator();
317
return NS_ERROR_OUT_OF_MEMORY;
320
NS_ADDREF(*aInstancePtrResult = iter);
326
/******************************************************
328
******************************************************/
330
NS_IMPL_ISUPPORTS1(nsContentIterator, nsIContentIterator)
333
/******************************************************
334
* constructor/destructor
335
******************************************************/
337
nsContentIterator::nsContentIterator() :
338
// don't need to explicitly initialize |nsCOMPtr|s, they will automatically be NULL
339
mCachedIndex(0), mIsDone(PR_FALSE), mPre(PR_FALSE)
344
nsContentIterator::~nsContentIterator()
349
/******************************************************
351
******************************************************/
355
nsContentIterator::Init(nsIContent* aRoot)
358
return NS_ERROR_NULL_POINTER;
365
mLast = GetDeepLastChild(aRoot, nsnull);
369
mFirst = GetDeepFirstChild(aRoot, nsnull);
373
mCommonParent = aRoot;
381
nsContentIterator::Init(nsIDOMRange* aRange)
384
return NS_ERROR_NULL_POINTER;
386
nsCOMPtr<nsIDOMNode> dN;
388
nsCOMPtr<nsIContent> startCon;
389
nsCOMPtr<nsIDOMNode> startDOM;
390
nsCOMPtr<nsIContent> endCon;
391
nsCOMPtr<nsIDOMNode> endDOM;
397
// get common content parent
398
if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(dN))) || !dN)
399
return NS_ERROR_FAILURE;
400
mCommonParent = do_QueryInterface(dN);
402
// get the start node and offset, convert to nsIContent
403
aRange->GetStartContainer(getter_AddRefs(startDOM));
405
return NS_ERROR_ILLEGAL_VALUE;
406
startCon = do_QueryInterface(startDOM);
408
return NS_ERROR_FAILURE;
410
aRange->GetStartOffset(&startIndx);
412
// get the end node and offset, convert to nsIContent
413
aRange->GetEndContainer(getter_AddRefs(endDOM));
415
return NS_ERROR_ILLEGAL_VALUE;
416
endCon = do_QueryInterface(endDOM);
418
return NS_ERROR_FAILURE;
420
aRange->GetEndOffset(&endIndx);
422
nsCOMPtr<nsIDOMCharacterData> cData(do_QueryInterface(startCon));
424
// short circuit when start node == end node
425
if (startDOM == endDOM)
427
// Check to see if we have a collapsed range, if so,
428
// there is nothing to iterate over.
430
// XXX: CharacterDataNodes (text nodes) are currently an exception,
431
// since we always want to be able to iterate text nodes at
432
// the end points of a range.
434
if (!cData && startIndx == endIndx)
453
// Find first node in range.
455
nsIContent *cChild = nsnull;
457
if (!cData && ContentHasChildren(startCon))
458
cChild = startCon->GetChildAt(startIndx);
460
if (!cChild) // no children, must be a text node
464
// XXX: In the future, if start offset is after the last
465
// character in the cdata node, should we set mFirst to
470
mFirst = GetNextSibling(startCon, nsnull);
472
// Does mFirst node really intersect the range?
473
// The range could be 'degenerate', ie not collapsed
474
// but still contain no content.
476
if (mFirst && !ContentIsInTraversalRange(mFirst, mPre, startDOM, startIndx, endDOM, endIndx))
491
mFirst = GetDeepFirstChild(cChild, nsnull);
493
// Does mFirst node really intersect the range?
494
// The range could be 'degenerate', ie not collapsed
495
// but still contain no content.
497
if (mFirst && !ContentIsInTraversalRange(mFirst, mPre, startDOM, startIndx, endDOM, endIndx))
503
// Find last node in range.
505
cData = do_QueryInterface(endCon);
507
if (cData || !ContentHasChildren(endCon) || endIndx == 0)
513
// XXX: In the future, if end offset is before the first
514
// character in the cdata node, should we set mLast to
519
mLast = GetPrevSibling(endCon, nsnull);
521
if (!ContentIsInTraversalRange(mLast, mPre, startDOM, startIndx, endDOM, endIndx))
530
PRInt32 indx = endIndx;
532
cChild = endCon->GetChildAt(--indx);
534
if (!cChild) // No child at offset!
536
NS_NOTREACHED("nsContentIterator::nsContentIterator");
537
return NS_ERROR_FAILURE;
542
mLast = GetDeepLastChild(cChild, nsnull);
544
if (!ContentIsInTraversalRange(mLast, mPre, startDOM, startIndx, endDOM, endIndx))
551
// If either first or last is null, they both
554
if (!mFirst || !mLast)
572
/******************************************************
574
******************************************************/
575
// WARNING: This function is expensive
576
nsresult nsContentIterator::RebuildIndexStack()
578
// Make sure we start at the right indexes on the stack! Build array up
579
// to common parent of start and end. Perhaps it's too many entries, but
580
// thats far better than too few.
590
while (current != mCommonParent)
592
parent = current->GetParent();
595
return NS_ERROR_FAILURE;
597
mIndexes.InsertElementAt(NS_INT32_TO_PTR(parent->IndexOf(current)), 0);
605
nsContentIterator::MakeEmpty()
610
mCommonParent = nsnull;
616
nsContentIterator::GetDeepFirstChild(nsIContent *aRoot, nsVoidArray *aIndexes)
622
nsIContent *cN = aRoot;
623
nsIContent *cChild = cN->GetChildAt(0);
629
// Add this node to the stack of indexes
630
aIndexes->AppendElement(NS_INT32_TO_PTR(0));
633
cChild = cN->GetChildAt(0);
640
nsContentIterator::GetDeepLastChild(nsIContent *aRoot, nsVoidArray *aIndexes)
646
nsIContent *deepLastChild = aRoot;
648
nsIContent *cN = aRoot;
649
PRInt32 numChildren = cN->GetChildCount();
653
nsIContent *cChild = cN->GetChildAt(--numChildren);
657
// Add this node to the stack of indexes
658
aIndexes->AppendElement(NS_INT32_TO_PTR(numChildren));
660
numChildren = cChild->GetChildCount();
666
return deepLastChild;
669
// Get the next sibling, or parents next sibling, or grandpa's next sibling...
671
nsContentIterator::GetNextSibling(nsIContent *aNode,
672
nsVoidArray *aIndexes)
677
nsIContent *parent = aNode->GetParent();
685
NS_ASSERTION(aIndexes->Count() > 0, "ContentIterator stack underflow");
686
// use the last entry on the Indexes array for the current index
687
indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]);
692
// reverify that the index of the current node hasn't changed.
693
// not super cheap, but a lot cheaper than IndexOf(), and still O(1).
694
// ignore result this time - the index may now be out of range.
695
nsIContent *sib = parent->GetChildAt(indx);
698
// someone changed our index - find the new index the painful way
699
indx = parent->IndexOf(aNode);
702
// indx is now canonically correct
703
if ((sib = parent->GetChildAt(++indx)))
705
// update index cache
708
aIndexes->ReplaceElementAt(NS_INT32_TO_PTR(indx),aIndexes->Count()-1);
710
else mCachedIndex = indx;
714
if (parent != mCommonParent)
718
// pop node off the stack, go up one level and return parent or fail.
719
// Don't leave the index empty, especially if we're
720
// returning NULL. This confuses other parts of the code.
721
if (aIndexes->Count() > 1)
722
aIndexes->RemoveElementAt(aIndexes->Count()-1);
726
// ok to leave cache out of date here if parent == mCommonParent?
727
sib = GetNextSibling(parent, aIndexes);
733
// Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
735
nsContentIterator::GetPrevSibling(nsIContent *aNode,
736
nsVoidArray *aIndexes)
741
nsIContent *parent = aNode->GetParent();
749
NS_ASSERTION(aIndexes->Count() > 0, "ContentIterator stack underflow");
750
// use the last entry on the Indexes array for the current index
751
indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]);
756
// reverify that the index of the current node hasn't changed
757
// ignore result this time - the index may now be out of range.
758
nsIContent *sib = parent->GetChildAt(indx);
761
// someone changed our index - find the new index the painful way
762
indx = parent->IndexOf(aNode);
765
// indx is now canonically correct
766
if (indx > 0 && (sib = parent->GetChildAt(--indx)))
768
// update index cache
771
aIndexes->ReplaceElementAt(NS_INT32_TO_PTR(indx),aIndexes->Count()-1);
773
else mCachedIndex = indx;
775
else if (parent != mCommonParent)
779
// pop node off the stack, go up one level and try again.
780
aIndexes->RemoveElementAt(aIndexes->Count()-1);
782
return GetPrevSibling(parent, aIndexes);
789
nsContentIterator::NextNode(nsIContent *aNode, nsVoidArray *aIndexes)
791
nsIContent *cN = aNode;
792
nsIContent *nextNode = nsnull;
794
if (mPre) // if we are a Pre-order iterator, use pre-order
796
// if it has children then next node is first child
797
if (ContentHasChildren(cN))
799
nsIContent *cFirstChild = cN->GetChildAt(0);
804
// push an entry on the index stack
805
aIndexes->AppendElement(NS_INT32_TO_PTR(0));
807
else mCachedIndex = 0;
812
// else next sibling is next
813
nextNode = GetNextSibling(cN, aIndexes);
817
nsIContent *parent = cN->GetParent();
818
nsIContent *cSibling = nsnull;
821
// get the cached index
824
NS_ASSERTION(aIndexes->Count() > 0, "ContentIterator stack underflow");
825
// use the last entry on the Indexes array for the current index
826
indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]);
828
else indx = mCachedIndex;
830
// reverify that the index of the current node hasn't changed.
831
// not super cheap, but a lot cheaper than IndexOf(), and still O(1).
832
// ignore result this time - the index may now be out of range.
834
cSibling = parent->GetChildAt(indx);
837
// someone changed our index - find the new index the painful way
838
indx = parent->IndexOf(cN);
841
// indx is now canonically correct
842
cSibling = parent->GetChildAt(++indx);
848
// replace an entry on the index stack
849
aIndexes->ReplaceElementAt(NS_INT32_TO_PTR(indx),aIndexes->Count()-1);
851
else mCachedIndex = indx;
853
// next node is siblings "deep left" child
854
return GetDeepFirstChild(cSibling, aIndexes);
857
// else it's the parent
861
// pop an entry off the index stack
862
// Don't leave the index empty, especially if we're
863
// returning NULL. This confuses other parts of the code.
864
if (aIndexes->Count() > 1)
865
aIndexes->RemoveElementAt(aIndexes->Count()-1);
867
else mCachedIndex = 0; // this might be wrong, but we are better off guessing
875
nsContentIterator::PrevNode(nsIContent *aNode, nsVoidArray *aIndexes)
877
nsIContent *prevNode = nsnull;
878
nsIContent *cN = aNode;
880
if (mPre) // if we are a Pre-order iterator, use pre-order
882
nsIContent *parent = cN->GetParent();
883
nsIContent *cSibling = nsnull;
886
// get the cached index
889
NS_ASSERTION(aIndexes->Count() > 0, "ContentIterator stack underflow");
890
// use the last entry on the Indexes array for the current index
891
indx = NS_PTR_TO_INT32((*aIndexes)[aIndexes->Count()-1]);
893
else indx = mCachedIndex;
895
// reverify that the index of the current node hasn't changed.
896
// not super cheap, but a lot cheaper than IndexOf(), and still O(1).
897
// ignore result this time - the index may now be out of range.
899
cSibling = parent->GetChildAt(indx);
903
// someone changed our index - find the new index the painful way
904
indx = parent->IndexOf(cN);
907
// indx is now canonically correct
908
if (indx && (cSibling = parent->GetChildAt(--indx)))
913
// replace an entry on the index stack
914
aIndexes->ReplaceElementAt(NS_INT32_TO_PTR(indx),aIndexes->Count()-1);
916
else mCachedIndex = indx;
918
// prev node is siblings "deep right" child
919
return GetDeepLastChild(cSibling, aIndexes);
922
// else it's the parent
926
// pop an entry off the index stack
927
aIndexes->RemoveElementAt(aIndexes->Count()-1);
929
else mCachedIndex = 0; // this might be wrong, but we are better off guessing
934
PRInt32 numChildren = cN->GetChildCount();
936
// if it has children then prev node is last child
939
nsIContent *cLastChild = cN->GetChildAt(--numChildren);
944
// push an entry on the index stack
945
aIndexes->AppendElement(NS_INT32_TO_PTR(numChildren));
947
else mCachedIndex = numChildren;
952
// else prev sibling is previous
953
prevNode = GetPrevSibling(cN, aIndexes);
959
/******************************************************
960
* ContentIterator routines
961
******************************************************/
964
nsContentIterator::First()
966
NS_ASSERTION(mFirst, "No first node!");
974
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
977
mIsDone = mFirst == nsnull;
982
nsContentIterator::Last()
984
NS_ASSERTION(mLast, "No last node!");
992
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
995
mIsDone = mLast == nsnull;
1000
nsContentIterator::Next()
1002
if (mIsDone || !mCurNode)
1005
if (mCurNode == mLast)
1011
mCurNode = NextNode(mCurNode, &mIndexes);
1016
nsContentIterator::Prev()
1018
if (mIsDone || !mCurNode)
1021
if (mCurNode == mFirst)
1027
mCurNode = PrevNode(mCurNode, &mIndexes);
1032
nsContentIterator::IsDone()
1038
// Keeping arrays of indexes for the stack of nodes makes PositionAt
1041
nsContentIterator::PositionAt(nsIContent* aCurNode)
1044
return NS_ERROR_NULL_POINTER;
1046
nsIContent *newCurNode = aCurNode;
1047
nsIContent *tempNode = mCurNode;
1049
mCurNode = aCurNode;
1050
// take an early out if this doesn't actually change the position
1051
if (mCurNode == tempNode)
1053
mIsDone = PR_FALSE; // paranoia
1057
// Check to see if the node falls within the traversal range.
1059
nsCOMPtr<nsIDOMNode> firstNode(do_QueryInterface(mFirst));
1060
nsCOMPtr<nsIDOMNode> lastNode(do_QueryInterface(mLast));
1061
PRInt32 firstOffset=0, lastOffset=0;
1063
if (firstNode && lastNode)
1065
PRUint32 numChildren;
1069
ContentToParentOffset(mFirst, getter_AddRefs(firstNode), &firstOffset);
1071
numChildren = GetNumChildren(lastNode);
1077
ContentToParentOffset(mLast, getter_AddRefs(lastNode), &lastOffset);
1083
numChildren = GetNumChildren(firstNode);
1086
firstOffset = numChildren;
1088
ContentToParentOffset(mFirst, getter_AddRefs(firstNode), &firstOffset);
1090
ContentToParentOffset(mLast, getter_AddRefs(lastNode), &lastOffset);
1095
if (!firstNode || !lastNode ||
1096
!ContentIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset,
1097
lastNode, lastOffset))
1100
return NS_ERROR_FAILURE;
1103
// We can be at ANY node in the sequence.
1104
// Need to regenerate the array of indexes back to the root or common parent!
1105
nsAutoVoidArray oldParentStack;
1106
nsAutoVoidArray newIndexes;
1108
// Get a list of the parents up to the root, then compare the new node
1109
// with entries in that array until we find a match (lowest common
1110
// ancestor). If no match, use IndexOf, take the parent, and repeat.
1111
// This avoids using IndexOf() N times on possibly large arrays. We
1112
// still end up doing it a fair bit. It's better to use Clone() if
1115
// we know the depth we're down (though we may not have started at the
1117
if (!oldParentStack.SizeTo(mIndexes.Count()+1))
1118
return NS_ERROR_FAILURE;
1120
// plus one for the node we're currently on.
1121
for (PRInt32 i = mIndexes.Count()+1; i > 0 && tempNode; i--)
1123
// Insert at head since we're walking up
1124
oldParentStack.InsertElementAt(tempNode,0);
1126
nsIContent *parent = tempNode->GetParent();
1128
if (!parent) // this node has no parent, and thus no index
1131
if (parent == mCurNode)
1133
// The position was moved to a parent of the current position.
1134
// All we need to do is drop some indexes. Shortcut here.
1135
mIndexes.RemoveElementsAt(mIndexes.Count() - (oldParentStack.Count()+1),
1136
oldParentStack.Count());
1143
// Ok. We have the array of old parents. Look for a match.
1146
nsIContent *parent = newCurNode->GetParent();
1148
if (!parent) // this node has no parent, and thus no index
1151
PRInt32 indx = parent->IndexOf(newCurNode);
1153
// insert at the head!
1154
newIndexes.InsertElementAt(NS_INT32_TO_PTR(indx),0);
1156
// look to see if the parent is in the stack
1157
indx = oldParentStack.IndexOf(parent);
1160
// ok, the parent IS on the old stack! Rework things.
1161
// we want newIndexes to replace all nodes equal to or below the match
1162
// Note that index oldParentStack.Count()-1 is the last node, which is
1163
// one BELOW the last index in the mIndexes stack.
1164
PRInt32 numToDrop = oldParentStack.Count()-(1+indx);
1166
mIndexes.RemoveElementsAt(mIndexes.Count() - numToDrop,numToDrop);
1167
mIndexes.InsertElementsAt(newIndexes,mIndexes.Count());
1171
newCurNode = parent;
1182
nsContentIterator::GetCurrentNode()
1188
NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
1197
/*====================================================================================*/
1198
/*====================================================================================*/
1205
/******************************************************
1206
* nsContentSubtreeIterator
1207
******************************************************/
1211
* A simple iterator class for traversing the content in "top subtree" order
1213
class nsContentSubtreeIterator : public nsContentIterator
1216
nsContentSubtreeIterator() {};
1217
virtual ~nsContentSubtreeIterator() {};
1219
// nsContentIterator overrides ------------------------------
1221
virtual nsresult Init(nsIContent* aRoot);
1223
virtual nsresult Init(nsIDOMRange* aRange);
1225
virtual void Next();
1227
virtual void Prev();
1229
virtual nsresult PositionAt(nsIContent* aCurNode);
1231
// Must override these because we don't do PositionAt
1232
virtual void First();
1234
// Must override these because we don't do PositionAt
1235
virtual void Last();
1239
nsresult GetTopAncestorInRange(nsIContent *aNode,
1240
nsCOMPtr<nsIContent> *outAnestor);
1242
// no copy's or assigns FIX ME
1243
nsContentSubtreeIterator(const nsContentSubtreeIterator&);
1244
nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
1246
nsCOMPtr<nsIDOMRange> mRange;
1247
// these arrays all typically are used and have elements
1249
nsAutoVoidArray mStartNodes;
1250
nsAutoVoidArray mStartOffsets;
1253
nsAutoVoidArray mEndNodes;
1254
nsAutoVoidArray mEndOffsets;
1257
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
1262
/******************************************************
1264
******************************************************/
1266
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult)
1268
nsContentIterator * iter = new nsContentSubtreeIterator();
1270
return NS_ERROR_OUT_OF_MEMORY;
1273
NS_ADDREF(*aInstancePtrResult = iter);
1280
/******************************************************
1282
******************************************************/
1285
nsresult nsContentSubtreeIterator::Init(nsIContent* aRoot)
1287
return NS_ERROR_NOT_IMPLEMENTED;
1291
nsresult nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
1294
return NS_ERROR_NULL_POINTER;
1300
// get the start node and offset, convert to nsIContent
1301
nsCOMPtr<nsIDOMNode> commonParent;
1302
nsCOMPtr<nsIDOMNode> startParent;
1303
nsCOMPtr<nsIDOMNode> endParent;
1304
nsCOMPtr<nsIContent> cStartP;
1305
nsCOMPtr<nsIContent> cEndP;
1306
nsCOMPtr<nsIContent> cN;
1307
nsIContent *firstCandidate = nsnull;
1308
nsIContent *lastCandidate = nsnull;
1309
nsCOMPtr<nsIDOMNode> dChild;
1310
nsCOMPtr<nsIContent> cChild;
1311
PRInt32 indx, startIndx, endIndx;
1312
PRInt32 numChildren;
1314
// get common content parent
1315
if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent))) || !commonParent)
1316
return NS_ERROR_FAILURE;
1317
mCommonParent = do_QueryInterface(commonParent);
1319
// get start content parent
1320
if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(startParent))) || !startParent)
1321
return NS_ERROR_FAILURE;
1322
cStartP = do_QueryInterface(startParent);
1323
aRange->GetStartOffset(&startIndx);
1325
// get end content parent
1326
if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(endParent))) || !endParent)
1327
return NS_ERROR_FAILURE;
1328
cEndP = do_QueryInterface(endParent);
1329
aRange->GetEndOffset(&endIndx);
1331
// short circuit when start node == end node
1332
if (startParent == endParent)
1334
cChild = cStartP->GetChildAt(0);
1336
if (!cChild) // no children, must be a text node or empty container
1338
// all inside one text node - empty subtree iterator
1344
if (startIndx == endIndx) // collapsed range
1354
nsContentUtils::GetAncestorsAndOffsets(startParent, startIndx,
1355
&mStartNodes, &mStartOffsets);
1357
nsContentUtils::GetAncestorsAndOffsets(endParent, endIndx,
1358
&mEndNodes, &mEndOffsets);
1360
// find first node in range
1361
aRange->GetStartOffset(&indx);
1362
numChildren = GetNumChildren(startParent);
1364
if (!numChildren) // no children, must be a text node
1370
dChild = GetChildAt(startParent, indx);
1371
cChild = do_QueryInterface(dChild);
1372
if (!cChild) // offset after last child
1378
firstCandidate = cChild;
1382
if (!firstCandidate)
1384
// then firstCandidate is next node after cN
1385
firstCandidate = GetNextSibling(cN, nsnull);
1387
if (!firstCandidate)
1394
firstCandidate = GetDeepFirstChild(firstCandidate, nsnull);
1396
// confirm that this first possible contained node
1397
// is indeed contained. Else we have a range that
1398
// does not fully contain any node.
1400
PRBool nodeBefore, nodeAfter;
1401
if (NS_FAILED(nsRange::CompareNodeToRange(firstCandidate, aRange,
1402
&nodeBefore, &nodeAfter)))
1403
return NS_ERROR_FAILURE;
1405
if (nodeBefore || nodeAfter)
1411
// cool, we have the first node in the range. Now we walk
1412
// up it's ancestors to find the most senior that is still
1413
// in the range. That's the real first node.
1414
if (NS_FAILED(GetTopAncestorInRange(firstCandidate, address_of(mFirst))))
1415
return NS_ERROR_FAILURE;
1417
// now to find the last node
1418
aRange->GetEndOffset(&indx);
1419
numChildren = GetNumChildren(endParent);
1421
if (indx > numChildren) indx = numChildren;
1428
if (!numChildren) // no children, must be a text node
1434
dChild = GetChildAt(endParent, --indx);
1435
cChild = do_QueryInterface(dChild);
1436
if (!cChild) // shouldn't happen
1438
NS_ASSERTION(0,"tree traversal trouble in nsContentSubtreeIterator::Init");
1439
return NS_ERROR_FAILURE;
1443
lastCandidate = cChild;
1450
// then lastCandidate is prev node before cN
1451
lastCandidate = GetPrevSibling(cN, nsnull);
1454
lastCandidate = GetDeepLastChild(lastCandidate, nsnull);
1456
// confirm that this last possible contained node
1457
// is indeed contained. Else we have a range that
1458
// does not fully contain any node.
1460
if (NS_FAILED(nsRange::CompareNodeToRange(lastCandidate, aRange, &nodeBefore,
1462
return NS_ERROR_FAILURE;
1464
if (nodeBefore || nodeAfter)
1470
// cool, we have the last node in the range. Now we walk
1471
// up it's ancestors to find the most senior that is still
1472
// in the range. That's the real first node.
1473
if (NS_FAILED(GetTopAncestorInRange(lastCandidate, address_of(mLast))))
1474
return NS_ERROR_FAILURE;
1482
/****************************************************************
1483
* nsContentSubtreeIterator overrides of ContentIterator routines
1484
****************************************************************/
1486
// we can't call PositionAt in a subtree iterator...
1488
nsContentSubtreeIterator::First()
1490
mIsDone = mFirst == nsnull;
1495
// we can't call PositionAt in a subtree iterator...
1497
nsContentSubtreeIterator::Last()
1499
mIsDone = mLast == nsnull;
1506
nsContentSubtreeIterator::Next()
1508
if (mIsDone || !mCurNode)
1511
if (mCurNode == mLast)
1517
nsIContent *nextNode = GetNextSibling(mCurNode, nsnull);
1518
NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
1521
nextNode = GetDeepFirstChild(nextNode);
1522
return GetTopAncestorInRange(nextNode, address_of(mCurNode));
1524
PRInt32 i = mEndNodes.IndexOf(nextNode);
1527
// as long as we are finding ancestors of the endpoint of the range,
1528
// dive down into their children
1529
nextNode = nextNode->GetChildAt(0);
1530
NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
1532
// should be impossible to get a null pointer. If we went all the way
1533
// down the child chain to the bottom without finding an interior node,
1534
// then the previous node should have been the last, which was
1535
// was tested at top of routine.
1536
i = mEndNodes.IndexOf(nextNode);
1539
mCurNode = nextNode;
1541
// This shouldn't be needed, but since our selection code can put us
1542
// in a situation where mLast is in generated content, we need this
1543
// to stop the iterator when we've walked past past the last node!
1544
mIsDone = mCurNode == nsnull;
1551
nsContentSubtreeIterator::Prev()
1553
// Prev should be optimized to use the mStartNodes, just as Next
1555
if (mIsDone || !mCurNode)
1558
if (mCurNode == mFirst)
1564
nsIContent *prevNode = PrevNode(GetDeepFirstChild(mCurNode, nsnull), nsnull);
1566
prevNode = GetDeepLastChild(prevNode, nsnull);
1568
GetTopAncestorInRange(prevNode, address_of(mCurNode));
1570
// This shouldn't be needed, but since our selection code can put us
1571
// in a situation where mFirst is in generated content, we need this
1572
// to stop the iterator when we've walked past past the first node!
1573
mIsDone = mCurNode == nsnull;
1578
nsContentSubtreeIterator::PositionAt(nsIContent* aCurNode)
1580
NS_ERROR("Not implemented!");
1582
return NS_ERROR_NOT_IMPLEMENTED;
1585
/****************************************************************
1586
* nsContentSubtreeIterator helper routines
1587
****************************************************************/
1590
nsContentSubtreeIterator::GetTopAncestorInRange(nsIContent *aNode,
1591
nsCOMPtr<nsIContent> *outAnestor)
1594
return NS_ERROR_NULL_POINTER;
1596
return NS_ERROR_NULL_POINTER;
1599
// sanity check: aNode is itself in the range
1600
PRBool nodeBefore, nodeAfter;
1601
if (NS_FAILED(nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore,
1603
return NS_ERROR_FAILURE;
1605
if (nodeBefore || nodeAfter)
1606
return NS_ERROR_FAILURE;
1608
nsCOMPtr<nsIContent> parent, tmp;
1611
parent = aNode->GetParent();
1619
else return NS_ERROR_FAILURE;
1621
if (NS_FAILED(nsRange::CompareNodeToRange(parent, mRange, &nodeBefore,
1623
return NS_ERROR_FAILURE;
1625
if (nodeBefore || nodeAfter)
1627
*outAnestor = aNode;
1633
return NS_ERROR_FAILURE;