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"
13 #include "nsIContent.h"
20 * ContentIteratorBase is a base class of PostContentIterator,
21 * PreContentIterator and ContentSubtreeIterator. Making each concrete
22 * classes "final", compiler can avoid virtual calls if they are treated
23 * by the users directly.
25 class ContentIteratorBase
{
27 ContentIteratorBase() = delete;
28 ContentIteratorBase(const ContentIteratorBase
&) = delete;
29 ContentIteratorBase
& operator=(const ContentIteratorBase
&) = delete;
30 virtual ~ContentIteratorBase() = default;
32 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentIteratorBase
)
34 virtual nsresult
Init(nsINode
* aRoot
);
35 virtual nsresult
Init(nsRange
* aRange
);
36 virtual nsresult
Init(nsINode
* aStartContainer
, uint32_t aStartOffset
,
37 nsINode
* aEndContainer
, uint32_t aEndOffset
);
38 virtual nsresult
Init(const RawRangeBoundary
& aStart
,
39 const RawRangeBoundary
& aEnd
);
46 virtual nsINode
* GetCurrentNode();
48 virtual bool IsDone();
50 virtual nsresult
PositionAt(nsINode
* aCurNode
);
53 explicit ContentIteratorBase(bool aPre
);
56 * Callers must guarantee that:
57 * - Neither aStartContainer nor aEndContainer is nullptr.
58 * - aStartOffset and aEndOffset are valid for its container.
59 * - The start point and the end point are in document order.
61 nsresult
InitInternal(const RawRangeBoundary
& aStart
,
62 const RawRangeBoundary
& aEnd
);
64 // Recursively get the deepest first/last child of aRoot. This will return
65 // aRoot itself if it has no children.
66 nsINode
* GetDeepFirstChild(nsINode
* aRoot
);
67 nsIContent
* GetDeepFirstChild(nsIContent
* aRoot
);
68 nsINode
* GetDeepLastChild(nsINode
* aRoot
);
69 nsIContent
* GetDeepLastChild(nsIContent
* aRoot
);
71 // Get the next/previous sibling of aNode, or its parent's, or grandparent's,
72 // etc. Returns null if aNode and all its ancestors have no next/previous
74 nsIContent
* GetNextSibling(nsINode
* aNode
);
75 nsIContent
* GetPrevSibling(nsINode
* aNode
);
77 nsINode
* NextNode(nsINode
* aNode
);
78 nsINode
* PrevNode(nsINode
* aNode
);
82 nsCOMPtr
<nsINode
> mCurNode
;
83 nsCOMPtr
<nsINode
> mFirst
;
84 nsCOMPtr
<nsINode
> mLast
;
85 nsCOMPtr
<nsINode
> mCommonParent
;
89 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
90 ContentIteratorBase
&, const char*,
92 friend void ImplCycleCollectionUnlink(ContentIteratorBase
&);
95 // Each concreate class of ContentIteratorBase may be owned by another class
96 // which may be owned by JS. Therefore, all of them should be in the cycle
97 // collection. However, we cannot make non-refcountable classes only with the
98 // macros. So, we need to make them cycle collectable without the macros.
99 inline void ImplCycleCollectionTraverse(
100 nsCycleCollectionTraversalCallback
& aCallback
, ContentIteratorBase
& aField
,
101 const char* aName
, uint32_t aFlags
= 0) {
102 ImplCycleCollectionTraverse(aCallback
, aField
.mCurNode
, aName
, aFlags
);
103 ImplCycleCollectionTraverse(aCallback
, aField
.mFirst
, aName
, aFlags
);
104 ImplCycleCollectionTraverse(aCallback
, aField
.mLast
, aName
, aFlags
);
105 ImplCycleCollectionTraverse(aCallback
, aField
.mCommonParent
, aName
, aFlags
);
108 inline void ImplCycleCollectionUnlink(ContentIteratorBase
& aField
) {
109 ImplCycleCollectionUnlink(aField
.mCurNode
);
110 ImplCycleCollectionUnlink(aField
.mFirst
);
111 ImplCycleCollectionUnlink(aField
.mLast
);
112 ImplCycleCollectionUnlink(aField
.mCommonParent
);
116 * A simple iterator class for traversing the content in "close tag" order.
118 class PostContentIterator final
: public ContentIteratorBase
{
120 PostContentIterator() : ContentIteratorBase(false) {}
121 PostContentIterator(const PostContentIterator
&) = delete;
122 PostContentIterator
& operator=(const PostContentIterator
&) = delete;
123 virtual ~PostContentIterator() = default;
124 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
125 PostContentIterator
&, const char*,
127 friend void ImplCycleCollectionUnlink(PostContentIterator
&);
130 inline void ImplCycleCollectionTraverse(
131 nsCycleCollectionTraversalCallback
& aCallback
, PostContentIterator
& aField
,
132 const char* aName
, uint32_t aFlags
= 0) {
133 ImplCycleCollectionTraverse(
134 aCallback
, static_cast<ContentIteratorBase
&>(aField
), aName
, aFlags
);
137 inline void ImplCycleCollectionUnlink(PostContentIterator
& aField
) {
138 ImplCycleCollectionUnlink(static_cast<ContentIteratorBase
&>(aField
));
142 * A simple iterator class for traversing the content in "start tag" order.
144 class PreContentIterator final
: public ContentIteratorBase
{
146 PreContentIterator() : ContentIteratorBase(true) {}
147 PreContentIterator(const PreContentIterator
&) = delete;
148 PreContentIterator
& operator=(const PreContentIterator
&) = delete;
149 virtual ~PreContentIterator() = default;
150 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
151 PreContentIterator
&, const char*,
153 friend void ImplCycleCollectionUnlink(PreContentIterator
&);
156 inline void ImplCycleCollectionTraverse(
157 nsCycleCollectionTraversalCallback
& aCallback
, PreContentIterator
& aField
,
158 const char* aName
, uint32_t aFlags
= 0) {
159 ImplCycleCollectionTraverse(
160 aCallback
, static_cast<ContentIteratorBase
&>(aField
), aName
, aFlags
);
163 inline void ImplCycleCollectionUnlink(PreContentIterator
& aField
) {
164 ImplCycleCollectionUnlink(static_cast<ContentIteratorBase
&>(aField
));
168 * A simple iterator class for traversing the content in "top subtree" order.
170 class ContentSubtreeIterator final
: public ContentIteratorBase
{
172 ContentSubtreeIterator() : ContentIteratorBase(true) {}
173 ContentSubtreeIterator(const ContentSubtreeIterator
&) = delete;
174 ContentSubtreeIterator
& operator=(const ContentSubtreeIterator
&) = delete;
175 virtual ~ContentSubtreeIterator() = default;
177 virtual nsresult
Init(nsINode
* aRoot
) override
;
178 virtual nsresult
Init(nsRange
* aRange
) override
;
179 virtual nsresult
Init(nsINode
* aStartContainer
, uint32_t aStartOffset
,
180 nsINode
* aEndContainer
, uint32_t aEndOffset
) override
;
181 virtual nsresult
Init(const RawRangeBoundary
& aStart
,
182 const RawRangeBoundary
& aEnd
) override
;
184 virtual void Next() override
;
185 virtual void Prev() override
;
186 // Must override these because we don't do PositionAt
187 virtual void First() override
;
188 // Must override these because we don't do PositionAt
189 virtual void Last() override
;
191 virtual nsresult
PositionAt(nsINode
* aCurNode
) override
;
193 friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
&,
194 ContentSubtreeIterator
&, const char*,
196 friend void ImplCycleCollectionUnlink(ContentSubtreeIterator
&);
200 * Callers must guarantee that mRange isn't nullptr and is positioned.
202 nsresult
InitWithRange();
204 // Returns the highest inclusive ancestor of aNode that's in the range
205 // (possibly aNode itself). Returns null if aNode is null, or is not itself
206 // in the range. A node is in the range if (node, 0) comes strictly after
207 // the range endpoint, and (node, node.length) comes strictly before it, so
208 // the range's start and end nodes will never be considered "in" it.
209 nsIContent
* GetTopAncestorInRange(nsINode
* aNode
);
211 RefPtr
<nsRange
> mRange
;
213 AutoTArray
<nsIContent
*, 8> mEndNodes
;
216 inline void ImplCycleCollectionTraverse(
217 nsCycleCollectionTraversalCallback
& aCallback
,
218 ContentSubtreeIterator
& aField
, const char* aName
, uint32_t aFlags
= 0) {
219 ImplCycleCollectionTraverse(aCallback
, aField
.mRange
, aName
, aFlags
);
220 ImplCycleCollectionTraverse(
221 aCallback
, static_cast<ContentIteratorBase
&>(aField
), aName
, aFlags
);
224 inline void ImplCycleCollectionUnlink(ContentSubtreeIterator
& aField
) {
225 ImplCycleCollectionUnlink(aField
.mRange
);
226 ImplCycleCollectionUnlink(static_cast<ContentIteratorBase
&>(aField
));
229 } // namespace mozilla
231 #endif // #ifndef mozilla_ContentIterator_h