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/. */
7 #ifndef mozilla_ContentIterator_h
8 #define mozilla_ContentIterator_h
10 #include "mozilla/RangeBoundary.h"
12 #include "nsCycleCollectionParticipant.h"
22 * ContentIteratorBase is a base class of PostContentIterator,
23 * PreContentIterator and ContentSubtreeIterator. Making each concrete
24 * classes "final", compiler can avoid virtual calls if they are treated
25 * by the users directly.
27 class ContentIteratorBase
{
29 ContentIteratorBase() = delete;
30 ContentIteratorBase(const ContentIteratorBase
&) = delete;
31 ContentIteratorBase
& operator=(const ContentIteratorBase
&) = delete;
32 virtual ~ContentIteratorBase();
34 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentIteratorBase
)
37 * Allows to iterate over the inclusive descendants
38 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant) of
41 virtual nsresult
Init(nsINode
* aRoot
);
43 virtual nsresult
Init(nsRange
* aRange
);
44 virtual nsresult
Init(nsINode
* aStartContainer
, uint32_t aStartOffset
,
45 nsINode
* aEndContainer
, uint32_t aEndOffset
);
46 virtual nsresult
Init(const RawRangeBoundary
& aStart
,
47 const RawRangeBoundary
& aEnd
);
54 nsINode
* GetCurrentNode() const { return mCurNode
; }
56 bool IsDone() const { return !mCurNode
; }
58 virtual nsresult
PositionAt(nsINode
* aCurNode
);
62 Pre
, /*!< <https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR)>.
64 Post
/*!< <https://en.wikipedia.org/wiki/Tree_traversal#Post-order_(LRN)>.
68 explicit ContentIteratorBase(Order aOrder
);
73 * Callers must guarantee that:
74 * - Neither aStartContainer nor aEndContainer is nullptr.
75 * - aStartOffset and aEndOffset are valid for its container.
76 * - The start point and the end point are in document order.
78 nsresult
InitInternal(const RawRangeBoundary
& aStart
,
79 const RawRangeBoundary
& aEnd
);
81 // Recursively get the deepest first/last child of aRoot. This will return
82 // aRoot itself if it has no children.
83 static nsINode
* GetDeepFirstChild(nsINode
* aRoot
);
84 static nsIContent
* GetDeepFirstChild(nsIContent
* aRoot
);
85 static nsINode
* GetDeepLastChild(nsINode
* aRoot
);
86 static nsIContent
* GetDeepLastChild(nsIContent
* aRoot
);
88 // Get the next/previous sibling of aNode, or its parent's, or grandparent's,
89 // etc. Returns null if aNode and all its ancestors have no next/previous
91 static nsIContent
* GetNextSibling(nsINode
* aNode
);
92 static nsIContent
* GetPrevSibling(nsINode
* aNode
);
94 nsINode
* NextNode(nsINode
* aNode
);
95 nsINode
* PrevNode(nsINode
* aNode
);
99 nsCOMPtr
<nsINode
> mCurNode
;
100 nsCOMPtr
<nsINode
> mFirst
;
101 nsCOMPtr
<nsINode
> mLast
;
102 // See <https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor>.
103 nsCOMPtr
<nsINode
> mClosestCommonInclusiveAncestor
;
107 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
108 ContentIteratorBase
&, const char*,
110 friend void ImplCycleCollectionUnlink(ContentIteratorBase
&);
114 * A simple iterator class for traversing the content in "close tag" order.
116 class PostContentIterator final
: public ContentIteratorBase
{
118 PostContentIterator() : ContentIteratorBase(Order::Post
) {}
119 PostContentIterator(const PostContentIterator
&) = delete;
120 PostContentIterator
& operator=(const PostContentIterator
&) = delete;
121 virtual ~PostContentIterator() = default;
122 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
123 PostContentIterator
&, const char*,
125 friend void ImplCycleCollectionUnlink(PostContentIterator
&);
128 inline void ImplCycleCollectionTraverse(
129 nsCycleCollectionTraversalCallback
& aCallback
, PostContentIterator
& aField
,
130 const char* aName
, uint32_t aFlags
= 0) {
131 ImplCycleCollectionTraverse(
132 aCallback
, static_cast<ContentIteratorBase
&>(aField
), aName
, aFlags
);
135 inline void ImplCycleCollectionUnlink(PostContentIterator
& aField
) {
136 ImplCycleCollectionUnlink(static_cast<ContentIteratorBase
&>(aField
));
140 * A simple iterator class for traversing the content in "start tag" order.
142 class PreContentIterator final
: public ContentIteratorBase
{
144 PreContentIterator() : ContentIteratorBase(Order::Pre
) {}
145 PreContentIterator(const PreContentIterator
&) = delete;
146 PreContentIterator
& operator=(const PreContentIterator
&) = delete;
147 virtual ~PreContentIterator() = default;
148 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
149 PreContentIterator
&, const char*,
151 friend void ImplCycleCollectionUnlink(PreContentIterator
&);
154 inline void ImplCycleCollectionTraverse(
155 nsCycleCollectionTraversalCallback
& aCallback
, PreContentIterator
& aField
,
156 const char* aName
, uint32_t aFlags
= 0) {
157 ImplCycleCollectionTraverse(
158 aCallback
, static_cast<ContentIteratorBase
&>(aField
), aName
, aFlags
);
161 inline void ImplCycleCollectionUnlink(PreContentIterator
& aField
) {
162 ImplCycleCollectionUnlink(static_cast<ContentIteratorBase
&>(aField
));
166 * A simple iterator class for traversing the content in "top subtree" order.
168 class ContentSubtreeIterator final
: public ContentIteratorBase
{
170 ContentSubtreeIterator() : ContentIteratorBase(Order::Pre
) {}
171 ContentSubtreeIterator(const ContentSubtreeIterator
&) = delete;
172 ContentSubtreeIterator
& operator=(const ContentSubtreeIterator
&) = delete;
173 virtual ~ContentSubtreeIterator() = default;
178 virtual nsresult
Init(nsINode
* aRoot
) override
;
180 virtual nsresult
Init(nsRange
* aRange
) override
;
181 virtual nsresult
Init(nsINode
* aStartContainer
, uint32_t aStartOffset
,
182 nsINode
* aEndContainer
, uint32_t aEndOffset
) override
;
183 virtual nsresult
Init(const RawRangeBoundary
& aStartBoundary
,
184 const RawRangeBoundary
& aEndBoundary
) override
;
186 void Next() override
;
187 void Prev() override
;
188 // Must override these because we don't do PositionAt
189 void First() override
;
190 // Must override these because we don't do PositionAt
191 void Last() override
;
193 nsresult
PositionAt(nsINode
* aCurNode
) override
;
195 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
196 ContentSubtreeIterator
&, const char*,
198 friend void ImplCycleCollectionUnlink(ContentSubtreeIterator
&);
202 * See <https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor>.
204 void CacheInclusiveAncestorsOfEndContainer();
207 * @return may be nullptr.
209 nsIContent
* DetermineCandidateForFirstContent() const;
212 * @return may be nullptr.
214 nsIContent
* DetermineCandidateForLastContent() const;
217 * @return may be nullptr.
219 nsIContent
* DetermineFirstContent() const;
222 * @return may be nullptr.
224 nsIContent
* DetermineLastContent() const;
227 * Callers must guarantee that mRange isn't nullptr and is positioned.
229 nsresult
InitWithRange();
231 // Returns the highest inclusive ancestor of aNode that's in the range
232 // (possibly aNode itself). Returns null if aNode is null, or is not itself
233 // in the range. A node is in the range if (node, 0) comes strictly after
234 // the range endpoint, and (node, node.length) comes strictly before it, so
235 // the range's start and end nodes will never be considered "in" it.
236 nsIContent
* GetTopAncestorInRange(nsINode
* aNode
) const;
238 RefPtr
<nsRange
> mRange
;
240 // See <https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor>.
241 AutoTArray
<nsIContent
*, 8> mInclusiveAncestorsOfEndContainer
;
244 inline void ImplCycleCollectionTraverse(
245 nsCycleCollectionTraversalCallback
& aCallback
,
246 ContentSubtreeIterator
& aField
, const char* aName
, uint32_t aFlags
= 0) {
247 ImplCycleCollectionTraverse(aCallback
, aField
.mRange
, aName
, aFlags
);
248 ImplCycleCollectionTraverse(
249 aCallback
, static_cast<ContentIteratorBase
&>(aField
), aName
, aFlags
);
252 inline void ImplCycleCollectionUnlink(ContentSubtreeIterator
& aField
) {
253 ImplCycleCollectionUnlink(aField
.mRange
);
254 ImplCycleCollectionUnlink(static_cast<ContentIteratorBase
&>(aField
));
257 } // namespace mozilla
259 #endif // #ifndef mozilla_ContentIterator_h