Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsISupports.h"
7 #include "nsIDOMNodeList.h"
8 #include "nsIContentIterator.h"
9 #include "nsRange.h"
10 #include "nsIContent.h"
11 #include "nsCOMPtr.h"
12 #include "nsTArray.h"
13 #include "nsContentUtils.h"
14 #include "nsINode.h"
15 #include "nsCycleCollectionParticipant.h"
17 // couple of utility static functs
19 ///////////////////////////////////////////////////////////////////////////
20 // NodeToParentOffset: returns the node's parent and offset.
21 //
23 static nsINode*
24 NodeToParentOffset(nsINode* aNode, int32_t* aOffset)
25 {
26 *aOffset = 0;
28 nsINode* parent = aNode->GetParentNode();
30 if (parent) {
31 *aOffset = parent->IndexOf(aNode);
32 }
34 return parent;
35 }
37 ///////////////////////////////////////////////////////////////////////////
38 // NodeIsInTraversalRange: returns true if content is visited during
39 // the traversal of the range in the specified mode.
40 //
41 static bool
42 NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
43 nsINode* aStartNode, int32_t aStartOffset,
44 nsINode* aEndNode, int32_t aEndOffset)
45 {
46 if (!aStartNode || !aEndNode || !aNode) {
47 return false;
48 }
50 // If a chardata node contains an end point of the traversal range, it is
51 // always in the traversal range.
52 if (aNode->IsNodeOfType(nsINode::eDATA_NODE) &&
53 (aNode == aStartNode || aNode == aEndNode)) {
54 return true;
55 }
57 nsINode* parent = aNode->GetParentNode();
58 if (!parent) {
59 return false;
60 }
62 int32_t indx = parent->IndexOf(aNode);
64 if (!aIsPreMode) {
65 ++indx;
66 }
68 return nsContentUtils::ComparePoints(aStartNode, aStartOffset,
69 parent, indx) <= 0 &&
70 nsContentUtils::ComparePoints(aEndNode, aEndOffset,
71 parent, indx) >= 0;
72 }
76 /*
77 * A simple iterator class for traversing the content in "close tag" order
78 */
79 class nsContentIterator : public nsIContentIterator
80 {
81 public:
82 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
83 NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator)
85 explicit nsContentIterator(bool aPre);
86 virtual ~nsContentIterator();
88 // nsIContentIterator interface methods ------------------------------
90 virtual nsresult Init(nsINode* aRoot);
92 virtual nsresult Init(nsIDOMRange* aRange);
94 virtual void First();
96 virtual void Last();
98 virtual void Next();
100 virtual void Prev();
102 virtual nsINode* GetCurrentNode();
104 virtual bool IsDone();
106 virtual nsresult PositionAt(nsINode* aCurNode);
108 protected:
110 // Recursively get the deepest first/last child of aRoot. This will return
111 // aRoot itself if it has no children.
112 nsINode* GetDeepFirstChild(nsINode* aRoot,
113 nsTArray<int32_t>* aIndexes = nullptr);
114 nsIContent* GetDeepFirstChild(nsIContent* aRoot,
115 nsTArray<int32_t>* aIndexes = nullptr);
116 nsINode* GetDeepLastChild(nsINode* aRoot,
117 nsTArray<int32_t>* aIndexes = nullptr);
118 nsIContent* GetDeepLastChild(nsIContent* aRoot,
119 nsTArray<int32_t>* aIndexes = nullptr);
121 // Get the next/previous sibling of aNode, or its parent's, or grandparent's,
122 // etc. Returns null if aNode and all its ancestors have no next/previous
123 // sibling.
124 nsIContent* GetNextSibling(nsINode* aNode,
125 nsTArray<int32_t>* aIndexes = nullptr);
126 nsIContent* GetPrevSibling(nsINode* aNode,
127 nsTArray<int32_t>* aIndexes = nullptr);
129 nsINode* NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes = nullptr);
130 nsINode* PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes = nullptr);
132 // WARNING: This function is expensive
133 nsresult RebuildIndexStack();
135 void MakeEmpty();
137 virtual void LastRelease();
139 nsCOMPtr<nsINode> mCurNode;
140 nsCOMPtr<nsINode> mFirst;
141 nsCOMPtr<nsINode> mLast;
142 nsCOMPtr<nsINode> mCommonParent;
144 // used by nsContentIterator to cache indices
145 nsAutoTArray<int32_t, 8> mIndexes;
147 // used by nsSubtreeIterator to cache indices. Why put them in the base
148 // class? Because otherwise I have to duplicate the routines GetNextSibling
149 // etc across both classes, with slight variations for caching. Or
150 // alternately, create a base class for the cache itself and have all the
151 // cache manipulation go through a vptr. I think this is the best space and
152 // speed combo, even though it's ugly.
153 int32_t mCachedIndex;
154 // another note about mCachedIndex: why should the subtree iterator use a
155 // trivial cached index instead of the mre robust array of indicies (which is
156 // what the basic content iterator uses)? The reason is that subtree
157 // iterators do not do much transitioning between parents and children. They
158 // tend to stay at the same level. In fact, you can prove (though I won't
159 // attempt it here) that they change levels at most n+m times, where n is the
160 // height of the parent hierarchy from the range start to the common
161 // ancestor, and m is the the height of the parent hierarchy from the range
162 // end to the common ancestor. If we used the index array, we would pay the
163 // price up front for n, and then pay the cost for m on the fly later on.
164 // With the simple cache, we only "pay as we go". Either way, we call
165 // IndexOf() once for each change of level in the hierarchy. Since a trivial
166 // index is much simpler, we use it for the subtree iterator.
168 bool mIsDone;
169 bool mPre;
171 private:
173 // no copies or assigns FIX ME
174 nsContentIterator(const nsContentIterator&);
175 nsContentIterator& operator=(const nsContentIterator&);
177 };
180 /******************************************************
181 * repository cruft
182 ******************************************************/
184 already_AddRefed<nsIContentIterator>
185 NS_NewContentIterator()
186 {
187 nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(false);
188 return iter.forget();
189 }
192 already_AddRefed<nsIContentIterator>
193 NS_NewPreContentIterator()
194 {
195 nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(true);
196 return iter.forget();
197 }
200 /******************************************************
201 * XPCOM cruft
202 ******************************************************/
204 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator)
205 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsContentIterator,
206 LastRelease())
208 NS_INTERFACE_MAP_BEGIN(nsContentIterator)
209 NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
210 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
211 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator)
212 NS_INTERFACE_MAP_END
214 NS_IMPL_CYCLE_COLLECTION(nsContentIterator,
215 mCurNode,
216 mFirst,
217 mLast,
218 mCommonParent)
220 void
221 nsContentIterator::LastRelease()
222 {
223 mCurNode = nullptr;
224 mFirst = nullptr;
225 mLast = nullptr;
226 mCommonParent = nullptr;
227 }
229 /******************************************************
230 * constructor/destructor
231 ******************************************************/
233 nsContentIterator::nsContentIterator(bool aPre) :
234 // don't need to explicitly initialize |nsCOMPtr|s, they will automatically
235 // be nullptr
236 mCachedIndex(0), mIsDone(false), mPre(aPre)
237 {
238 }
241 nsContentIterator::~nsContentIterator()
242 {
243 }
246 /******************************************************
247 * Init routines
248 ******************************************************/
251 nsresult
252 nsContentIterator::Init(nsINode* aRoot)
253 {
254 if (!aRoot) {
255 return NS_ERROR_NULL_POINTER;
256 }
258 mIsDone = false;
259 mIndexes.Clear();
261 if (mPre) {
262 mFirst = aRoot;
263 mLast = GetDeepLastChild(aRoot);
264 } else {
265 mFirst = GetDeepFirstChild(aRoot);
266 mLast = aRoot;
267 }
269 mCommonParent = aRoot;
270 mCurNode = mFirst;
271 RebuildIndexStack();
272 return NS_OK;
273 }
275 nsresult
276 nsContentIterator::Init(nsIDOMRange* aDOMRange)
277 {
278 NS_ENSURE_ARG_POINTER(aDOMRange);
279 nsRange* range = static_cast<nsRange*>(aDOMRange);
281 mIsDone = false;
283 // get common content parent
284 mCommonParent = range->GetCommonAncestor();
285 NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE);
287 // get the start node and offset
288 int32_t startIndx = range->StartOffset();
289 nsINode* startNode = range->GetStartParent();
290 NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
292 // get the end node and offset
293 int32_t endIndx = range->EndOffset();
294 nsINode* endNode = range->GetEndParent();
295 NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
297 bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
299 // short circuit when start node == end node
300 if (startNode == endNode) {
301 // Check to see if we have a collapsed range, if so, there is nothing to
302 // iterate over.
303 //
304 // XXX: CharacterDataNodes (text nodes) are currently an exception, since
305 // we always want to be able to iterate text nodes at the end points
306 // of a range.
308 if (!startIsData && startIndx == endIndx) {
309 MakeEmpty();
310 return NS_OK;
311 }
313 if (startIsData) {
314 // It's a character data node.
315 mFirst = startNode->AsContent();
316 mLast = mFirst;
317 mCurNode = mFirst;
319 RebuildIndexStack();
320 return NS_OK;
321 }
322 }
324 // Find first node in range.
326 nsIContent* cChild = nullptr;
328 if (!startIsData && startNode->HasChildren()) {
329 cChild = startNode->GetChildAt(startIndx);
330 }
332 if (!cChild) {
333 // no children, must be a text node
334 //
335 // XXXbz no children might also just mean no children. So I'm not
336 // sure what that comment above is talking about.
338 if (mPre) {
339 // XXX: In the future, if start offset is after the last
340 // character in the cdata node, should we set mFirst to
341 // the next sibling?
343 if (!startIsData) {
344 mFirst = GetNextSibling(startNode);
346 // Does mFirst node really intersect the range? The range could be
347 // 'degenerate', i.e., not collapsed but still contain no content.
349 if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode,
350 startIndx, endNode, endIndx)) {
351 mFirst = nullptr;
352 }
353 } else {
354 mFirst = startNode->AsContent();
355 }
356 } else {
357 // post-order
358 if (startNode->IsContent()) {
359 mFirst = startNode->AsContent();
360 } else {
361 // What else can we do?
362 mFirst = nullptr;
363 }
364 }
365 } else {
366 if (mPre) {
367 mFirst = cChild;
368 } else {
369 // post-order
370 mFirst = GetDeepFirstChild(cChild);
372 // Does mFirst node really intersect the range? The range could be
373 // 'degenerate', i.e., not collapsed but still contain no content.
375 if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
376 endNode, endIndx)) {
377 mFirst = nullptr;
378 }
379 }
380 }
383 // Find last node in range.
385 bool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);
387 if (endIsData || !endNode->HasChildren() || endIndx == 0) {
388 if (mPre) {
389 if (endNode->IsContent()) {
390 mLast = endNode->AsContent();
391 } else {
392 // Not much else to do here...
393 mLast = nullptr;
394 }
395 } else {
396 // post-order
397 //
398 // XXX: In the future, if end offset is before the first character in the
399 // cdata node, should we set mLast to the prev sibling?
401 if (!endIsData) {
402 mLast = GetPrevSibling(endNode);
404 if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
405 endNode, endIndx)) {
406 mLast = nullptr;
407 }
408 } else {
409 mLast = endNode->AsContent();
410 }
411 }
412 } else {
413 int32_t indx = endIndx;
415 cChild = endNode->GetChildAt(--indx);
417 if (!cChild) {
418 // No child at offset!
419 NS_NOTREACHED("nsContentIterator::nsContentIterator");
420 return NS_ERROR_FAILURE;
421 }
423 if (mPre) {
424 mLast = GetDeepLastChild(cChild);
426 if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
427 endNode, endIndx)) {
428 mLast = nullptr;
429 }
430 } else {
431 // post-order
432 mLast = cChild;
433 }
434 }
436 // If either first or last is null, they both have to be null!
438 if (!mFirst || !mLast) {
439 mFirst = nullptr;
440 mLast = nullptr;
441 }
443 mCurNode = mFirst;
444 mIsDone = !mCurNode;
446 if (!mCurNode) {
447 mIndexes.Clear();
448 } else {
449 RebuildIndexStack();
450 }
452 return NS_OK;
453 }
456 /******************************************************
457 * Helper routines
458 ******************************************************/
459 // WARNING: This function is expensive
460 nsresult
461 nsContentIterator::RebuildIndexStack()
462 {
463 // Make sure we start at the right indexes on the stack! Build array up
464 // to common parent of start and end. Perhaps it's too many entries, but
465 // that's far better than too few.
466 nsINode* parent;
467 nsINode* current;
469 mIndexes.Clear();
470 current = mCurNode;
471 if (!current) {
472 return NS_OK;
473 }
475 while (current != mCommonParent) {
476 parent = current->GetParentNode();
478 if (!parent) {
479 return NS_ERROR_FAILURE;
480 }
482 mIndexes.InsertElementAt(0, parent->IndexOf(current));
484 current = parent;
485 }
487 return NS_OK;
488 }
490 void
491 nsContentIterator::MakeEmpty()
492 {
493 mCurNode = nullptr;
494 mFirst = nullptr;
495 mLast = nullptr;
496 mCommonParent = nullptr;
497 mIsDone = true;
498 mIndexes.Clear();
499 }
501 nsINode*
502 nsContentIterator::GetDeepFirstChild(nsINode* aRoot,
503 nsTArray<int32_t>* aIndexes)
504 {
505 if (!aRoot || !aRoot->HasChildren()) {
506 return aRoot;
507 }
508 // We can't pass aRoot itself to the full GetDeepFirstChild, because that
509 // will only take nsIContent and aRoot might be a document. Pass aRoot's
510 // child, but be sure to preserve aIndexes.
511 if (aIndexes) {
512 aIndexes->AppendElement(0);
513 }
514 return GetDeepFirstChild(aRoot->GetFirstChild(), aIndexes);
515 }
517 nsIContent*
518 nsContentIterator::GetDeepFirstChild(nsIContent* aRoot,
519 nsTArray<int32_t>* aIndexes)
520 {
521 if (!aRoot) {
522 return nullptr;
523 }
525 nsIContent* node = aRoot;
526 nsIContent* child = node->GetFirstChild();
528 while (child) {
529 if (aIndexes) {
530 // Add this node to the stack of indexes
531 aIndexes->AppendElement(0);
532 }
533 node = child;
534 child = node->GetFirstChild();
535 }
537 return node;
538 }
540 nsINode*
541 nsContentIterator::GetDeepLastChild(nsINode* aRoot,
542 nsTArray<int32_t>* aIndexes)
543 {
544 if (!aRoot || !aRoot->HasChildren()) {
545 return aRoot;
546 }
547 // We can't pass aRoot itself to the full GetDeepLastChild, because that will
548 // only take nsIContent and aRoot might be a document. Pass aRoot's child,
549 // but be sure to preserve aIndexes.
550 if (aIndexes) {
551 aIndexes->AppendElement(aRoot->GetChildCount() - 1);
552 }
553 return GetDeepLastChild(aRoot->GetLastChild(), aIndexes);
554 }
556 nsIContent*
557 nsContentIterator::GetDeepLastChild(nsIContent* aRoot,
558 nsTArray<int32_t>* aIndexes)
559 {
560 if (!aRoot) {
561 return nullptr;
562 }
564 nsIContent* node = aRoot;
565 int32_t numChildren = node->GetChildCount();
567 while (numChildren) {
568 nsIContent* child = node->GetChildAt(--numChildren);
570 if (aIndexes) {
571 // Add this node to the stack of indexes
572 aIndexes->AppendElement(numChildren);
573 }
574 numChildren = child->GetChildCount();
575 node = child;
576 }
578 return node;
579 }
581 // Get the next sibling, or parent's next sibling, or grandpa's next sibling...
582 nsIContent*
583 nsContentIterator::GetNextSibling(nsINode* aNode,
584 nsTArray<int32_t>* aIndexes)
585 {
586 if (!aNode) {
587 return nullptr;
588 }
590 nsINode* parent = aNode->GetParentNode();
591 if (!parent) {
592 return nullptr;
593 }
595 int32_t indx = 0;
597 NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
598 "ContentIterator stack underflow");
599 if (aIndexes && !aIndexes->IsEmpty()) {
600 // use the last entry on the Indexes array for the current index
601 indx = (*aIndexes)[aIndexes->Length()-1];
602 } else {
603 indx = mCachedIndex;
604 }
606 // reverify that the index of the current node hasn't changed.
607 // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
608 // ignore result this time - the index may now be out of range.
609 nsIContent* sib = parent->GetChildAt(indx);
610 if (sib != aNode) {
611 // someone changed our index - find the new index the painful way
612 indx = parent->IndexOf(aNode);
613 }
615 // indx is now canonically correct
616 if ((sib = parent->GetChildAt(++indx))) {
617 // update index cache
618 if (aIndexes && !aIndexes->IsEmpty()) {
619 aIndexes->ElementAt(aIndexes->Length()-1) = indx;
620 } else {
621 mCachedIndex = indx;
622 }
623 } else {
624 if (parent != mCommonParent) {
625 if (aIndexes) {
626 // pop node off the stack, go up one level and return parent or fail.
627 // Don't leave the index empty, especially if we're
628 // returning nullptr. This confuses other parts of the code.
629 if (aIndexes->Length() > 1) {
630 aIndexes->RemoveElementAt(aIndexes->Length()-1);
631 }
632 }
633 }
635 // ok to leave cache out of date here if parent == mCommonParent?
636 sib = GetNextSibling(parent, aIndexes);
637 }
639 return sib;
640 }
642 // Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling...
643 nsIContent*
644 nsContentIterator::GetPrevSibling(nsINode* aNode,
645 nsTArray<int32_t>* aIndexes)
646 {
647 if (!aNode) {
648 return nullptr;
649 }
651 nsINode* parent = aNode->GetParentNode();
652 if (!parent) {
653 return nullptr;
654 }
656 int32_t indx = 0;
658 NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
659 "ContentIterator stack underflow");
660 if (aIndexes && !aIndexes->IsEmpty()) {
661 // use the last entry on the Indexes array for the current index
662 indx = (*aIndexes)[aIndexes->Length()-1];
663 } else {
664 indx = mCachedIndex;
665 }
667 // reverify that the index of the current node hasn't changed
668 // ignore result this time - the index may now be out of range.
669 nsIContent* sib = parent->GetChildAt(indx);
670 if (sib != aNode) {
671 // someone changed our index - find the new index the painful way
672 indx = parent->IndexOf(aNode);
673 }
675 // indx is now canonically correct
676 if (indx > 0 && (sib = parent->GetChildAt(--indx))) {
677 // update index cache
678 if (aIndexes && !aIndexes->IsEmpty()) {
679 aIndexes->ElementAt(aIndexes->Length()-1) = indx;
680 } else {
681 mCachedIndex = indx;
682 }
683 } else if (parent != mCommonParent) {
684 if (aIndexes && !aIndexes->IsEmpty()) {
685 // pop node off the stack, go up one level and try again.
686 aIndexes->RemoveElementAt(aIndexes->Length()-1);
687 }
688 return GetPrevSibling(parent, aIndexes);
689 }
691 return sib;
692 }
694 nsINode*
695 nsContentIterator::NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
696 {
697 nsINode* node = aNode;
699 // if we are a Pre-order iterator, use pre-order
700 if (mPre) {
701 // if it has children then next node is first child
702 if (node->HasChildren()) {
703 nsIContent* firstChild = node->GetFirstChild();
705 // update cache
706 if (aIndexes) {
707 // push an entry on the index stack
708 aIndexes->AppendElement(0);
709 } else {
710 mCachedIndex = 0;
711 }
713 return firstChild;
714 }
716 // else next sibling is next
717 return GetNextSibling(node, aIndexes);
718 }
720 // post-order
721 nsINode* parent = node->GetParentNode();
722 nsIContent* sibling = nullptr;
723 int32_t indx = 0;
725 // get the cached index
726 NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
727 "ContentIterator stack underflow");
728 if (aIndexes && !aIndexes->IsEmpty()) {
729 // use the last entry on the Indexes array for the current index
730 indx = (*aIndexes)[aIndexes->Length()-1];
731 } else {
732 indx = mCachedIndex;
733 }
735 // reverify that the index of the current node hasn't changed. not super
736 // cheap, but a lot cheaper than IndexOf(), and still O(1). ignore result
737 // this time - the index may now be out of range.
738 if (indx >= 0) {
739 sibling = parent->GetChildAt(indx);
740 }
741 if (sibling != node) {
742 // someone changed our index - find the new index the painful way
743 indx = parent->IndexOf(node);
744 }
746 // indx is now canonically correct
747 sibling = parent->GetChildAt(++indx);
748 if (sibling) {
749 // update cache
750 if (aIndexes && !aIndexes->IsEmpty()) {
751 // replace an entry on the index stack
752 aIndexes->ElementAt(aIndexes->Length()-1) = indx;
753 } else {
754 mCachedIndex = indx;
755 }
757 // next node is sibling's "deep left" child
758 return GetDeepFirstChild(sibling, aIndexes);
759 }
761 // else it's the parent, update cache
762 if (aIndexes) {
763 // Pop an entry off the index stack. Don't leave the index empty,
764 // especially if we're returning nullptr. This confuses other parts of the
765 // code.
766 if (aIndexes->Length() > 1) {
767 aIndexes->RemoveElementAt(aIndexes->Length()-1);
768 }
769 } else {
770 // this might be wrong, but we are better off guessing
771 mCachedIndex = 0;
772 }
774 return parent;
775 }
777 nsINode*
778 nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
779 {
780 nsINode* node = aNode;
782 // if we are a Pre-order iterator, use pre-order
783 if (mPre) {
784 nsINode* parent = node->GetParentNode();
785 nsIContent* sibling = nullptr;
786 int32_t indx = 0;
788 // get the cached index
789 NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
790 "ContentIterator stack underflow");
791 if (aIndexes && !aIndexes->IsEmpty()) {
792 // use the last entry on the Indexes array for the current index
793 indx = (*aIndexes)[aIndexes->Length()-1];
794 } else {
795 indx = mCachedIndex;
796 }
798 // reverify that the index of the current node hasn't changed. not super
799 // cheap, but a lot cheaper than IndexOf(), and still O(1). ignore result
800 // this time - the index may now be out of range.
801 if (indx >= 0) {
802 sibling = parent->GetChildAt(indx);
803 }
805 if (sibling != node) {
806 // someone changed our index - find the new index the painful way
807 indx = parent->IndexOf(node);
808 }
810 // indx is now canonically correct
811 if (indx && (sibling = parent->GetChildAt(--indx))) {
812 // update cache
813 if (aIndexes && !aIndexes->IsEmpty()) {
814 // replace an entry on the index stack
815 aIndexes->ElementAt(aIndexes->Length()-1) = indx;
816 } else {
817 mCachedIndex = indx;
818 }
820 // prev node is sibling's "deep right" child
821 return GetDeepLastChild(sibling, aIndexes);
822 }
824 // else it's the parent, update cache
825 if (aIndexes && !aIndexes->IsEmpty()) {
826 // pop an entry off the index stack
827 aIndexes->RemoveElementAt(aIndexes->Length()-1);
828 } else {
829 // this might be wrong, but we are better off guessing
830 mCachedIndex = 0;
831 }
832 return parent;
833 }
835 // post-order
836 int32_t numChildren = node->GetChildCount();
838 // if it has children then prev node is last child
839 if (numChildren) {
840 nsIContent* lastChild = node->GetLastChild();
841 numChildren--;
843 // update cache
844 if (aIndexes) {
845 // push an entry on the index stack
846 aIndexes->AppendElement(numChildren);
847 } else {
848 mCachedIndex = numChildren;
849 }
851 return lastChild;
852 }
854 // else prev sibling is previous
855 return GetPrevSibling(node, aIndexes);
856 }
858 /******************************************************
859 * ContentIterator routines
860 ******************************************************/
862 void
863 nsContentIterator::First()
864 {
865 if (mFirst) {
866 #ifdef DEBUG
867 nsresult rv =
868 #endif
869 PositionAt(mFirst);
871 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
872 }
874 mIsDone = mFirst == nullptr;
875 }
878 void
879 nsContentIterator::Last()
880 {
881 NS_ASSERTION(mLast, "No last node!");
883 if (mLast) {
884 #ifdef DEBUG
885 nsresult rv =
886 #endif
887 PositionAt(mLast);
889 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
890 }
892 mIsDone = mLast == nullptr;
893 }
896 void
897 nsContentIterator::Next()
898 {
899 if (mIsDone || !mCurNode) {
900 return;
901 }
903 if (mCurNode == mLast) {
904 mIsDone = true;
905 return;
906 }
908 mCurNode = NextNode(mCurNode, &mIndexes);
909 }
912 void
913 nsContentIterator::Prev()
914 {
915 if (mIsDone || !mCurNode) {
916 return;
917 }
919 if (mCurNode == mFirst) {
920 mIsDone = true;
921 return;
922 }
924 mCurNode = PrevNode(mCurNode, &mIndexes);
925 }
928 bool
929 nsContentIterator::IsDone()
930 {
931 return mIsDone;
932 }
935 // Keeping arrays of indexes for the stack of nodes makes PositionAt
936 // interesting...
937 nsresult
938 nsContentIterator::PositionAt(nsINode* aCurNode)
939 {
940 if (!aCurNode) {
941 return NS_ERROR_NULL_POINTER;
942 }
944 nsINode* newCurNode = aCurNode;
945 nsINode* tempNode = mCurNode;
947 mCurNode = aCurNode;
948 // take an early out if this doesn't actually change the position
949 if (mCurNode == tempNode) {
950 mIsDone = false; // paranoia
951 return NS_OK;
952 }
954 // Check to see if the node falls within the traversal range.
956 nsINode* firstNode = mFirst;
957 nsINode* lastNode = mLast;
958 int32_t firstOffset = 0, lastOffset = 0;
960 if (firstNode && lastNode) {
961 if (mPre) {
962 firstNode = NodeToParentOffset(mFirst, &firstOffset);
964 if (lastNode->GetChildCount()) {
965 lastOffset = 0;
966 } else {
967 lastNode = NodeToParentOffset(mLast, &lastOffset);
968 ++lastOffset;
969 }
970 } else {
971 uint32_t numChildren = firstNode->GetChildCount();
973 if (numChildren) {
974 firstOffset = numChildren;
975 } else {
976 firstNode = NodeToParentOffset(mFirst, &firstOffset);
977 }
979 lastNode = NodeToParentOffset(mLast, &lastOffset);
980 ++lastOffset;
981 }
982 }
984 // The end positions are always in the range even if it has no parent. We
985 // need to allow that or 'iter->Init(root)' would assert in Last() or First()
986 // for example, bug 327694.
987 if (mFirst != mCurNode && mLast != mCurNode &&
988 (!firstNode || !lastNode ||
989 !NodeIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset,
990 lastNode, lastOffset))) {
991 mIsDone = true;
992 return NS_ERROR_FAILURE;
993 }
995 // We can be at ANY node in the sequence. Need to regenerate the array of
996 // indexes back to the root or common parent!
997 nsAutoTArray<nsINode*, 8> oldParentStack;
998 nsAutoTArray<int32_t, 8> newIndexes;
1000 // Get a list of the parents up to the root, then compare the new node with
1001 // entries in that array until we find a match (lowest common ancestor). If
1002 // no match, use IndexOf, take the parent, and repeat. This avoids using
1003 // IndexOf() N times on possibly large arrays. We still end up doing it a
1004 // fair bit. It's better to use Clone() if possible.
1006 // we know the depth we're down (though we may not have started at the top).
1007 oldParentStack.SetCapacity(mIndexes.Length() + 1);
1009 // We want to loop mIndexes.Length() + 1 times here, because we want to make
1010 // sure we include mCommonParent in the oldParentStack, for use in the next
1011 // for loop, and mIndexes only has entries for nodes from tempNode up through
1012 // an ancestor of tempNode that's a child of mCommonParent.
1013 for (int32_t i = mIndexes.Length() + 1; i > 0 && tempNode; i--) {
1014 // Insert at head since we're walking up
1015 oldParentStack.InsertElementAt(0, tempNode);
1017 nsINode* parent = tempNode->GetParentNode();
1019 if (!parent) {
1020 // this node has no parent, and thus no index
1021 break;
1022 }
1024 if (parent == mCurNode) {
1025 // The position was moved to a parent of the current position. All we
1026 // need to do is drop some indexes. Shortcut here.
1027 mIndexes.RemoveElementsAt(mIndexes.Length() - oldParentStack.Length(),
1028 oldParentStack.Length());
1029 mIsDone = false;
1030 return NS_OK;
1031 }
1032 tempNode = parent;
1033 }
1035 // Ok. We have the array of old parents. Look for a match.
1036 while (newCurNode) {
1037 nsINode* parent = newCurNode->GetParentNode();
1039 if (!parent) {
1040 // this node has no parent, and thus no index
1041 break;
1042 }
1044 int32_t indx = parent->IndexOf(newCurNode);
1046 // insert at the head!
1047 newIndexes.InsertElementAt(0, indx);
1049 // look to see if the parent is in the stack
1050 indx = oldParentStack.IndexOf(parent);
1051 if (indx >= 0) {
1052 // ok, the parent IS on the old stack! Rework things. We want
1053 // newIndexes to replace all nodes equal to or below the match. Note
1054 // that index oldParentStack.Length() - 1 is the last node, which is one
1055 // BELOW the last index in the mIndexes stack. In other words, we want
1056 // to remove elements starting at index (indx + 1).
1057 int32_t numToDrop = oldParentStack.Length() - (1 + indx);
1058 if (numToDrop > 0) {
1059 mIndexes.RemoveElementsAt(mIndexes.Length() - numToDrop, numToDrop);
1060 }
1061 mIndexes.AppendElements(newIndexes);
1063 break;
1064 }
1065 newCurNode = parent;
1066 }
1068 // phew!
1070 mIsDone = false;
1071 return NS_OK;
1072 }
1074 nsINode*
1075 nsContentIterator::GetCurrentNode()
1076 {
1077 if (mIsDone) {
1078 return nullptr;
1079 }
1081 NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
1083 return mCurNode;
1084 }
1090 /*====================================================================================*/
1091 /*====================================================================================*/
1098 /******************************************************
1099 * nsContentSubtreeIterator
1100 ******************************************************/
1103 /*
1104 * A simple iterator class for traversing the content in "top subtree" order
1105 */
1106 class nsContentSubtreeIterator : public nsContentIterator
1107 {
1108 public:
1109 nsContentSubtreeIterator() : nsContentIterator(false) {}
1110 virtual ~nsContentSubtreeIterator() {}
1112 NS_DECL_ISUPPORTS_INHERITED
1113 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1115 // nsContentIterator overrides ------------------------------
1117 virtual nsresult Init(nsINode* aRoot);
1119 virtual nsresult Init(nsIDOMRange* aRange);
1121 virtual void Next();
1123 virtual void Prev();
1125 virtual nsresult PositionAt(nsINode* aCurNode);
1127 // Must override these because we don't do PositionAt
1128 virtual void First();
1130 // Must override these because we don't do PositionAt
1131 virtual void Last();
1133 protected:
1135 // Returns the highest inclusive ancestor of aNode that's in the range
1136 // (possibly aNode itself). Returns null if aNode is null, or is not itself
1137 // in the range. A node is in the range if (node, 0) comes strictly after
1138 // the range endpoint, and (node, node.length) comes strictly before it, so
1139 // the range's start and end nodes will never be considered "in" it.
1140 nsIContent* GetTopAncestorInRange(nsINode* aNode);
1142 // no copy's or assigns FIX ME
1143 nsContentSubtreeIterator(const nsContentSubtreeIterator&);
1144 nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
1146 virtual void LastRelease() MOZ_OVERRIDE;
1148 nsRefPtr<nsRange> mRange;
1150 // these arrays all typically are used and have elements
1151 nsAutoTArray<nsIContent*, 8> mEndNodes;
1152 nsAutoTArray<int32_t, 8> mEndOffsets;
1153 };
1155 NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1156 NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator)
1158 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator)
1159 NS_INTERFACE_MAP_END_INHERITING(nsContentIterator)
1161 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator, nsContentIterator,
1162 mRange)
1164 void
1165 nsContentSubtreeIterator::LastRelease()
1166 {
1167 mRange = nullptr;
1168 nsContentIterator::LastRelease();
1169 }
1171 /******************************************************
1172 * repository cruft
1173 ******************************************************/
1175 already_AddRefed<nsIContentIterator>
1176 NS_NewContentSubtreeIterator()
1177 {
1178 nsCOMPtr<nsIContentIterator> iter = new nsContentSubtreeIterator();
1179 return iter.forget();
1180 }
1184 /******************************************************
1185 * Init routines
1186 ******************************************************/
1189 nsresult
1190 nsContentSubtreeIterator::Init(nsINode* aRoot)
1191 {
1192 return NS_ERROR_NOT_IMPLEMENTED;
1193 }
1196 nsresult
1197 nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
1198 {
1199 MOZ_ASSERT(aRange);
1201 mIsDone = false;
1203 mRange = static_cast<nsRange*>(aRange);
1205 // get the start node and offset, convert to nsINode
1206 mCommonParent = mRange->GetCommonAncestor();
1207 nsINode* startParent = mRange->GetStartParent();
1208 int32_t startOffset = mRange->StartOffset();
1209 nsINode* endParent = mRange->GetEndParent();
1210 int32_t endOffset = mRange->EndOffset();
1211 MOZ_ASSERT(mCommonParent && startParent && endParent);
1212 // Bug 767169
1213 MOZ_ASSERT(uint32_t(startOffset) <= startParent->Length() &&
1214 uint32_t(endOffset) <= endParent->Length());
1216 // short circuit when start node == end node
1217 if (startParent == endParent) {
1218 nsINode* child = startParent->GetFirstChild();
1220 if (!child || startOffset == endOffset) {
1221 // Text node, empty container, or collapsed
1222 MakeEmpty();
1223 return NS_OK;
1224 }
1225 }
1227 // cache ancestors
1228 nsContentUtils::GetAncestorsAndOffsets(endParent->AsDOMNode(), endOffset,
1229 &mEndNodes, &mEndOffsets);
1231 nsIContent* firstCandidate = nullptr;
1232 nsIContent* lastCandidate = nullptr;
1234 // find first node in range
1235 int32_t offset = mRange->StartOffset();
1237 nsINode* node;
1238 if (!startParent->GetChildCount()) {
1239 // no children, start at the node itself
1240 node = startParent;
1241 } else {
1242 nsIContent* child = startParent->GetChildAt(offset);
1243 if (!child) {
1244 // offset after last child
1245 node = startParent;
1246 } else {
1247 firstCandidate = child;
1248 }
1249 }
1251 if (!firstCandidate) {
1252 // then firstCandidate is next node after node
1253 firstCandidate = GetNextSibling(node);
1255 if (!firstCandidate) {
1256 MakeEmpty();
1257 return NS_OK;
1258 }
1259 }
1261 firstCandidate = GetDeepFirstChild(firstCandidate);
1263 // confirm that this first possible contained node is indeed contained. Else
1264 // we have a range that does not fully contain any node.
1266 bool nodeBefore, nodeAfter;
1267 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
1268 nsRange::CompareNodeToRange(firstCandidate, mRange, &nodeBefore, &nodeAfter)));
1270 if (nodeBefore || nodeAfter) {
1271 MakeEmpty();
1272 return NS_OK;
1273 }
1275 // cool, we have the first node in the range. Now we walk up its ancestors
1276 // to find the most senior that is still in the range. That's the real first
1277 // node.
1278 mFirst = GetTopAncestorInRange(firstCandidate);
1280 // now to find the last node
1281 offset = mRange->EndOffset();
1282 int32_t numChildren = endParent->GetChildCount();
1284 if (offset > numChildren) {
1285 // Can happen for text nodes
1286 offset = numChildren;
1287 }
1288 if (!offset || !numChildren) {
1289 node = endParent;
1290 } else {
1291 lastCandidate = endParent->GetChildAt(--offset);
1292 NS_ASSERTION(lastCandidate,
1293 "tree traversal trouble in nsContentSubtreeIterator::Init");
1294 }
1296 if (!lastCandidate) {
1297 // then lastCandidate is prev node before node
1298 lastCandidate = GetPrevSibling(node);
1299 }
1301 if (!lastCandidate) {
1302 MakeEmpty();
1303 return NS_OK;
1304 }
1306 lastCandidate = GetDeepLastChild(lastCandidate);
1308 // confirm that this last possible contained node is indeed contained. Else
1309 // we have a range that does not fully contain any node.
1311 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
1312 nsRange::CompareNodeToRange(lastCandidate, mRange, &nodeBefore, &nodeAfter)));
1314 if (nodeBefore || nodeAfter) {
1315 MakeEmpty();
1316 return NS_OK;
1317 }
1319 // cool, we have the last node in the range. Now we walk up its ancestors to
1320 // find the most senior that is still in the range. That's the real first
1321 // node.
1322 mLast = GetTopAncestorInRange(lastCandidate);
1324 mCurNode = mFirst;
1326 return NS_OK;
1327 }
1329 /****************************************************************
1330 * nsContentSubtreeIterator overrides of ContentIterator routines
1331 ****************************************************************/
1333 // we can't call PositionAt in a subtree iterator...
1334 void
1335 nsContentSubtreeIterator::First()
1336 {
1337 mIsDone = mFirst == nullptr;
1339 mCurNode = mFirst;
1340 }
1342 // we can't call PositionAt in a subtree iterator...
1343 void
1344 nsContentSubtreeIterator::Last()
1345 {
1346 mIsDone = mLast == nullptr;
1348 mCurNode = mLast;
1349 }
1352 void
1353 nsContentSubtreeIterator::Next()
1354 {
1355 if (mIsDone || !mCurNode) {
1356 return;
1357 }
1359 if (mCurNode == mLast) {
1360 mIsDone = true;
1361 return;
1362 }
1364 nsINode* nextNode = GetNextSibling(mCurNode);
1365 NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
1367 int32_t i = mEndNodes.IndexOf(nextNode);
1368 while (i != -1) {
1369 // as long as we are finding ancestors of the endpoint of the range,
1370 // dive down into their children
1371 nextNode = nextNode->GetFirstChild();
1372 NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
1374 // should be impossible to get a null pointer. If we went all the way
1375 // down the child chain to the bottom without finding an interior node,
1376 // then the previous node should have been the last, which was
1377 // was tested at top of routine.
1378 i = mEndNodes.IndexOf(nextNode);
1379 }
1381 mCurNode = nextNode;
1383 // This shouldn't be needed, but since our selection code can put us
1384 // in a situation where mLast is in generated content, we need this
1385 // to stop the iterator when we've walked past past the last node!
1386 mIsDone = mCurNode == nullptr;
1387 }
1390 void
1391 nsContentSubtreeIterator::Prev()
1392 {
1393 // Prev should be optimized to use the mStartNodes, just as Next
1394 // uses mEndNodes.
1395 if (mIsDone || !mCurNode) {
1396 return;
1397 }
1399 if (mCurNode == mFirst) {
1400 mIsDone = true;
1401 return;
1402 }
1404 // If any of these function calls return null, so will all succeeding ones,
1405 // so mCurNode will wind up set to null.
1406 nsINode* prevNode = GetDeepFirstChild(mCurNode);
1408 prevNode = PrevNode(prevNode);
1410 prevNode = GetDeepLastChild(prevNode);
1412 mCurNode = GetTopAncestorInRange(prevNode);
1414 // This shouldn't be needed, but since our selection code can put us
1415 // in a situation where mFirst is in generated content, we need this
1416 // to stop the iterator when we've walked past past the first node!
1417 mIsDone = mCurNode == nullptr;
1418 }
1421 nsresult
1422 nsContentSubtreeIterator::PositionAt(nsINode* aCurNode)
1423 {
1424 NS_ERROR("Not implemented!");
1426 return NS_ERROR_NOT_IMPLEMENTED;
1427 }
1429 /****************************************************************
1430 * nsContentSubtreeIterator helper routines
1431 ****************************************************************/
1433 nsIContent*
1434 nsContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode)
1435 {
1436 if (!aNode || !aNode->GetParentNode()) {
1437 return nullptr;
1438 }
1440 // aNode has a parent, so it must be content.
1441 nsIContent* content = aNode->AsContent();
1443 // sanity check: aNode is itself in the range
1444 bool nodeBefore, nodeAfter;
1445 nsresult res = nsRange::CompareNodeToRange(aNode, mRange,
1446 &nodeBefore, &nodeAfter);
1447 NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
1448 "aNode isn't in mRange, or something else weird happened");
1449 if (NS_FAILED(res) || nodeBefore || nodeAfter) {
1450 return nullptr;
1451 }
1453 while (content) {
1454 nsIContent* parent = content->GetParent();
1455 // content always has a parent. If its parent is the root, however --
1456 // i.e., either it's not content, or it is content but its own parent is
1457 // null -- then we're finished, since we don't go up to the root.
1458 //
1459 // We have to special-case this because CompareNodeToRange treats the root
1460 // node differently -- see bug 765205.
1461 if (!parent || !parent->GetParentNode()) {
1462 return content;
1463 }
1464 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
1465 nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter)));
1467 if (nodeBefore || nodeAfter) {
1468 return content;
1469 }
1470 content = parent;
1471 }
1473 MOZ_CRASH("This should only be possible if aNode was null");
1474 }