1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/DebugOnly.h"
8 #include "nsISupports.h"
9 #include "nsIDOMNodeList.h"
10 #include "nsIContentIterator.h"
11 #include "nsRange.h"
12 #include "nsIContent.h"
13 #include "nsCOMPtr.h"
14 #include "nsTArray.h"
15 #include "nsContentUtils.h"
16 #include "nsINode.h"
17 #include "nsCycleCollectionParticipant.h"
18 #include "nsElementTable.h"
19 
20 using mozilla::DebugOnly;
21 using mozilla::RawRangeBoundary;
22 
23 // couple of utility static functs
24 
25 ///////////////////////////////////////////////////////////////////////////
26 // NodeIsInTraversalRange: returns true if content is visited during
27 // the traversal of the range in the specified mode.
28 //
NodeIsInTraversalRange(nsINode * aNode,bool aIsPreMode,const RawRangeBoundary & aStart,const RawRangeBoundary & aEnd)29 static bool NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
30                                    const RawRangeBoundary& aStart,
31                                    const RawRangeBoundary& aEnd) {
32   if (NS_WARN_IF(!aStart.IsSet()) || NS_WARN_IF(!aEnd.IsSet()) ||
33       NS_WARN_IF(!aNode)) {
34     return false;
35   }
36 
37   // If a leaf node contains an end point of the traversal range, it is
38   // always in the traversal range.
39   if (aNode == aStart.Container() || aNode == aEnd.Container()) {
40     if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
41       return true;  // text node or something
42     }
43     if (!aNode->HasChildren()) {
44       MOZ_ASSERT(
45           aNode != aStart.Container() || aStart.IsStartOfContainer(),
46           "aStart.Container() doesn't have children and not a data node, "
47           "aStart should be at the beginning of its container");
48       MOZ_ASSERT(aNode != aEnd.Container() || aEnd.IsStartOfContainer(),
49                  "aEnd.Container() doesn't have children and not a data node, "
50                  "aEnd should be at the beginning of its container");
51       return true;
52     }
53   }
54 
55   nsINode* parent = aNode->GetParentNode();
56   if (!parent) {
57     return false;
58   }
59 
60   if (!aIsPreMode) {
61     // aNode should always be content, as we have a parent, but let's just be
62     // extra careful and check.
63     nsIContent* content =
64         NS_WARN_IF(!aNode->IsContent()) ? nullptr : aNode->AsContent();
65     // Post mode: start < node <= end.
66     RawRangeBoundary afterNode(parent, content);
67     return nsContentUtils::ComparePoints(aStart, afterNode) < 0 &&
68            nsContentUtils::ComparePoints(aEnd, afterNode) >= 0;
69   }
70 
71   // Pre mode: start <= node < end.
72   RawRangeBoundary beforeNode(parent, aNode->GetPreviousSibling());
73   return nsContentUtils::ComparePoints(aStart, beforeNode) <= 0 &&
74          nsContentUtils::ComparePoints(aEnd, beforeNode) > 0;
75 }
76 
77 /*
78  *  A simple iterator class for traversing the content in "close tag" order
79  */
80 class nsContentIterator : public nsIContentIterator {
81  public:
82   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
83   NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator)
84 
85   explicit nsContentIterator(bool aPre);
86 
87   // nsIContentIterator interface methods ------------------------------
88 
89   virtual nsresult Init(nsINode* aRoot) override;
90 
91   virtual nsresult Init(nsIDOMRange* aRange) override;
92 
93   virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
94                         nsINode* aEndContainer, uint32_t aEndOffset) override;
95 
96   virtual nsresult Init(const RawRangeBoundary& aStart,
97                         const RawRangeBoundary& aEnd) override;
98 
99   virtual void First() override;
100 
101   virtual void Last() override;
102 
103   virtual void Next() override;
104 
105   virtual void Prev() override;
106 
107   virtual nsINode* GetCurrentNode() override;
108 
109   virtual bool IsDone() override;
110 
111   virtual nsresult PositionAt(nsINode* aCurNode) override;
112 
113  protected:
114   virtual ~nsContentIterator();
115 
116   /**
117    * Callers must guarantee that:
118    * - Neither aStartContainer nor aEndContainer is nullptr.
119    * - aStartOffset and aEndOffset are valid for its container.
120    * - The start point and the end point are in document order.
121    */
122   nsresult InitInternal(const RawRangeBoundary& aStart,
123                         const RawRangeBoundary& aEnd);
124 
125   // Recursively get the deepest first/last child of aRoot.  This will return
126   // aRoot itself if it has no children.
127   nsINode* GetDeepFirstChild(nsINode* aRoot);
128   nsIContent* GetDeepFirstChild(nsIContent* aRoot);
129   nsINode* GetDeepLastChild(nsINode* aRoot);
130   nsIContent* GetDeepLastChild(nsIContent* aRoot);
131 
132   // Get the next/previous sibling of aNode, or its parent's, or grandparent's,
133   // etc.  Returns null if aNode and all its ancestors have no next/previous
134   // sibling.
135   nsIContent* GetNextSibling(nsINode* aNode);
136   nsIContent* GetPrevSibling(nsINode* aNode);
137 
138   nsINode* NextNode(nsINode* aNode);
139   nsINode* PrevNode(nsINode* aNode);
140 
141   void MakeEmpty();
142 
143   virtual void LastRelease();
144 
145   nsCOMPtr<nsINode> mCurNode;
146   nsCOMPtr<nsINode> mFirst;
147   nsCOMPtr<nsINode> mLast;
148   nsCOMPtr<nsINode> mCommonParent;
149 
150   bool mIsDone;
151   bool mPre;
152 
153  private:
154   // no copies or assigns  FIX ME
155   nsContentIterator(const nsContentIterator&);
156   nsContentIterator& operator=(const nsContentIterator&);
157 };
158 
159 /******************************************************
160  * repository cruft
161  ******************************************************/
162 
NS_NewContentIterator()163 already_AddRefed<nsIContentIterator> NS_NewContentIterator() {
164   nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(false);
165   return iter.forget();
166 }
167 
NS_NewPreContentIterator()168 already_AddRefed<nsIContentIterator> NS_NewPreContentIterator() {
169   nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(true);
170   return iter.forget();
171 }
172 
173 /******************************************************
174  * XPCOM cruft
175  ******************************************************/
176 
177 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator)
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsContentIterator,LastRelease ())178 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsContentIterator,
179                                                    LastRelease())
180 
181 NS_INTERFACE_MAP_BEGIN(nsContentIterator)
182   NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
183   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
184   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator)
185 NS_INTERFACE_MAP_END
186 
187 NS_IMPL_CYCLE_COLLECTION(nsContentIterator, mCurNode, mFirst, mLast,
188                          mCommonParent)
189 
190 void nsContentIterator::LastRelease() {
191   mCurNode = nullptr;
192   mFirst = nullptr;
193   mLast = nullptr;
194   mCommonParent = nullptr;
195 }
196 
197 /******************************************************
198  * constructor/destructor
199  ******************************************************/
200 
nsContentIterator(bool aPre)201 nsContentIterator::nsContentIterator(bool aPre) : mIsDone(false), mPre(aPre) {}
202 
~nsContentIterator()203 nsContentIterator::~nsContentIterator() {}
204 
205 /******************************************************
206  * Init routines
207  ******************************************************/
208 
Init(nsINode * aRoot)209 nsresult nsContentIterator::Init(nsINode* aRoot) {
210   if (NS_WARN_IF(!aRoot)) {
211     return NS_ERROR_NULL_POINTER;
212   }
213 
214   mIsDone = false;
215 
216   if (mPre) {
217     mFirst = aRoot;
218     mLast = GetDeepLastChild(aRoot);
219     NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
220   } else {
221     mFirst = GetDeepFirstChild(aRoot);
222     NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
223     mLast = aRoot;
224   }
225 
226   mCommonParent = aRoot;
227   mCurNode = mFirst;
228   return NS_OK;
229 }
230 
Init(nsIDOMRange * aDOMRange)231 nsresult nsContentIterator::Init(nsIDOMRange* aDOMRange) {
232   mIsDone = false;
233 
234   if (NS_WARN_IF(!aDOMRange)) {
235     return NS_ERROR_INVALID_ARG;
236   }
237 
238   nsRange* range = static_cast<nsRange*>(aDOMRange);
239   if (NS_WARN_IF(!range->IsPositioned())) {
240     return NS_ERROR_INVALID_ARG;
241   }
242 
243   return InitInternal(range->StartRef().AsRaw(), range->EndRef().AsRaw());
244 }
245 
Init(nsINode * aStartContainer,uint32_t aStartOffset,nsINode * aEndContainer,uint32_t aEndOffset)246 nsresult nsContentIterator::Init(nsINode* aStartContainer,
247                                  uint32_t aStartOffset, nsINode* aEndContainer,
248                                  uint32_t aEndOffset) {
249   mIsDone = false;
250 
251   if (NS_WARN_IF(!nsRange::IsValidPoints(aStartContainer, aStartOffset,
252                                          aEndContainer, aEndOffset))) {
253     return NS_ERROR_INVALID_ARG;
254   }
255 
256   return InitInternal(RawRangeBoundary(aStartContainer, aStartOffset),
257                       RawRangeBoundary(aEndContainer, aEndOffset));
258 }
259 
Init(const RawRangeBoundary & aStart,const RawRangeBoundary & aEnd)260 nsresult nsContentIterator::Init(const RawRangeBoundary& aStart,
261                                  const RawRangeBoundary& aEnd) {
262   mIsDone = false;
263 
264   if (NS_WARN_IF(!nsRange::IsValidPoints(aStart.Container(), aStart.Offset(),
265                                          aEnd.Container(), aEnd.Offset()))) {
266     return NS_ERROR_INVALID_ARG;
267   }
268 
269   return InitInternal(aStart, aEnd);
270 }
271 
InitInternal(const RawRangeBoundary & aStart,const RawRangeBoundary & aEnd)272 nsresult nsContentIterator::InitInternal(const RawRangeBoundary& aStart,
273                                          const RawRangeBoundary& aEnd) {
274   // get common content parent
275   mCommonParent =
276       nsContentUtils::GetCommonAncestor(aStart.Container(), aEnd.Container());
277   if (NS_WARN_IF(!mCommonParent)) {
278     return NS_ERROR_FAILURE;
279   }
280 
281   bool startIsData = aStart.Container()->IsNodeOfType(nsINode::eDATA_NODE);
282 
283   // Check to see if we have a collapsed range, if so, there is nothing to
284   // iterate over.
285   //
286   // XXX: CharacterDataNodes (text nodes) are currently an exception, since
287   //      we always want to be able to iterate text nodes at the end points
288   //      of a range.
289 
290   if (!startIsData && aStart == aEnd) {
291     MakeEmpty();
292     return NS_OK;
293   }
294 
295   // Handle ranges within a single character data node.
296   if (startIsData && aStart.Container() == aEnd.Container()) {
297     mFirst = aStart.Container()->AsContent();
298     mLast = mFirst;
299     mCurNode = mFirst;
300 
301     return NS_OK;
302   }
303 
304   // Find first node in range.
305 
306   nsIContent* cChild = nullptr;
307 
308   // Try to get the child at our starting point. This might return null if
309   // aStart is immediately after the last node in aStart.Container().
310   if (!startIsData) {
311     cChild = aStart.GetChildAtOffset();
312   }
313 
314   if (!cChild) {
315     // No children (possibly a <br> or text node), or index is after last child.
316 
317     if (mPre) {
318       // XXX: In the future, if start offset is after the last
319       //      character in the cdata node, should we set mFirst to
320       //      the next sibling?
321 
322       // Normally we would skip the start node because the start node is outside
323       // of the range in pre mode. However, if aStartOffset == 0, and the node
324       // is a non-container node (e.g. <br>), we don't skip the node in this
325       // case in order to address bug 1215798.
326       bool startIsContainer = true;
327       if (aStart.Container()->IsHTMLElement()) {
328         nsAtom* name = aStart.Container()->NodeInfo()->NameAtom();
329         startIsContainer =
330             nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
331       }
332       if (!startIsData && (startIsContainer || !aStart.IsStartOfContainer())) {
333         mFirst = GetNextSibling(aStart.Container());
334         NS_WARNING_ASSERTION(mFirst, "GetNextSibling returned null");
335 
336         // Does mFirst node really intersect the range?  The range could be
337         // 'degenerate', i.e., not collapsed but still contain no content.
338         if (mFirst &&
339             NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, aStart, aEnd))) {
340           mFirst = nullptr;
341         }
342       } else {
343         mFirst = aStart.Container()->AsContent();
344       }
345     } else {
346       // post-order
347       if (NS_WARN_IF(!aStart.Container()->IsContent())) {
348         // What else can we do?
349         mFirst = nullptr;
350       } else {
351         mFirst = aStart.Container()->AsContent();
352       }
353     }
354   } else {
355     if (mPre) {
356       mFirst = cChild;
357     } else {
358       // post-order
359       mFirst = GetDeepFirstChild(cChild);
360       NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
361 
362       // Does mFirst node really intersect the range?  The range could be
363       // 'degenerate', i.e., not collapsed but still contain no content.
364 
365       if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, aStart, aEnd)) {
366         mFirst = nullptr;
367       }
368     }
369   }
370 
371   // Find last node in range.
372 
373   bool endIsData = aEnd.Container()->IsNodeOfType(nsINode::eDATA_NODE);
374 
375   if (endIsData || !aEnd.Container()->HasChildren() ||
376       aEnd.IsStartOfContainer()) {
377     if (mPre) {
378       if (NS_WARN_IF(!aEnd.Container()->IsContent())) {
379         // Not much else to do here...
380         mLast = nullptr;
381       } else {
382         // If the end node is a non-container element and the end offset is 0,
383         // the last element should be the previous node (i.e., shouldn't
384         // include the end node in the range).
385         bool endIsContainer = true;
386         if (aEnd.Container()->IsHTMLElement()) {
387           nsAtom* name = aEnd.Container()->NodeInfo()->NameAtom();
388           endIsContainer =
389               nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
390         }
391         if (!endIsData && !endIsContainer && aEnd.IsStartOfContainer()) {
392           mLast = PrevNode(aEnd.Container());
393           NS_WARNING_ASSERTION(mLast, "PrevNode returned null");
394           if (mLast && mLast != mFirst &&
395               NS_WARN_IF(!NodeIsInTraversalRange(
396                   mLast, mPre, RawRangeBoundary(mFirst, 0), aEnd))) {
397             mLast = nullptr;
398           }
399         } else {
400           mLast = aEnd.Container()->AsContent();
401         }
402       }
403     } else {
404       // post-order
405       //
406       // XXX: In the future, if end offset is before the first character in the
407       //      cdata node, should we set mLast to the prev sibling?
408 
409       if (!endIsData) {
410         mLast = GetPrevSibling(aEnd.Container());
411         NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null");
412 
413         if (!NodeIsInTraversalRange(mLast, mPre, aStart, aEnd)) {
414           mLast = nullptr;
415         }
416       } else {
417         mLast = aEnd.Container()->AsContent();
418       }
419     }
420   } else {
421     cChild = aEnd.Ref();
422 
423     if (NS_WARN_IF(!cChild)) {
424       // No child at offset!
425       NS_NOTREACHED("nsContentIterator::nsContentIterator");
426       return NS_ERROR_FAILURE;
427     }
428 
429     if (mPre) {
430       mLast = GetDeepLastChild(cChild);
431       NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
432 
433       if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre, aStart, aEnd))) {
434         mLast = nullptr;
435       }
436     } else {
437       // post-order
438       mLast = cChild;
439     }
440   }
441 
442   // If either first or last is null, they both have to be null!
443 
444   if (!mFirst || !mLast) {
445     mFirst = nullptr;
446     mLast = nullptr;
447   }
448 
449   mCurNode = mFirst;
450   mIsDone = !mCurNode;
451 
452   return NS_OK;
453 }
454 
MakeEmpty()455 void nsContentIterator::MakeEmpty() {
456   mCurNode = nullptr;
457   mFirst = nullptr;
458   mLast = nullptr;
459   mCommonParent = nullptr;
460   mIsDone = true;
461 }
462 
GetDeepFirstChild(nsINode * aRoot)463 nsINode* nsContentIterator::GetDeepFirstChild(nsINode* aRoot) {
464   if (NS_WARN_IF(!aRoot) || !aRoot->HasChildren()) {
465     return aRoot;
466   }
467 
468   return GetDeepFirstChild(aRoot->GetFirstChild());
469 }
470 
GetDeepFirstChild(nsIContent * aRoot)471 nsIContent* nsContentIterator::GetDeepFirstChild(nsIContent* aRoot) {
472   if (NS_WARN_IF(!aRoot)) {
473     return nullptr;
474   }
475 
476   nsIContent* node = aRoot;
477   nsIContent* child = node->GetFirstChild();
478 
479   while (child) {
480     node = child;
481     child = node->GetFirstChild();
482   }
483 
484   return node;
485 }
486 
GetDeepLastChild(nsINode * aRoot)487 nsINode* nsContentIterator::GetDeepLastChild(nsINode* aRoot) {
488   if (NS_WARN_IF(!aRoot) || !aRoot->HasChildren()) {
489     return aRoot;
490   }
491 
492   return GetDeepLastChild(aRoot->GetLastChild());
493 }
494 
GetDeepLastChild(nsIContent * aRoot)495 nsIContent* nsContentIterator::GetDeepLastChild(nsIContent* aRoot) {
496   if (NS_WARN_IF(!aRoot)) {
497     return nullptr;
498   }
499 
500   nsIContent* node = aRoot;
501   while (node->HasChildren()) {
502     nsIContent* child = node->GetLastChild();
503     node = child;
504   }
505   return node;
506 }
507 
508 // Get the next sibling, or parent's next sibling, or grandpa's next sibling...
GetNextSibling(nsINode * aNode)509 nsIContent* nsContentIterator::GetNextSibling(nsINode* aNode) {
510   if (NS_WARN_IF(!aNode)) {
511     return nullptr;
512   }
513 
514   if (aNode->GetNextSibling()) {
515     return aNode->GetNextSibling();
516   }
517 
518   nsINode* parent = aNode->GetParentNode();
519   if (NS_WARN_IF(!parent)) {
520     return nullptr;
521   }
522 
523   // XXX This is a hack to preserve previous behaviour: This should be fixed
524   // in bug 1404916. If we were positioned on anonymous content, move to
525   // the first child of our parent.
526   if (parent->GetLastChild() && parent->GetLastChild() != aNode) {
527     return parent->GetFirstChild();
528   }
529 
530   return GetNextSibling(parent);
531 }
532 
533 // Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling...
GetPrevSibling(nsINode * aNode)534 nsIContent* nsContentIterator::GetPrevSibling(nsINode* aNode) {
535   if (NS_WARN_IF(!aNode)) {
536     return nullptr;
537   }
538 
539   if (aNode->GetPreviousSibling()) {
540     return aNode->GetPreviousSibling();
541   }
542 
543   nsINode* parent = aNode->GetParentNode();
544   if (NS_WARN_IF(!parent)) {
545     return nullptr;
546   }
547 
548   // XXX This is a hack to preserve previous behaviour: This should be fixed
549   // in bug 1404916. If we were positioned on anonymous content, move to
550   // the last child of our parent.
551   if (parent->GetFirstChild() && parent->GetFirstChild() != aNode) {
552     return parent->GetLastChild();
553   }
554 
555   return GetPrevSibling(parent);
556 }
557 
NextNode(nsINode * aNode)558 nsINode* nsContentIterator::NextNode(nsINode* aNode) {
559   nsINode* node = aNode;
560 
561   // if we are a Pre-order iterator, use pre-order
562   if (mPre) {
563     // if it has children then next node is first child
564     if (node->HasChildren()) {
565       nsIContent* firstChild = node->GetFirstChild();
566       MOZ_ASSERT(firstChild);
567 
568       return firstChild;
569     }
570 
571     // else next sibling is next
572     return GetNextSibling(node);
573   }
574 
575   // post-order
576   nsINode* parent = node->GetParentNode();
577   if (NS_WARN_IF(!parent)) {
578     MOZ_ASSERT(parent, "The node is the root node but not the last node");
579     mIsDone = true;
580     return node;
581   }
582 
583   nsIContent* sibling = node->GetNextSibling();
584   if (sibling) {
585     // next node is sibling's "deep left" child
586     return GetDeepFirstChild(sibling);
587   }
588 
589   return parent;
590 }
591 
PrevNode(nsINode * aNode)592 nsINode* nsContentIterator::PrevNode(nsINode* aNode) {
593   nsINode* node = aNode;
594 
595   // if we are a Pre-order iterator, use pre-order
596   if (mPre) {
597     nsINode* parent = node->GetParentNode();
598     if (NS_WARN_IF(!parent)) {
599       MOZ_ASSERT(parent, "The node is the root node but not the first node");
600       mIsDone = true;
601       return aNode;
602     }
603 
604     nsIContent* sibling = node->GetPreviousSibling();
605     if (sibling) {
606       return GetDeepLastChild(sibling);
607     }
608 
609     return parent;
610   }
611 
612   // post-order
613   if (node->HasChildren()) {
614     return node->GetLastChild();
615   }
616 
617   // else prev sibling is previous
618   return GetPrevSibling(node);
619 }
620 
621 /******************************************************
622  * ContentIterator routines
623  ******************************************************/
624 
First()625 void nsContentIterator::First() {
626   if (mFirst) {
627     mozilla::DebugOnly<nsresult> rv = PositionAt(mFirst);
628     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
629   }
630 
631   mIsDone = mFirst == nullptr;
632 }
633 
Last()634 void nsContentIterator::Last() {
635   // Note that mLast can be nullptr if MakeEmpty() is called in Init() since
636   // at that time, Init() returns NS_OK.
637   if (!mLast) {
638     MOZ_ASSERT(mIsDone);
639     return;
640   }
641 
642   mozilla::DebugOnly<nsresult> rv = PositionAt(mLast);
643   NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
644 
645   mIsDone = mLast == nullptr;
646 }
647 
Next()648 void nsContentIterator::Next() {
649   if (mIsDone || NS_WARN_IF(!mCurNode)) {
650     return;
651   }
652 
653   if (mCurNode == mLast) {
654     mIsDone = true;
655     return;
656   }
657 
658   mCurNode = NextNode(mCurNode);
659 }
660 
Prev()661 void nsContentIterator::Prev() {
662   if (NS_WARN_IF(mIsDone) || NS_WARN_IF(!mCurNode)) {
663     return;
664   }
665 
666   if (mCurNode == mFirst) {
667     mIsDone = true;
668     return;
669   }
670 
671   mCurNode = PrevNode(mCurNode);
672 }
673 
IsDone()674 bool nsContentIterator::IsDone() { return mIsDone; }
675 
676 // Keeping arrays of indexes for the stack of nodes makes PositionAt
677 // interesting...
PositionAt(nsINode * aCurNode)678 nsresult nsContentIterator::PositionAt(nsINode* aCurNode) {
679   if (NS_WARN_IF(!aCurNode)) {
680     return NS_ERROR_NULL_POINTER;
681   }
682 
683   // take an early out if this doesn't actually change the position
684   if (mCurNode == aCurNode) {
685     mIsDone = false;
686     return NS_OK;
687   }
688   mCurNode = aCurNode;
689 
690   // Check to see if the node falls within the traversal range.
691 
692   RawRangeBoundary first(mFirst, 0);
693   RawRangeBoundary last(mLast, 0);
694 
695   if (mFirst && mLast) {
696     if (mPre) {
697       // In pre we want to record the point immediately before mFirst, which is
698       // the point immediately after mFirst's previous sibling.
699       first.SetAfterRef(mFirst->GetParentNode(), mFirst->GetPreviousSibling());
700 
701       // If mLast has no children, then we want to make sure to include it.
702       if (!mLast->HasChildren()) {
703         last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
704       }
705     } else {
706       // If the first node has any children, we want to be immediately after the
707       // last. Otherwise we want to be immediately before mFirst.
708       if (mFirst->HasChildren()) {
709         first.SetAfterRef(mFirst, mFirst->GetLastChild());
710       } else {
711         first.SetAfterRef(mFirst->GetParentNode(),
712                           mFirst->GetPreviousSibling());
713       }
714 
715       // Set the last point immediately after the final node.
716       last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
717     }
718   }
719 
720   NS_WARNING_ASSERTION(first.IsSetAndValid(), "first is not valid");
721   NS_WARNING_ASSERTION(last.IsSetAndValid(), "last is not valid");
722 
723   // The end positions are always in the range even if it has no parent.  We
724   // need to allow that or 'iter->Init(root)' would assert in Last() or First()
725   // for example, bug 327694.
726   if (mFirst != mCurNode && mLast != mCurNode &&
727       (NS_WARN_IF(!first.IsSet()) || NS_WARN_IF(!last.IsSet()) ||
728        NS_WARN_IF(!NodeIsInTraversalRange(mCurNode, mPre, first, last)))) {
729     mIsDone = true;
730     return NS_ERROR_FAILURE;
731   }
732 
733   mIsDone = false;
734   return NS_OK;
735 }
736 
GetCurrentNode()737 nsINode* nsContentIterator::GetCurrentNode() {
738   if (mIsDone) {
739     return nullptr;
740   }
741 
742   NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
743 
744   return mCurNode;
745 }
746 
747 /*====================================================================================*/
748 /*====================================================================================*/
749 
750 /******************************************************
751  * nsContentSubtreeIterator
752  ******************************************************/
753 
754 /*
755  *  A simple iterator class for traversing the content in "top subtree" order
756  */
757 class nsContentSubtreeIterator : public nsContentIterator {
758  public:
nsContentSubtreeIterator()759   nsContentSubtreeIterator() : nsContentIterator(false) {}
760 
761   NS_DECL_ISUPPORTS_INHERITED
762   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator,
763                                            nsContentIterator)
764 
765   // nsContentIterator overrides ------------------------------
766 
767   virtual nsresult Init(nsINode* aRoot) override;
768 
769   virtual nsresult Init(nsIDOMRange* aRange) override;
770 
771   virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
772                         nsINode* aEndContainer, uint32_t aEndOffset) override;
773 
774   virtual nsresult Init(const RawRangeBoundary& aStart,
775                         const RawRangeBoundary& aEnd) override;
776 
777   virtual void Next() override;
778 
779   virtual void Prev() override;
780 
781   virtual nsresult PositionAt(nsINode* aCurNode) override;
782 
783   // Must override these because we don't do PositionAt
784   virtual void First() override;
785 
786   // Must override these because we don't do PositionAt
787   virtual void Last() override;
788 
789  protected:
~nsContentSubtreeIterator()790   virtual ~nsContentSubtreeIterator() {}
791 
792   /**
793    * Callers must guarantee that mRange isn't nullptr and is positioned.
794    */
795   nsresult InitWithRange();
796 
797   // Returns the highest inclusive ancestor of aNode that's in the range
798   // (possibly aNode itself).  Returns null if aNode is null, or is not itself
799   // in the range.  A node is in the range if (node, 0) comes strictly after
800   // the range endpoint, and (node, node.length) comes strictly before it, so
801   // the range's start and end nodes will never be considered "in" it.
802   nsIContent* GetTopAncestorInRange(nsINode* aNode);
803 
804   // no copy's or assigns  FIX ME
805   nsContentSubtreeIterator(const nsContentSubtreeIterator&);
806   nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
807 
808   virtual void LastRelease() override;
809 
810   RefPtr<nsRange> mRange;
811 
812   // these arrays all typically are used and have elements
813   AutoTArray<nsIContent*, 8> mEndNodes;
814   AutoTArray<int32_t, 8> mEndOffsets;
815 };
816 
NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator,nsContentIterator)817 NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator)
818 NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator)
819 
820 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSubtreeIterator)
821 NS_INTERFACE_MAP_END_INHERITING(nsContentIterator)
822 
823 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator, nsContentIterator,
824                                    mRange)
825 
826 void nsContentSubtreeIterator::LastRelease() {
827   mRange = nullptr;
828   nsContentIterator::LastRelease();
829 }
830 
831 /******************************************************
832  * repository cruft
833  ******************************************************/
834 
NS_NewContentSubtreeIterator()835 already_AddRefed<nsIContentIterator> NS_NewContentSubtreeIterator() {
836   nsCOMPtr<nsIContentIterator> iter = new nsContentSubtreeIterator();
837   return iter.forget();
838 }
839 
840 /******************************************************
841  * Init routines
842  ******************************************************/
843 
Init(nsINode * aRoot)844 nsresult nsContentSubtreeIterator::Init(nsINode* aRoot) {
845   return NS_ERROR_NOT_IMPLEMENTED;
846 }
847 
Init(nsIDOMRange * aRange)848 nsresult nsContentSubtreeIterator::Init(nsIDOMRange* aRange) {
849   MOZ_ASSERT(aRange);
850 
851   mIsDone = false;
852 
853   nsRange* range = static_cast<nsRange*>(aRange);
854   if (NS_WARN_IF(!range->IsPositioned())) {
855     return NS_ERROR_INVALID_ARG;
856   }
857 
858   mRange = range;
859 
860   return InitWithRange();
861 }
862 
Init(nsINode * aStartContainer,uint32_t aStartOffset,nsINode * aEndContainer,uint32_t aEndOffset)863 nsresult nsContentSubtreeIterator::Init(nsINode* aStartContainer,
864                                         uint32_t aStartOffset,
865                                         nsINode* aEndContainer,
866                                         uint32_t aEndOffset) {
867   return Init(RawRangeBoundary(aStartContainer, aStartOffset),
868               RawRangeBoundary(aEndContainer, aEndOffset));
869 }
870 
Init(const RawRangeBoundary & aStart,const RawRangeBoundary & aEnd)871 nsresult nsContentSubtreeIterator::Init(const RawRangeBoundary& aStart,
872                                         const RawRangeBoundary& aEnd) {
873   mIsDone = false;
874 
875   RefPtr<nsRange> range;
876   nsresult rv = nsRange::CreateRange(aStart, aEnd, getter_AddRefs(range));
877   if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
878       NS_WARN_IF(!range->IsPositioned())) {
879     return NS_ERROR_INVALID_ARG;
880   }
881 
882   if (NS_WARN_IF(range->StartRef() != aStart) ||
883       NS_WARN_IF(range->EndRef() != aEnd)) {
884     return NS_ERROR_UNEXPECTED;
885   }
886 
887   mRange = Move(range);
888 
889   return InitWithRange();
890 }
891 
InitWithRange()892 nsresult nsContentSubtreeIterator::InitWithRange() {
893   MOZ_ASSERT(mRange);
894   MOZ_ASSERT(mRange->IsPositioned());
895 
896   // get the start node and offset, convert to nsINode
897   mCommonParent = mRange->GetCommonAncestor();
898   nsINode* startContainer = mRange->GetStartContainer();
899   int32_t startOffset = mRange->StartOffset();
900   nsINode* endContainer = mRange->GetEndContainer();
901   int32_t endOffset = mRange->EndOffset();
902   MOZ_ASSERT(mCommonParent && startContainer && endContainer);
903   // Bug 767169
904   MOZ_ASSERT(uint32_t(startOffset) <= startContainer->Length() &&
905              uint32_t(endOffset) <= endContainer->Length());
906 
907   // short circuit when start node == end node
908   if (startContainer == endContainer) {
909     nsINode* child = startContainer->GetFirstChild();
910 
911     if (!child || startOffset == endOffset) {
912       // Text node, empty container, or collapsed
913       MakeEmpty();
914       return NS_OK;
915     }
916   }
917 
918   // cache ancestors
919   nsContentUtils::GetAncestorsAndOffsets(endContainer->AsDOMNode(), endOffset,
920                                          &mEndNodes, &mEndOffsets);
921 
922   nsIContent* firstCandidate = nullptr;
923   nsIContent* lastCandidate = nullptr;
924 
925   // find first node in range
926   int32_t offset = mRange->StartOffset();
927 
928   nsINode* node = nullptr;
929   if (!startContainer->GetChildCount()) {
930     // no children, start at the node itself
931     node = startContainer;
932   } else {
933     nsIContent* child = startContainer->GetChildAt_Deprecated(offset);
934     if (!child) {
935       // offset after last child
936       node = startContainer;
937     } else {
938       firstCandidate = child;
939     }
940   }
941 
942   if (!firstCandidate) {
943     // then firstCandidate is next node after node
944     firstCandidate = GetNextSibling(node);
945 
946     if (!firstCandidate) {
947       MakeEmpty();
948       return NS_OK;
949     }
950   }
951 
952   firstCandidate = GetDeepFirstChild(firstCandidate);
953 
954   // confirm that this first possible contained node is indeed contained.  Else
955   // we have a range that does not fully contain any node.
956 
957   bool nodeBefore, nodeAfter;
958   MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(firstCandidate, mRange,
959                                                   &nodeBefore, &nodeAfter));
960 
961   if (nodeBefore || nodeAfter) {
962     MakeEmpty();
963     return NS_OK;
964   }
965 
966   // cool, we have the first node in the range.  Now we walk up its ancestors
967   // to find the most senior that is still in the range.  That's the real first
968   // node.
969   mFirst = GetTopAncestorInRange(firstCandidate);
970 
971   // now to find the last node
972   offset = mRange->EndOffset();
973   int32_t numChildren = endContainer->GetChildCount();
974 
975   if (offset > numChildren) {
976     // Can happen for text nodes
977     offset = numChildren;
978   }
979   if (!offset || !numChildren) {
980     node = endContainer;
981   } else {
982     lastCandidate = endContainer->GetChildAt_Deprecated(--offset);
983     NS_ASSERTION(lastCandidate,
984                  "tree traversal trouble in nsContentSubtreeIterator::Init");
985   }
986 
987   if (!lastCandidate) {
988     // then lastCandidate is prev node before node
989     lastCandidate = GetPrevSibling(node);
990   }
991 
992   if (!lastCandidate) {
993     MakeEmpty();
994     return NS_OK;
995   }
996 
997   lastCandidate = GetDeepLastChild(lastCandidate);
998 
999   // confirm that this last possible contained node is indeed contained.  Else
1000   // we have a range that does not fully contain any node.
1001 
1002   MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(lastCandidate, mRange,
1003                                                   &nodeBefore, &nodeAfter));
1004 
1005   if (nodeBefore || nodeAfter) {
1006     MakeEmpty();
1007     return NS_OK;
1008   }
1009 
1010   // cool, we have the last node in the range.  Now we walk up its ancestors to
1011   // find the most senior that is still in the range.  That's the real first
1012   // node.
1013   mLast = GetTopAncestorInRange(lastCandidate);
1014 
1015   mCurNode = mFirst;
1016 
1017   return NS_OK;
1018 }
1019 
1020 /****************************************************************
1021  * nsContentSubtreeIterator overrides of ContentIterator routines
1022  ****************************************************************/
1023 
1024 // we can't call PositionAt in a subtree iterator...
First()1025 void nsContentSubtreeIterator::First() {
1026   mIsDone = mFirst == nullptr;
1027 
1028   mCurNode = mFirst;
1029 }
1030 
1031 // we can't call PositionAt in a subtree iterator...
Last()1032 void nsContentSubtreeIterator::Last() {
1033   mIsDone = mLast == nullptr;
1034 
1035   mCurNode = mLast;
1036 }
1037 
Next()1038 void nsContentSubtreeIterator::Next() {
1039   if (mIsDone || !mCurNode) {
1040     return;
1041   }
1042 
1043   if (mCurNode == mLast) {
1044     mIsDone = true;
1045     return;
1046   }
1047 
1048   nsINode* nextNode = GetNextSibling(mCurNode);
1049   NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
1050 
1051   int32_t i = mEndNodes.IndexOf(nextNode);
1052   while (i != -1) {
1053     // as long as we are finding ancestors of the endpoint of the range,
1054     // dive down into their children
1055     nextNode = nextNode->GetFirstChild();
1056     NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
1057 
1058     // should be impossible to get a null pointer.  If we went all the way
1059     // down the child chain to the bottom without finding an interior node,
1060     // then the previous node should have been the last, which was
1061     // was tested at top of routine.
1062     i = mEndNodes.IndexOf(nextNode);
1063   }
1064 
1065   mCurNode = nextNode;
1066 
1067   // This shouldn't be needed, but since our selection code can put us
1068   // in a situation where mLast is in generated content, we need this
1069   // to stop the iterator when we've walked past past the last node!
1070   mIsDone = mCurNode == nullptr;
1071 }
1072 
Prev()1073 void nsContentSubtreeIterator::Prev() {
1074   // Prev should be optimized to use the mStartNodes, just as Next
1075   // uses mEndNodes.
1076   if (mIsDone || !mCurNode) {
1077     return;
1078   }
1079 
1080   if (mCurNode == mFirst) {
1081     mIsDone = true;
1082     return;
1083   }
1084 
1085   // If any of these function calls return null, so will all succeeding ones,
1086   // so mCurNode will wind up set to null.
1087   nsINode* prevNode = GetDeepFirstChild(mCurNode);
1088 
1089   prevNode = PrevNode(prevNode);
1090 
1091   prevNode = GetDeepLastChild(prevNode);
1092 
1093   mCurNode = GetTopAncestorInRange(prevNode);
1094 
1095   // This shouldn't be needed, but since our selection code can put us
1096   // in a situation where mFirst is in generated content, we need this
1097   // to stop the iterator when we've walked past past the first node!
1098   mIsDone = mCurNode == nullptr;
1099 }
1100 
PositionAt(nsINode * aCurNode)1101 nsresult nsContentSubtreeIterator::PositionAt(nsINode* aCurNode) {
1102   NS_ERROR("Not implemented!");
1103 
1104   return NS_ERROR_NOT_IMPLEMENTED;
1105 }
1106 
1107 /****************************************************************
1108  * nsContentSubtreeIterator helper routines
1109  ****************************************************************/
1110 
GetTopAncestorInRange(nsINode * aNode)1111 nsIContent* nsContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode) {
1112   if (!aNode || !aNode->GetParentNode()) {
1113     return nullptr;
1114   }
1115 
1116   // aNode has a parent, so it must be content.
1117   nsIContent* content = aNode->AsContent();
1118 
1119   // sanity check: aNode is itself in the range
1120   bool nodeBefore, nodeAfter;
1121   nsresult res =
1122       nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter);
1123   NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
1124                "aNode isn't in mRange, or something else weird happened");
1125   if (NS_FAILED(res) || nodeBefore || nodeAfter) {
1126     return nullptr;
1127   }
1128 
1129   while (content) {
1130     nsIContent* parent = content->GetParent();
1131     // content always has a parent.  If its parent is the root, however --
1132     // i.e., either it's not content, or it is content but its own parent is
1133     // null -- then we're finished, since we don't go up to the root.
1134     //
1135     // We have to special-case this because CompareNodeToRange treats the root
1136     // node differently -- see bug 765205.
1137     if (!parent || !parent->GetParentNode()) {
1138       return content;
1139     }
1140     MOZ_ALWAYS_SUCCEEDS(
1141         nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter));
1142 
1143     if (nodeBefore || nodeAfter) {
1144       return content;
1145     }
1146     content = parent;
1147   }
1148 
1149   MOZ_CRASH("This should only be possible if aNode was null");
1150 }
1151