1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
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
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsISupports.h"
40 : #include "nsIDOMNodeList.h"
41 : #include "nsIContentIterator.h"
42 : #include "nsRange.h"
43 : #include "nsIContent.h"
44 : #include "nsCOMPtr.h"
45 : #include "nsTArray.h"
46 : #include "nsContentUtils.h"
47 : #include "nsINode.h"
48 : #include "nsCycleCollectionParticipant.h"
49 :
50 : // couple of utility static functs
51 :
52 : ///////////////////////////////////////////////////////////////////////////
53 : // ContentHasChildren: returns true if the node has children
54 : //
55 : static inline bool
56 0 : NodeHasChildren(nsINode *aNode)
57 : {
58 0 : return aNode->GetChildCount() > 0;
59 : }
60 :
61 : ///////////////////////////////////////////////////////////////////////////
62 : // NodeToParentOffset: returns the node's parent and offset.
63 : //
64 :
65 : static nsINode*
66 0 : NodeToParentOffset(nsINode *aNode, PRInt32 *aOffset)
67 : {
68 0 : *aOffset = 0;
69 :
70 0 : nsINode* parent = aNode->GetNodeParent();
71 :
72 0 : if (parent) {
73 0 : *aOffset = parent->IndexOf(aNode);
74 : }
75 :
76 0 : return parent;
77 : }
78 :
79 : ///////////////////////////////////////////////////////////////////////////
80 : // NodeIsInTraversalRange: returns true if content is visited during
81 : // the traversal of the range in the specified mode.
82 : //
83 : static bool
84 0 : NodeIsInTraversalRange(nsINode *aNode, bool aIsPreMode,
85 : nsINode *aStartNode, PRInt32 aStartOffset,
86 : nsINode *aEndNode, PRInt32 aEndOffset)
87 : {
88 0 : if (!aStartNode || !aEndNode || !aNode)
89 0 : return false;
90 :
91 : // If a chardata node contains an end point of the traversal range,
92 : // it is always in the traversal range.
93 0 : if (aNode->IsNodeOfType(nsINode::eDATA_NODE) &&
94 : (aNode == aStartNode || aNode == aEndNode)) {
95 0 : return true;
96 : }
97 :
98 0 : nsINode* parent = aNode->GetNodeParent();
99 0 : if (!parent)
100 0 : return false;
101 :
102 0 : PRInt32 indx = parent->IndexOf(aNode);
103 :
104 0 : if (!aIsPreMode)
105 0 : ++indx;
106 :
107 : return (nsContentUtils::ComparePoints(aStartNode, aStartOffset,
108 0 : parent, indx) <= 0) &&
109 : (nsContentUtils::ComparePoints(aEndNode, aEndOffset,
110 0 : parent, indx) >= 0);
111 : }
112 :
113 :
114 :
115 : /*
116 : * A simple iterator class for traversing the content in "close tag" order
117 : */
118 : class nsContentIterator : public nsIContentIterator //, public nsIEnumerator
119 : {
120 : public:
121 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
122 2952 : NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator)
123 :
124 : explicit nsContentIterator(bool aPre);
125 : virtual ~nsContentIterator();
126 :
127 : // nsIContentIterator interface methods ------------------------------
128 :
129 : virtual nsresult Init(nsINode* aRoot);
130 :
131 : virtual nsresult Init(nsIDOMRange* aRange);
132 :
133 : virtual void First();
134 :
135 : virtual void Last();
136 :
137 : virtual void Next();
138 :
139 : virtual void Prev();
140 :
141 : virtual nsINode *GetCurrentNode();
142 :
143 : virtual bool IsDone();
144 :
145 : virtual nsresult PositionAt(nsINode* aCurNode);
146 :
147 : // nsIEnumertor interface methods ------------------------------
148 :
149 : //NS_IMETHOD CurrentItem(nsISupports **aItem);
150 :
151 : protected:
152 :
153 : nsINode* GetDeepFirstChild(nsINode *aRoot, nsTArray<PRInt32> *aIndexes);
154 : nsINode* GetDeepLastChild(nsINode *aRoot, nsTArray<PRInt32> *aIndexes);
155 :
156 : // Get the next sibling of aNode. Note that this will generally return null
157 : // if aNode happens not to be a content node. That's OK.
158 : nsINode* GetNextSibling(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
159 :
160 : // Get the prev sibling of aNode. Note that this will generally return null
161 : // if aNode happens not to be a content node. That's OK.
162 : nsINode* GetPrevSibling(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
163 :
164 : nsINode* NextNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
165 : nsINode* PrevNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes);
166 :
167 : // WARNING: This function is expensive
168 : nsresult RebuildIndexStack();
169 :
170 : void MakeEmpty();
171 :
172 : nsCOMPtr<nsINode> mCurNode;
173 : nsCOMPtr<nsINode> mFirst;
174 : nsCOMPtr<nsINode> mLast;
175 : nsCOMPtr<nsINode> mCommonParent;
176 :
177 : // used by nsContentIterator to cache indices
178 : nsAutoTArray<PRInt32, 8> mIndexes;
179 :
180 : // used by nsSubtreeIterator to cache indices. Why put them in the base class?
181 : // Because otherwise I have to duplicate the routines GetNextSibling etc across both classes,
182 : // with slight variations for caching. Or alternately, create a base class for the cache
183 : // itself and have all the cache manipulation go through a vptr.
184 : // I think this is the best space and speed combo, even though it's ugly.
185 : PRInt32 mCachedIndex;
186 : // another note about mCachedIndex: why should the subtree iterator use a trivial cached index
187 : // instead of the mre robust array of indicies (which is what the basic content iterator uses)?
188 : // The reason is that subtree iterators do not do much transitioning between parents and children.
189 : // They tend to stay at the same level. In fact, you can prove (though I won't attempt it here)
190 : // that they change levels at most n+m times, where n is the height of the parent hierarchy from the
191 : // range start to the common ancestor, and m is the the height of the parent hierarchy from the
192 : // range end to the common ancestor. If we used the index array, we would pay the price up front
193 : // for n, and then pay the cost for m on the fly later on. With the simple cache, we only "pay
194 : // as we go". Either way, we call IndexOf() once for each change of level in the hierarchy.
195 : // Since a trivial index is much simpler, we use it for the subtree iterator.
196 :
197 : bool mIsDone;
198 : bool mPre;
199 :
200 : private:
201 :
202 : // no copy's or assigns FIX ME
203 : nsContentIterator(const nsContentIterator&);
204 : nsContentIterator& operator=(const nsContentIterator&);
205 :
206 : };
207 :
208 :
209 : /******************************************************
210 : * repository cruft
211 : ******************************************************/
212 :
213 0 : nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult)
214 : {
215 0 : nsContentIterator * iter = new nsContentIterator(false);
216 0 : if (!iter) {
217 0 : return NS_ERROR_OUT_OF_MEMORY;
218 : }
219 :
220 0 : NS_ADDREF(*aInstancePtrResult = iter);
221 :
222 0 : return NS_OK;
223 : }
224 :
225 :
226 0 : nsresult NS_NewPreContentIterator(nsIContentIterator** aInstancePtrResult)
227 : {
228 0 : nsContentIterator * iter = new nsContentIterator(true);
229 0 : if (!iter) {
230 0 : return NS_ERROR_OUT_OF_MEMORY;
231 : }
232 :
233 0 : NS_ADDREF(*aInstancePtrResult = iter);
234 :
235 0 : return NS_OK;
236 : }
237 :
238 :
239 : /******************************************************
240 : * XPCOM cruft
241 : ******************************************************/
242 :
243 12 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator)
244 12 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentIterator)
245 :
246 6 : NS_INTERFACE_MAP_BEGIN(nsContentIterator)
247 6 : NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
248 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
249 0 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator)
250 0 : NS_INTERFACE_MAP_END
251 :
252 1464 : NS_IMPL_CYCLE_COLLECTION_4(nsContentIterator,
253 : mCurNode,
254 : mFirst,
255 : mLast,
256 : mCommonParent)
257 :
258 : /******************************************************
259 : * constructor/destructor
260 : ******************************************************/
261 :
262 6 : nsContentIterator::nsContentIterator(bool aPre) :
263 : // don't need to explicitly initialize |nsCOMPtr|s, they will automatically be NULL
264 6 : mCachedIndex(0), mIsDone(false), mPre(aPre)
265 : {
266 6 : }
267 :
268 :
269 6 : nsContentIterator::~nsContentIterator()
270 : {
271 12 : }
272 :
273 :
274 : /******************************************************
275 : * Init routines
276 : ******************************************************/
277 :
278 :
279 : nsresult
280 0 : nsContentIterator::Init(nsINode* aRoot)
281 : {
282 0 : if (!aRoot)
283 0 : return NS_ERROR_NULL_POINTER;
284 :
285 0 : mIsDone = false;
286 0 : mIndexes.Clear();
287 :
288 0 : if (mPre)
289 : {
290 0 : mFirst = aRoot;
291 0 : mLast = GetDeepLastChild(aRoot, nsnull);
292 : }
293 : else
294 : {
295 0 : mFirst = GetDeepFirstChild(aRoot, nsnull);
296 0 : mLast = aRoot;
297 : }
298 :
299 0 : mCommonParent = aRoot;
300 0 : mCurNode = mFirst;
301 0 : RebuildIndexStack();
302 0 : return NS_OK;
303 : }
304 :
305 : nsresult
306 0 : nsContentIterator::Init(nsIDOMRange* aDOMRange)
307 : {
308 0 : NS_ENSURE_ARG_POINTER(aDOMRange);
309 0 : nsRange* range = static_cast<nsRange*>(aDOMRange);
310 :
311 0 : mIsDone = false;
312 :
313 : // get common content parent
314 0 : mCommonParent = range->GetCommonAncestor();
315 0 : NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE);
316 :
317 : // get the start node and offset
318 0 : PRInt32 startIndx = range->StartOffset();
319 0 : nsINode* startNode = range->GetStartParent();
320 0 : NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
321 :
322 : // get the end node and offset
323 0 : PRInt32 endIndx = range->EndOffset();
324 0 : nsINode* endNode = range->GetEndParent();
325 0 : NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
326 :
327 0 : bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
328 :
329 : // short circuit when start node == end node
330 0 : if (startNode == endNode)
331 : {
332 : // Check to see if we have a collapsed range, if so,
333 : // there is nothing to iterate over.
334 : //
335 : // XXX: CharacterDataNodes (text nodes) are currently an exception,
336 : // since we always want to be able to iterate text nodes at
337 : // the end points of a range.
338 :
339 0 : if (!startIsData && startIndx == endIndx)
340 : {
341 0 : MakeEmpty();
342 0 : return NS_OK;
343 : }
344 :
345 0 : if (startIsData)
346 : {
347 : // It's a textnode.
348 0 : NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
349 : "Data node that's not content?");
350 :
351 0 : mFirst = static_cast<nsIContent*>(startNode);
352 0 : mLast = mFirst;
353 0 : mCurNode = mFirst;
354 :
355 0 : RebuildIndexStack();
356 0 : return NS_OK;
357 : }
358 : }
359 :
360 : // Find first node in range.
361 :
362 0 : nsIContent *cChild = nsnull;
363 :
364 0 : if (!startIsData && NodeHasChildren(startNode))
365 0 : cChild = startNode->GetChildAt(startIndx);
366 :
367 0 : if (!cChild) // no children, must be a text node
368 : {
369 : // XXXbz no children might also just mean no children. So I'm not
370 : // sure what that comment above is talking about.
371 0 : if (mPre)
372 : {
373 : // XXX: In the future, if start offset is after the last
374 : // character in the cdata node, should we set mFirst to
375 : // the next sibling?
376 :
377 0 : if (!startIsData)
378 : {
379 0 : mFirst = GetNextSibling(startNode, nsnull);
380 :
381 : // Does mFirst node really intersect the range?
382 : // The range could be 'degenerate', ie not collapsed
383 : // but still contain no content.
384 :
385 0 : if (mFirst &&
386 : !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
387 0 : endNode, endIndx)) {
388 0 : mFirst = nsnull;
389 : }
390 : }
391 : else {
392 0 : NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
393 : "Data node that's not content?");
394 :
395 0 : mFirst = static_cast<nsIContent*>(startNode);
396 : }
397 : }
398 : else {
399 : // post-order
400 0 : if (startNode->IsNodeOfType(nsINode::eCONTENT)) {
401 0 : mFirst = static_cast<nsIContent*>(startNode);
402 : } else {
403 : // What else can we do?
404 0 : mFirst = nsnull;
405 : }
406 : }
407 : }
408 : else
409 : {
410 0 : if (mPre)
411 0 : mFirst = cChild;
412 : else // post-order
413 : {
414 0 : mFirst = GetDeepFirstChild(cChild, nsnull);
415 :
416 : // Does mFirst node really intersect the range?
417 : // The range could be 'degenerate', ie not collapsed
418 : // but still contain no content.
419 :
420 0 : if (mFirst &&
421 : !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
422 0 : endNode, endIndx))
423 0 : mFirst = nsnull;
424 : }
425 : }
426 :
427 :
428 : // Find last node in range.
429 :
430 0 : bool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);
431 :
432 0 : if (endIsData || !NodeHasChildren(endNode) || endIndx == 0)
433 : {
434 0 : if (mPre) {
435 0 : if (endNode->IsNodeOfType(nsINode::eCONTENT)) {
436 0 : mLast = static_cast<nsIContent*>(endNode);
437 : } else {
438 : // Not much else to do here...
439 0 : mLast = nsnull;
440 : }
441 : }
442 : else // post-order
443 : {
444 : // XXX: In the future, if end offset is before the first
445 : // character in the cdata node, should we set mLast to
446 : // the prev sibling?
447 :
448 0 : if (!endIsData)
449 : {
450 0 : mLast = GetPrevSibling(endNode, nsnull);
451 :
452 0 : if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
453 0 : endNode, endIndx))
454 0 : mLast = nsnull;
455 : }
456 : else {
457 0 : NS_ASSERTION(endNode->IsNodeOfType(nsINode::eCONTENT),
458 : "Data node that's not content?");
459 :
460 0 : mLast = static_cast<nsIContent*>(endNode);
461 : }
462 : }
463 : }
464 : else
465 : {
466 0 : PRInt32 indx = endIndx;
467 :
468 0 : cChild = endNode->GetChildAt(--indx);
469 :
470 0 : if (!cChild) // No child at offset!
471 : {
472 0 : NS_NOTREACHED("nsContentIterator::nsContentIterator");
473 0 : return NS_ERROR_FAILURE;
474 : }
475 :
476 0 : if (mPre)
477 : {
478 0 : mLast = GetDeepLastChild(cChild, nsnull);
479 :
480 0 : if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
481 0 : endNode, endIndx)) {
482 0 : mLast = nsnull;
483 : }
484 : }
485 : else { // post-order
486 0 : mLast = cChild;
487 : }
488 : }
489 :
490 : // If either first or last is null, they both
491 : // have to be null!
492 :
493 0 : if (!mFirst || !mLast)
494 : {
495 0 : mFirst = nsnull;
496 0 : mLast = nsnull;
497 : }
498 :
499 0 : mCurNode = mFirst;
500 0 : mIsDone = !mCurNode;
501 :
502 0 : if (!mCurNode)
503 0 : mIndexes.Clear();
504 : else
505 0 : RebuildIndexStack();
506 :
507 0 : return NS_OK;
508 : }
509 :
510 :
511 : /******************************************************
512 : * Helper routines
513 : ******************************************************/
514 : // WARNING: This function is expensive
515 0 : nsresult nsContentIterator::RebuildIndexStack()
516 : {
517 : // Make sure we start at the right indexes on the stack! Build array up
518 : // to common parent of start and end. Perhaps it's too many entries, but
519 : // that's far better than too few.
520 : nsINode* parent;
521 : nsINode* current;
522 :
523 0 : mIndexes.Clear();
524 0 : current = mCurNode;
525 0 : if (!current) {
526 0 : return NS_OK;
527 : }
528 :
529 0 : while (current != mCommonParent)
530 : {
531 0 : parent = current->GetNodeParent();
532 :
533 0 : if (!parent)
534 0 : return NS_ERROR_FAILURE;
535 :
536 0 : mIndexes.InsertElementAt(0, parent->IndexOf(current));
537 :
538 0 : current = parent;
539 : }
540 0 : return NS_OK;
541 : }
542 :
543 : void
544 0 : nsContentIterator::MakeEmpty()
545 : {
546 0 : mCurNode = nsnull;
547 0 : mFirst = nsnull;
548 0 : mLast = nsnull;
549 0 : mCommonParent = nsnull;
550 0 : mIsDone = true;
551 0 : mIndexes.Clear();
552 0 : }
553 :
554 : nsINode*
555 10 : nsContentIterator::GetDeepFirstChild(nsINode *aRoot,
556 : nsTArray<PRInt32> *aIndexes)
557 : {
558 10 : if (!aRoot) {
559 0 : return nsnull;
560 : }
561 :
562 10 : nsINode *n = aRoot;
563 10 : nsINode *nChild = n->GetFirstChild();
564 :
565 22 : while (nChild)
566 : {
567 2 : if (aIndexes)
568 : {
569 : // Add this node to the stack of indexes
570 0 : aIndexes->AppendElement(0);
571 : }
572 2 : n = nChild;
573 2 : nChild = n->GetFirstChild();
574 : }
575 :
576 10 : return n;
577 : }
578 :
579 : nsINode*
580 10 : nsContentIterator::GetDeepLastChild(nsINode *aRoot, nsTArray<PRInt32> *aIndexes)
581 : {
582 10 : if (!aRoot) {
583 0 : return nsnull;
584 : }
585 :
586 10 : nsINode *deepLastChild = aRoot;
587 :
588 10 : nsINode *n = aRoot;
589 10 : PRInt32 numChildren = n->GetChildCount();
590 :
591 22 : while (numChildren)
592 : {
593 2 : nsINode *nChild = n->GetChildAt(--numChildren);
594 :
595 2 : if (aIndexes)
596 : {
597 : // Add this node to the stack of indexes
598 0 : aIndexes->AppendElement(numChildren);
599 : }
600 2 : numChildren = nChild->GetChildCount();
601 2 : n = nChild;
602 :
603 2 : deepLastChild = n;
604 : }
605 :
606 10 : return deepLastChild;
607 : }
608 :
609 : // Get the next sibling, or parents next sibling, or grandpa's next sibling...
610 : nsINode *
611 2 : nsContentIterator::GetNextSibling(nsINode *aNode,
612 : nsTArray<PRInt32> *aIndexes)
613 : {
614 2 : if (!aNode)
615 0 : return nsnull;
616 :
617 2 : nsINode *parent = aNode->GetNodeParent();
618 2 : if (!parent)
619 0 : return nsnull;
620 :
621 2 : PRInt32 indx = 0;
622 :
623 2 : NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
624 : "ContentIterator stack underflow");
625 2 : if (aIndexes && !aIndexes->IsEmpty())
626 : {
627 : // use the last entry on the Indexes array for the current index
628 0 : indx = (*aIndexes)[aIndexes->Length()-1];
629 : }
630 : else
631 2 : indx = mCachedIndex;
632 :
633 : // reverify that the index of the current node hasn't changed.
634 : // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
635 : // ignore result this time - the index may now be out of range.
636 2 : nsINode *sib = parent->GetChildAt(indx);
637 2 : if (sib != aNode)
638 : {
639 : // someone changed our index - find the new index the painful way
640 2 : indx = parent->IndexOf(aNode);
641 : }
642 :
643 : // indx is now canonically correct
644 2 : if ((sib = parent->GetChildAt(++indx)))
645 : {
646 : // update index cache
647 2 : if (aIndexes && !aIndexes->IsEmpty())
648 : {
649 0 : aIndexes->ElementAt(aIndexes->Length()-1) = indx;
650 : }
651 2 : else mCachedIndex = indx;
652 : }
653 : else
654 : {
655 0 : if (parent != mCommonParent)
656 : {
657 0 : if (aIndexes)
658 : {
659 : // pop node off the stack, go up one level and return parent or fail.
660 : // Don't leave the index empty, especially if we're
661 : // returning NULL. This confuses other parts of the code.
662 0 : if (aIndexes->Length() > 1)
663 0 : aIndexes->RemoveElementAt(aIndexes->Length()-1);
664 : }
665 : }
666 :
667 : // ok to leave cache out of date here if parent == mCommonParent?
668 0 : sib = GetNextSibling(parent, aIndexes);
669 : }
670 :
671 2 : return sib;
672 : }
673 :
674 : // Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
675 : nsINode*
676 6 : nsContentIterator::GetPrevSibling(nsINode *aNode,
677 : nsTArray<PRInt32> *aIndexes)
678 : {
679 6 : if (!aNode)
680 0 : return nsnull;
681 :
682 6 : nsINode *parent = aNode->GetNodeParent();
683 6 : if (!parent)
684 0 : return nsnull;
685 :
686 6 : PRInt32 indx = 0;
687 :
688 6 : NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
689 : "ContentIterator stack underflow");
690 6 : if (aIndexes && !aIndexes->IsEmpty())
691 : {
692 : // use the last entry on the Indexes array for the current index
693 0 : indx = (*aIndexes)[aIndexes->Length()-1];
694 : }
695 : else
696 6 : indx = mCachedIndex;
697 :
698 : // reverify that the index of the current node hasn't changed
699 : // ignore result this time - the index may now be out of range.
700 6 : nsINode *sib = parent->GetChildAt(indx);
701 6 : if (sib != aNode)
702 : {
703 : // someone changed our index - find the new index the painful way
704 6 : indx = parent->IndexOf(aNode);
705 : }
706 :
707 : // indx is now canonically correct
708 6 : if (indx > 0 && (sib = parent->GetChildAt(--indx)))
709 : {
710 : // update index cache
711 6 : if (aIndexes && !aIndexes->IsEmpty())
712 : {
713 0 : aIndexes->ElementAt(aIndexes->Length()-1) = indx;
714 : }
715 6 : else mCachedIndex = indx;
716 : }
717 0 : else if (parent != mCommonParent)
718 : {
719 0 : if (aIndexes && !aIndexes->IsEmpty())
720 : {
721 : // pop node off the stack, go up one level and try again.
722 0 : aIndexes->RemoveElementAt(aIndexes->Length()-1);
723 : }
724 0 : return GetPrevSibling(parent, aIndexes);
725 : }
726 :
727 6 : return sib;
728 : }
729 :
730 : nsINode*
731 0 : nsContentIterator::NextNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes)
732 : {
733 0 : nsINode *n = aNode;
734 0 : nsINode *nextNode = nsnull;
735 :
736 0 : if (mPre) // if we are a Pre-order iterator, use pre-order
737 : {
738 : // if it has children then next node is first child
739 0 : if (NodeHasChildren(n))
740 : {
741 0 : nsINode *nFirstChild = n->GetFirstChild();
742 :
743 : // update cache
744 0 : if (aIndexes)
745 : {
746 : // push an entry on the index stack
747 0 : aIndexes->AppendElement(0);
748 : }
749 0 : else mCachedIndex = 0;
750 :
751 0 : return nFirstChild;
752 : }
753 :
754 : // else next sibling is next
755 0 : nextNode = GetNextSibling(n, aIndexes);
756 : }
757 : else // post-order
758 : {
759 0 : nsINode *parent = n->GetNodeParent();
760 0 : nsINode *nSibling = nsnull;
761 0 : PRInt32 indx = 0;
762 :
763 : // get the cached index
764 0 : NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
765 : "ContentIterator stack underflow");
766 0 : if (aIndexes && !aIndexes->IsEmpty())
767 : {
768 : // use the last entry on the Indexes array for the current index
769 0 : indx = (*aIndexes)[aIndexes->Length()-1];
770 : }
771 0 : else indx = mCachedIndex;
772 :
773 : // reverify that the index of the current node hasn't changed.
774 : // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
775 : // ignore result this time - the index may now be out of range.
776 0 : if (indx >= 0)
777 0 : nSibling = parent->GetChildAt(indx);
778 0 : if (nSibling != n)
779 : {
780 : // someone changed our index - find the new index the painful way
781 0 : indx = parent->IndexOf(n);
782 : }
783 :
784 : // indx is now canonically correct
785 0 : nSibling = parent->GetChildAt(++indx);
786 0 : if (nSibling)
787 : {
788 : // update cache
789 0 : if (aIndexes && !aIndexes->IsEmpty())
790 : {
791 : // replace an entry on the index stack
792 0 : aIndexes->ElementAt(aIndexes->Length()-1) = indx;
793 : }
794 0 : else mCachedIndex = indx;
795 :
796 : // next node is siblings "deep left" child
797 0 : return GetDeepFirstChild(nSibling, aIndexes);
798 : }
799 :
800 : // else it's the parent
801 : // update cache
802 0 : if (aIndexes)
803 : {
804 : // pop an entry off the index stack
805 : // Don't leave the index empty, especially if we're
806 : // returning NULL. This confuses other parts of the code.
807 0 : if (aIndexes->Length() > 1)
808 0 : aIndexes->RemoveElementAt(aIndexes->Length()-1);
809 : }
810 0 : else mCachedIndex = 0; // this might be wrong, but we are better off guessing
811 0 : nextNode = parent;
812 : }
813 :
814 0 : return nextNode;
815 : }
816 :
817 : nsINode*
818 4 : nsContentIterator::PrevNode(nsINode *aNode, nsTArray<PRInt32> *aIndexes)
819 : {
820 4 : nsINode *prevNode = nsnull;
821 4 : nsINode *n = aNode;
822 :
823 4 : if (mPre) // if we are a Pre-order iterator, use pre-order
824 : {
825 0 : nsINode *parent = n->GetNodeParent();
826 0 : nsINode *nSibling = nsnull;
827 0 : PRInt32 indx = 0;
828 :
829 : // get the cached index
830 0 : NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
831 : "ContentIterator stack underflow");
832 0 : if (aIndexes && !aIndexes->IsEmpty())
833 : {
834 : // use the last entry on the Indexes array for the current index
835 0 : indx = (*aIndexes)[aIndexes->Length()-1];
836 : }
837 0 : else indx = mCachedIndex;
838 :
839 : // reverify that the index of the current node hasn't changed.
840 : // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
841 : // ignore result this time - the index may now be out of range.
842 0 : if (indx >= 0)
843 0 : nSibling = parent->GetChildAt(indx);
844 :
845 0 : if (nSibling != n)
846 : {
847 : // someone changed our index - find the new index the painful way
848 0 : indx = parent->IndexOf(n);
849 : }
850 :
851 : // indx is now canonically correct
852 0 : if (indx && (nSibling = parent->GetChildAt(--indx)))
853 : {
854 : // update cache
855 0 : if (aIndexes && !aIndexes->IsEmpty())
856 : {
857 : // replace an entry on the index stack
858 0 : aIndexes->ElementAt(aIndexes->Length()-1) = indx;
859 : }
860 0 : else mCachedIndex = indx;
861 :
862 : // prev node is siblings "deep right" child
863 0 : return GetDeepLastChild(nSibling, aIndexes);
864 : }
865 :
866 : // else it's the parent
867 : // update cache
868 0 : if (aIndexes && !aIndexes->IsEmpty())
869 : {
870 : // pop an entry off the index stack
871 0 : aIndexes->RemoveElementAt(aIndexes->Length()-1);
872 : }
873 0 : else mCachedIndex = 0; // this might be wrong, but we are better off guessing
874 0 : prevNode = parent;
875 : }
876 : else // post-order
877 : {
878 4 : PRInt32 numChildren = n->GetChildCount();
879 :
880 : // if it has children then prev node is last child
881 4 : if (numChildren)
882 : {
883 0 : nsINode *nLastChild = n->GetLastChild();
884 0 : numChildren--;
885 :
886 : // update cache
887 0 : if (aIndexes)
888 : {
889 : // push an entry on the index stack
890 0 : aIndexes->AppendElement(numChildren);
891 : }
892 0 : else mCachedIndex = numChildren;
893 :
894 0 : return nLastChild;
895 : }
896 :
897 : // else prev sibling is previous
898 4 : prevNode = GetPrevSibling(n, aIndexes);
899 : }
900 :
901 4 : return prevNode;
902 : }
903 :
904 : /******************************************************
905 : * ContentIterator routines
906 : ******************************************************/
907 :
908 : void
909 0 : nsContentIterator::First()
910 : {
911 0 : if (mFirst) {
912 : #ifdef DEBUG
913 : nsresult rv =
914 : #endif
915 0 : PositionAt(mFirst);
916 :
917 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
918 : }
919 :
920 0 : mIsDone = mFirst == nsnull;
921 0 : }
922 :
923 :
924 : void
925 0 : nsContentIterator::Last()
926 : {
927 0 : NS_ASSERTION(mLast, "No last node!");
928 :
929 0 : if (mLast) {
930 : #ifdef DEBUG
931 : nsresult rv =
932 : #endif
933 0 : PositionAt(mLast);
934 :
935 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
936 : }
937 :
938 0 : mIsDone = mLast == nsnull;
939 0 : }
940 :
941 :
942 : void
943 0 : nsContentIterator::Next()
944 : {
945 0 : if (mIsDone || !mCurNode)
946 0 : return;
947 :
948 0 : if (mCurNode == mLast)
949 : {
950 0 : mIsDone = true;
951 0 : return;
952 : }
953 :
954 0 : mCurNode = NextNode(mCurNode, &mIndexes);
955 : }
956 :
957 :
958 : void
959 0 : nsContentIterator::Prev()
960 : {
961 0 : if (mIsDone || !mCurNode)
962 0 : return;
963 :
964 0 : if (mCurNode == mFirst)
965 : {
966 0 : mIsDone = true;
967 0 : return;
968 : }
969 :
970 0 : mCurNode = PrevNode(mCurNode, &mIndexes);
971 : }
972 :
973 :
974 : bool
975 16 : nsContentIterator::IsDone()
976 : {
977 16 : return mIsDone;
978 : }
979 :
980 :
981 : // Keeping arrays of indexes for the stack of nodes makes PositionAt
982 : // interesting...
983 : nsresult
984 0 : nsContentIterator::PositionAt(nsINode* aCurNode)
985 : {
986 0 : if (!aCurNode)
987 0 : return NS_ERROR_NULL_POINTER;
988 :
989 0 : nsINode *newCurNode = aCurNode;
990 0 : nsINode *tempNode = mCurNode;
991 :
992 0 : mCurNode = aCurNode;
993 : // take an early out if this doesn't actually change the position
994 0 : if (mCurNode == tempNode)
995 : {
996 0 : mIsDone = false; // paranoia
997 0 : return NS_OK;
998 : }
999 :
1000 : // Check to see if the node falls within the traversal range.
1001 :
1002 0 : nsINode* firstNode = mFirst;
1003 0 : nsINode* lastNode = mLast;
1004 0 : PRInt32 firstOffset=0, lastOffset=0;
1005 :
1006 0 : if (firstNode && lastNode)
1007 : {
1008 0 : if (mPre)
1009 : {
1010 0 : firstNode = NodeToParentOffset(mFirst, &firstOffset);
1011 :
1012 0 : if (lastNode->GetChildCount())
1013 0 : lastOffset = 0;
1014 : else
1015 : {
1016 0 : lastNode = NodeToParentOffset(mLast, &lastOffset);
1017 0 : ++lastOffset;
1018 : }
1019 : }
1020 : else
1021 : {
1022 0 : PRUint32 numChildren = firstNode->GetChildCount();
1023 :
1024 0 : if (numChildren)
1025 0 : firstOffset = numChildren;
1026 : else
1027 0 : firstNode = NodeToParentOffset(mFirst, &firstOffset);
1028 :
1029 0 : lastNode = NodeToParentOffset(mLast, &lastOffset);
1030 0 : ++lastOffset;
1031 : }
1032 : }
1033 :
1034 : // The end positions are always in the range even if it has no parent.
1035 : // We need to allow that or 'iter->Init(root)' would assert in Last()
1036 : // or First() for example, bug 327694.
1037 0 : if (mFirst != mCurNode && mLast != mCurNode &&
1038 : (!firstNode || !lastNode ||
1039 : !NodeIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset,
1040 0 : lastNode, lastOffset)))
1041 : {
1042 0 : mIsDone = true;
1043 0 : return NS_ERROR_FAILURE;
1044 : }
1045 :
1046 : // We can be at ANY node in the sequence.
1047 : // Need to regenerate the array of indexes back to the root or common parent!
1048 0 : nsAutoTArray<nsINode*, 8> oldParentStack;
1049 0 : nsAutoTArray<PRInt32, 8> newIndexes;
1050 :
1051 : // Get a list of the parents up to the root, then compare the new node
1052 : // with entries in that array until we find a match (lowest common
1053 : // ancestor). If no match, use IndexOf, take the parent, and repeat.
1054 : // This avoids using IndexOf() N times on possibly large arrays. We
1055 : // still end up doing it a fair bit. It's better to use Clone() if
1056 : // possible.
1057 :
1058 : // we know the depth we're down (though we may not have started at the
1059 : // top).
1060 0 : if (!oldParentStack.SetCapacity(mIndexes.Length()+1))
1061 0 : return NS_ERROR_FAILURE;
1062 :
1063 : // We want to loop mIndexes.Length() + 1 times here, because we want to make
1064 : // sure we include mCommonParent in the oldParentStack, for use in the next
1065 : // for loop, and mIndexes only has entries for nodes from tempNode up through
1066 : // an ancestor of tempNode that's a child of mCommonParent.
1067 0 : for (PRInt32 i = mIndexes.Length()+1; i > 0 && tempNode; i--)
1068 : {
1069 : // Insert at head since we're walking up
1070 0 : oldParentStack.InsertElementAt(0, tempNode);
1071 :
1072 0 : nsINode *parent = tempNode->GetNodeParent();
1073 :
1074 0 : if (!parent) // this node has no parent, and thus no index
1075 0 : break;
1076 :
1077 0 : if (parent == mCurNode)
1078 : {
1079 : // The position was moved to a parent of the current position.
1080 : // All we need to do is drop some indexes. Shortcut here.
1081 0 : mIndexes.RemoveElementsAt(mIndexes.Length() - oldParentStack.Length(),
1082 0 : oldParentStack.Length());
1083 0 : mIsDone = false;
1084 0 : return NS_OK;
1085 : }
1086 0 : tempNode = parent;
1087 : }
1088 :
1089 : // Ok. We have the array of old parents. Look for a match.
1090 0 : while (newCurNode)
1091 : {
1092 0 : nsINode *parent = newCurNode->GetNodeParent();
1093 :
1094 0 : if (!parent) // this node has no parent, and thus no index
1095 0 : break;
1096 :
1097 0 : PRInt32 indx = parent->IndexOf(newCurNode);
1098 :
1099 : // insert at the head!
1100 0 : newIndexes.InsertElementAt(0, indx);
1101 :
1102 : // look to see if the parent is in the stack
1103 0 : indx = oldParentStack.IndexOf(parent);
1104 0 : if (indx >= 0)
1105 : {
1106 : // ok, the parent IS on the old stack! Rework things.
1107 : // we want newIndexes to replace all nodes equal to or below the match
1108 : // Note that index oldParentStack.Length()-1 is the last node, which is
1109 : // one BELOW the last index in the mIndexes stack. In other words, we
1110 : // want to remove elements starting at index (indx+1).
1111 0 : PRInt32 numToDrop = oldParentStack.Length()-(1+indx);
1112 0 : if (numToDrop > 0)
1113 0 : mIndexes.RemoveElementsAt(mIndexes.Length() - numToDrop, numToDrop);
1114 0 : mIndexes.AppendElements(newIndexes);
1115 :
1116 0 : break;
1117 : }
1118 0 : newCurNode = parent;
1119 : }
1120 :
1121 : // phew!
1122 :
1123 0 : mIsDone = false;
1124 0 : return NS_OK;
1125 : }
1126 :
1127 : nsINode*
1128 13 : nsContentIterator::GetCurrentNode()
1129 : {
1130 13 : if (mIsDone) {
1131 0 : return nsnull;
1132 : }
1133 :
1134 13 : NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
1135 :
1136 13 : return mCurNode;
1137 : }
1138 :
1139 :
1140 :
1141 :
1142 :
1143 : /*====================================================================================*/
1144 : /*====================================================================================*/
1145 :
1146 :
1147 :
1148 :
1149 :
1150 :
1151 : /******************************************************
1152 : * nsContentSubtreeIterator
1153 : ******************************************************/
1154 :
1155 :
1156 : /*
1157 : * A simple iterator class for traversing the content in "top subtree" order
1158 : */
1159 : class nsContentSubtreeIterator : public nsContentIterator
1160 : {
1161 : public:
1162 6 : nsContentSubtreeIterator() : nsContentIterator(false) {}
1163 24 : virtual ~nsContentSubtreeIterator() {}
1164 :
1165 : NS_DECL_ISUPPORTS_INHERITED
1166 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1167 :
1168 : // nsContentIterator overrides ------------------------------
1169 :
1170 : virtual nsresult Init(nsINode* aRoot);
1171 :
1172 : virtual nsresult Init(nsIDOMRange* aRange);
1173 :
1174 : virtual void Next();
1175 :
1176 : virtual void Prev();
1177 :
1178 : virtual nsresult PositionAt(nsINode* aCurNode);
1179 :
1180 : // Must override these because we don't do PositionAt
1181 : virtual void First();
1182 :
1183 : // Must override these because we don't do PositionAt
1184 : virtual void Last();
1185 :
1186 : protected:
1187 :
1188 : nsresult GetTopAncestorInRange(nsINode *aNode,
1189 : nsCOMPtr<nsINode> *outAnestor);
1190 :
1191 : // no copy's or assigns FIX ME
1192 : nsContentSubtreeIterator(const nsContentSubtreeIterator&);
1193 : nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
1194 :
1195 : nsRefPtr<nsRange> mRange;
1196 : // these arrays all typically are used and have elements
1197 : #if 0
1198 : nsAutoTArray<nsIContent*, 8> mStartNodes;
1199 : nsAutoTArray<PRInt32, 8> mStartOffsets;
1200 : #endif
1201 :
1202 : nsAutoTArray<nsIContent*, 8> mEndNodes;
1203 : nsAutoTArray<PRInt32, 8> mEndOffsets;
1204 : };
1205 :
1206 12 : NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1207 12 : NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1208 :
1209 12 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator)
1210 6 : NS_INTERFACE_MAP_END_INHERITING(nsContentIterator)
1211 :
1212 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSubtreeIterator)
1213 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1214 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRange, nsIDOMRange)
1215 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1216 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1217 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRange)
1218 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1219 :
1220 : nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
1221 :
1222 :
1223 :
1224 :
1225 : /******************************************************
1226 : * repository cruft
1227 : ******************************************************/
1228 :
1229 6 : nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult)
1230 : {
1231 6 : nsContentIterator * iter = new nsContentSubtreeIterator();
1232 6 : if (!iter) {
1233 0 : return NS_ERROR_OUT_OF_MEMORY;
1234 : }
1235 :
1236 6 : NS_ADDREF(*aInstancePtrResult = iter);
1237 :
1238 6 : return NS_OK;
1239 : }
1240 :
1241 :
1242 :
1243 : /******************************************************
1244 : * Init routines
1245 : ******************************************************/
1246 :
1247 :
1248 0 : nsresult nsContentSubtreeIterator::Init(nsINode* aRoot)
1249 : {
1250 0 : return NS_ERROR_NOT_IMPLEMENTED;
1251 : }
1252 :
1253 :
1254 6 : nsresult nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
1255 : {
1256 6 : if (!aRange)
1257 0 : return NS_ERROR_NULL_POINTER;
1258 :
1259 6 : mIsDone = false;
1260 :
1261 6 : mRange = static_cast<nsRange*>(aRange);
1262 :
1263 : // get the start node and offset, convert to nsINode
1264 12 : nsCOMPtr<nsIDOMNode> commonParent;
1265 12 : nsCOMPtr<nsIDOMNode> startParent;
1266 12 : nsCOMPtr<nsIDOMNode> endParent;
1267 12 : nsCOMPtr<nsINode> nStartP;
1268 12 : nsCOMPtr<nsINode> nEndP;
1269 12 : nsCOMPtr<nsINode> n;
1270 6 : nsINode *firstCandidate = nsnull;
1271 6 : nsINode *lastCandidate = nsnull;
1272 : PRInt32 indx, startIndx, endIndx;
1273 :
1274 : // get common content parent
1275 6 : if (NS_FAILED(aRange->GetCommonAncestorContainer(getter_AddRefs(commonParent))) || !commonParent)
1276 0 : return NS_ERROR_FAILURE;
1277 6 : mCommonParent = do_QueryInterface(commonParent);
1278 :
1279 : // get start content parent
1280 6 : if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(startParent))) || !startParent)
1281 0 : return NS_ERROR_FAILURE;
1282 6 : nStartP = do_QueryInterface(startParent);
1283 6 : aRange->GetStartOffset(&startIndx);
1284 :
1285 : // get end content parent
1286 6 : if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(endParent))) || !endParent)
1287 0 : return NS_ERROR_FAILURE;
1288 6 : nEndP = do_QueryInterface(endParent);
1289 6 : aRange->GetEndOffset(&endIndx);
1290 :
1291 : // short circuit when start node == end node
1292 6 : if (startParent == endParent)
1293 : {
1294 4 : nsINode* nChild = nStartP->GetFirstChild();
1295 :
1296 4 : if (!nChild) // no children, must be a text node or empty container
1297 : {
1298 : // all inside one text node - empty subtree iterator
1299 0 : MakeEmpty();
1300 0 : return NS_OK;
1301 : }
1302 : else
1303 : {
1304 4 : if (startIndx == endIndx) // collapsed range
1305 : {
1306 0 : MakeEmpty();
1307 0 : return NS_OK;
1308 : }
1309 : }
1310 : }
1311 :
1312 : // cache ancestors
1313 : #if 0
1314 : nsContentUtils::GetAncestorsAndOffsets(startParent, startIndx,
1315 : &mStartNodes, &mStartOffsets);
1316 : #endif
1317 : nsContentUtils::GetAncestorsAndOffsets(endParent, endIndx,
1318 6 : &mEndNodes, &mEndOffsets);
1319 :
1320 : // find first node in range
1321 6 : aRange->GetStartOffset(&indx);
1322 :
1323 6 : if (!nStartP->GetChildCount()) // no children, start at the node itself
1324 : {
1325 2 : n = nStartP;
1326 : }
1327 : else
1328 : {
1329 4 : nsINode* nChild = nStartP->GetChildAt(indx);
1330 4 : if (!nChild) // offset after last child
1331 : {
1332 0 : n = nStartP;
1333 : }
1334 : else
1335 : {
1336 4 : firstCandidate = nChild;
1337 : }
1338 : }
1339 :
1340 6 : if (!firstCandidate)
1341 : {
1342 : // then firstCandidate is next node after cN
1343 2 : firstCandidate = GetNextSibling(n, nsnull);
1344 :
1345 2 : if (!firstCandidate)
1346 : {
1347 0 : MakeEmpty();
1348 0 : return NS_OK;
1349 : }
1350 : }
1351 :
1352 6 : firstCandidate = GetDeepFirstChild(firstCandidate, nsnull);
1353 :
1354 : // confirm that this first possible contained node
1355 : // is indeed contained. Else we have a range that
1356 : // does not fully contain any node.
1357 :
1358 : bool nodeBefore, nodeAfter;
1359 6 : if (NS_FAILED(nsRange::CompareNodeToRange(firstCandidate, mRange,
1360 : &nodeBefore, &nodeAfter)))
1361 0 : return NS_ERROR_FAILURE;
1362 :
1363 6 : if (nodeBefore || nodeAfter)
1364 : {
1365 0 : MakeEmpty();
1366 0 : return NS_OK;
1367 : }
1368 :
1369 : // cool, we have the first node in the range. Now we walk
1370 : // up its ancestors to find the most senior that is still
1371 : // in the range. That's the real first node.
1372 6 : if (NS_FAILED(GetTopAncestorInRange(firstCandidate, address_of(mFirst))))
1373 0 : return NS_ERROR_FAILURE;
1374 :
1375 : // now to find the last node
1376 6 : aRange->GetEndOffset(&indx);
1377 6 : PRInt32 numChildren = nEndP->GetChildCount();
1378 :
1379 6 : if (indx > numChildren) indx = numChildren;
1380 6 : if (!indx)
1381 : {
1382 2 : n = nEndP;
1383 : }
1384 : else
1385 : {
1386 4 : if (!numChildren) // no children, must be a text node
1387 : {
1388 0 : n = nEndP;
1389 : }
1390 : else
1391 : {
1392 4 : lastCandidate = nEndP->GetChildAt(--indx);
1393 4 : NS_ASSERTION(lastCandidate,
1394 : "tree traversal trouble in nsContentSubtreeIterator::Init");
1395 : }
1396 : }
1397 :
1398 6 : if (!lastCandidate)
1399 : {
1400 : // then lastCandidate is prev node before n
1401 2 : lastCandidate = GetPrevSibling(n, nsnull);
1402 : }
1403 :
1404 6 : lastCandidate = GetDeepLastChild(lastCandidate, nsnull);
1405 :
1406 : // confirm that this last possible contained node
1407 : // is indeed contained. Else we have a range that
1408 : // does not fully contain any node.
1409 :
1410 6 : if (NS_FAILED(nsRange::CompareNodeToRange(lastCandidate, mRange, &nodeBefore,
1411 : &nodeAfter)))
1412 0 : return NS_ERROR_FAILURE;
1413 :
1414 6 : if (nodeBefore || nodeAfter)
1415 : {
1416 0 : MakeEmpty();
1417 0 : return NS_OK;
1418 : }
1419 :
1420 : // cool, we have the last node in the range. Now we walk
1421 : // up its ancestors to find the most senior that is still
1422 : // in the range. That's the real first node.
1423 6 : if (NS_FAILED(GetTopAncestorInRange(lastCandidate, address_of(mLast))))
1424 0 : return NS_ERROR_FAILURE;
1425 :
1426 6 : mCurNode = mFirst;
1427 :
1428 6 : return NS_OK;
1429 : }
1430 :
1431 : /****************************************************************
1432 : * nsContentSubtreeIterator overrides of ContentIterator routines
1433 : ****************************************************************/
1434 :
1435 : // we can't call PositionAt in a subtree iterator...
1436 : void
1437 4 : nsContentSubtreeIterator::First()
1438 : {
1439 4 : mIsDone = mFirst == nsnull;
1440 :
1441 4 : mCurNode = mFirst;
1442 4 : }
1443 :
1444 : // we can't call PositionAt in a subtree iterator...
1445 : void
1446 6 : nsContentSubtreeIterator::Last()
1447 : {
1448 6 : mIsDone = mLast == nsnull;
1449 :
1450 6 : mCurNode = mLast;
1451 6 : }
1452 :
1453 :
1454 : void
1455 0 : nsContentSubtreeIterator::Next()
1456 : {
1457 0 : if (mIsDone || !mCurNode)
1458 0 : return;
1459 :
1460 0 : if (mCurNode == mLast)
1461 : {
1462 0 : mIsDone = true;
1463 0 : return;
1464 : }
1465 :
1466 0 : nsINode *nextNode = GetNextSibling(mCurNode, nsnull);
1467 0 : NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
1468 :
1469 : /*
1470 : nextNode = GetDeepFirstChild(nextNode);
1471 : return GetTopAncestorInRange(nextNode, address_of(mCurNode));
1472 : */
1473 0 : PRInt32 i = mEndNodes.IndexOf(nextNode);
1474 0 : while (i != -1)
1475 : {
1476 : // as long as we are finding ancestors of the endpoint of the range,
1477 : // dive down into their children
1478 0 : nextNode = nextNode->GetFirstChild();
1479 0 : NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
1480 :
1481 : // should be impossible to get a null pointer. If we went all the way
1482 : // down the child chain to the bottom without finding an interior node,
1483 : // then the previous node should have been the last, which was
1484 : // was tested at top of routine.
1485 0 : i = mEndNodes.IndexOf(nextNode);
1486 : }
1487 :
1488 0 : mCurNode = nextNode;
1489 :
1490 : // This shouldn't be needed, but since our selection code can put us
1491 : // in a situation where mLast is in generated content, we need this
1492 : // to stop the iterator when we've walked past past the last node!
1493 0 : mIsDone = mCurNode == nsnull;
1494 :
1495 0 : return;
1496 : }
1497 :
1498 :
1499 : void
1500 10 : nsContentSubtreeIterator::Prev()
1501 : {
1502 : // Prev should be optimized to use the mStartNodes, just as Next
1503 : // uses mEndNodes.
1504 10 : if (mIsDone || !mCurNode)
1505 0 : return;
1506 :
1507 10 : if (mCurNode == mFirst)
1508 : {
1509 6 : mIsDone = true;
1510 6 : return;
1511 : }
1512 :
1513 4 : nsINode *prevNode = PrevNode(GetDeepFirstChild(mCurNode, nsnull), nsnull);
1514 :
1515 4 : prevNode = GetDeepLastChild(prevNode, nsnull);
1516 :
1517 4 : GetTopAncestorInRange(prevNode, address_of(mCurNode));
1518 :
1519 : // This shouldn't be needed, but since our selection code can put us
1520 : // in a situation where mFirst is in generated content, we need this
1521 : // to stop the iterator when we've walked past past the first node!
1522 4 : mIsDone = mCurNode == nsnull;
1523 : }
1524 :
1525 :
1526 : nsresult
1527 0 : nsContentSubtreeIterator::PositionAt(nsINode* aCurNode)
1528 : {
1529 0 : NS_ERROR("Not implemented!");
1530 :
1531 0 : return NS_ERROR_NOT_IMPLEMENTED;
1532 : }
1533 :
1534 : /****************************************************************
1535 : * nsContentSubtreeIterator helper routines
1536 : ****************************************************************/
1537 :
1538 : nsresult
1539 16 : nsContentSubtreeIterator::GetTopAncestorInRange(nsINode *aNode,
1540 : nsCOMPtr<nsINode> *outAncestor)
1541 : {
1542 16 : if (!aNode)
1543 0 : return NS_ERROR_NULL_POINTER;
1544 16 : if (!outAncestor)
1545 0 : return NS_ERROR_NULL_POINTER;
1546 :
1547 :
1548 : // sanity check: aNode is itself in the range
1549 : bool nodeBefore, nodeAfter;
1550 16 : if (NS_FAILED(nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore,
1551 : &nodeAfter)))
1552 0 : return NS_ERROR_FAILURE;
1553 :
1554 16 : if (nodeBefore || nodeAfter)
1555 0 : return NS_ERROR_FAILURE;
1556 :
1557 32 : nsCOMPtr<nsINode> parent, tmp;
1558 36 : while (aNode)
1559 : {
1560 20 : parent = aNode->GetNodeParent();
1561 20 : if (!parent)
1562 : {
1563 0 : if (tmp)
1564 : {
1565 0 : *outAncestor = tmp;
1566 0 : return NS_OK;
1567 : }
1568 0 : else return NS_ERROR_FAILURE;
1569 : }
1570 20 : if (NS_FAILED(nsRange::CompareNodeToRange(parent, mRange, &nodeBefore,
1571 : &nodeAfter)))
1572 0 : return NS_ERROR_FAILURE;
1573 :
1574 20 : if (nodeBefore || nodeAfter)
1575 : {
1576 16 : *outAncestor = aNode;
1577 16 : return NS_OK;
1578 : }
1579 4 : tmp = aNode;
1580 4 : aNode = parent;
1581 : }
1582 0 : return NS_ERROR_FAILURE;
1583 4392 : }
1584 :
|