Bug 1700051: part 35) Reduce accessibility of `mSoftText.mDOMMapping` to `private...
[gecko.git] / dom / base / ChildIterator.h
bloba8fe672f30290e9e3bd564c6f7658fb20b3ad7f9
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef ChildIterator_h
8 #define ChildIterator_h
10 #include "nsIContent.h"
11 #include "nsIContentInlines.h"
12 #include <stdint.h>
14 /**
15 * Iterates over the children on a node. If a child is an insertion point,
16 * iterates over the children inserted there instead, or the default content
17 * if no children are inserted there.
19 * The FlattenedChildIterator expands any anonymous content bound from an XBL
20 * binding's <xbl:content> element.
23 class nsIContent;
25 namespace mozilla {
26 namespace dom {
28 // This class iterates normal DOM child nodes of a given DOM node with
29 // <xbl:children> nodes replaced by the elements that have been filtered into
30 // that insertion point. Any bindings on the given element are ignored for
31 // purposes of determining which insertion point children are filtered into. The
32 // iterator can be initialized to start at the end by providing false for
33 // aStartAtBeginning in order to start iterating in reverse from the last child.
34 class ExplicitChildIterator {
35 public:
36 explicit ExplicitChildIterator(const nsIContent* aParent,
37 bool aStartAtBeginning = true);
39 nsIContent* GetNextChild();
41 // Looks for aChildToFind respecting insertion points until aChildToFind is
42 // found. This version can take shortcuts that the two-argument version
43 // can't, so can be faster (and in fact can be O(1) instead of O(N) in many
44 // cases).
45 bool Seek(const nsIContent* aChildToFind);
47 // Looks for aChildToFind respecting insertion points until aChildToFind is
48 // found. or aBound is found. If aBound is nullptr then the seek is unbounded.
49 // Returns whether aChildToFind was found as an explicit child prior to
50 // encountering aBound.
51 bool Seek(const nsIContent* aChildToFind, nsIContent* aBound) {
52 // It would be nice to assert that we find aChildToFind, but bz thinks that
53 // we might not find aChildToFind when called from ContentInserted
54 // if first-letter frames are about.
56 // We can't easily take shortcuts here because we'd have to have a way to
57 // compare aChildToFind to aBound.
58 nsIContent* child;
59 do {
60 child = GetNextChild();
61 } while (child && child != aChildToFind && child != aBound);
63 return child == aChildToFind;
66 // Returns the current target of this iterator (which might be an explicit
67 // child of the node, fallback content of an insertion point or
68 // a node distributed to an insertion point.
69 nsIContent* Get() const;
71 // The inverse of GetNextChild. Properly steps in and out of insertion
72 // points.
73 nsIContent* GetPreviousChild();
75 protected:
76 // The parent of the children being iterated. For the FlattenedChildIterator,
77 // if there is a binding attached to the original parent, mParent points to
78 // the <xbl:content> element for the binding.
79 const nsIContent* mParent;
81 // If parent is a slot element, this points to the parent as HTMLSlotElement,
82 // otherwise, it's null.
83 const HTMLSlotElement* mParentAsSlot;
85 // The current child. When we encounter an insertion point,
86 // mChild remains as the insertion point whose content we're iterating (and
87 // our state is controled by mDefaultChild or mIndexInInserted depending on
88 // whether the insertion point expands to its default content or not).
89 nsIContent* mChild;
91 // If non-null, this points to the current default content for the current
92 // insertion point that we're iterating (i.e. mChild, which must be an
93 // nsXBLChildrenElement or HTMLContentElement). Once this transitions back
94 // to null, we continue iterating at mChild's next sibling.
95 nsIContent* mDefaultChild;
97 // A flag to let us know that we haven't started iterating yet.
98 bool mIsFirst;
100 // If not zero, we're iterating inserted children for an insertion point. This
101 // is an index into mChild's inserted children array (mChild must be an
102 // nsXBLChildrenElement). The index is one past the "current" child (as
103 // opposed to mChild which represents the "current" child).
104 uint32_t mIndexInInserted;
107 // Iterates over the flattened children of a node, which accounts for anonymous
108 // children and nodes moved by insertion points. If a node has anonymous
109 // children, those are iterated over. The iterator can be initialized to start
110 // at the end by providing false for aStartAtBeginning in order to start
111 // iterating in reverse from the last child.
112 class FlattenedChildIterator : public ExplicitChildIterator {
113 public:
114 explicit FlattenedChildIterator(const nsIContent* aParent,
115 bool aStartAtBeginning = true)
116 : ExplicitChildIterator(aParent, aStartAtBeginning),
117 mOriginalContent(aParent) {
118 Init(false);
121 bool ShadowDOMInvolved() { return mShadowDOMInvolved; }
123 const nsIContent* Parent() const { return mOriginalContent; }
125 private:
126 void Init(bool aIgnoreXBL);
128 protected:
130 * This constructor is a hack to help AllChildrenIterator which sometimes
131 * doesn't want to consider XBL.
133 FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
134 bool aStartAtBeginning = true)
135 : ExplicitChildIterator(aParent, aStartAtBeginning),
136 mOriginalContent(aParent) {
137 bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
138 Init(ignoreXBL);
141 const nsIContent* mOriginalContent;
143 private:
144 // For certain optimizations, nsCSSFrameConstructor needs to know if the child
145 // list of the element that we're iterating matches its .childNodes.
146 bool mShadowDOMInvolved = false;
150 * AllChildrenIterator traverses the children of an element including before /
151 * after content and optionally XBL children. The iterator can be initialized
152 * to start at the end by providing false for aStartAtBeginning in order to
153 * start iterating in reverse from the last child.
155 * Note: it assumes that no mutation of the DOM or frame tree takes place during
156 * iteration, and will break horribly if that is not true.
158 class AllChildrenIterator : private FlattenedChildIterator {
159 public:
160 AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
161 bool aStartAtBeginning = true)
162 : FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
163 mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
164 mFlags(aFlags),
165 mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) {}
167 #ifdef DEBUG
168 AllChildrenIterator(AllChildrenIterator&&) = default;
170 AllChildrenIterator& operator=(AllChildrenIterator&& aOther) {
171 // Explicitly call the destructor to ensure the assertion in the destructor
172 // is checked.
173 this->~AllChildrenIterator();
174 new (this) AllChildrenIterator(std::move(aOther));
175 return *this;
178 ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
179 #endif
181 // Returns the current target the iterator is at, or null if the iterator
182 // doesn't point to any child node (either eAtBegin or eAtEnd phase).
183 nsIContent* Get() const;
185 // Seeks the given node in children of a parent element, starting from
186 // the current iterator's position, and sets the iterator at the given child
187 // node if it was found.
188 bool Seek(const nsIContent* aChildToFind);
190 nsIContent* GetNextChild();
191 nsIContent* GetPreviousChild();
193 enum IteratorPhase {
194 eAtBegin,
195 eAtMarkerKid,
196 eAtBeforeKid,
197 eAtExplicitKids,
198 eAtAnonKids,
199 eAtAfterKid,
200 eAtEnd
202 IteratorPhase Phase() const { return mPhase; }
204 private:
205 // Helpers.
206 void AppendNativeAnonymousChildren();
208 // mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
209 // in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
210 // eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
211 // mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
212 // the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
213 // is somewhere before the first native anon child.
214 nsTArray<nsIContent*> mAnonKids;
215 uint32_t mAnonKidsIdx;
217 uint32_t mFlags;
218 IteratorPhase mPhase;
219 #ifdef DEBUG
220 // XXX we should really assert there are no frame tree changes as well, but
221 // there's no easy way to do that.
222 nsMutationGuard mMutationGuard;
223 #endif
227 * StyleChildrenIterator traverses the children of the element from the
228 * perspective of the style system, particularly the children we need to
229 * traverse during restyle.
231 * At present, this is identical to AllChildrenIterator with
232 * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent). We used to have
233 * detect and skip any native anonymous children that are used to implement some
234 * special magic in here that went away, but we keep the separate class so
235 * we can reintroduce special magic back if needed.
237 * Note: it assumes that no mutation of the DOM or frame tree takes place during
238 * iteration, and will break horribly if that is not true.
240 * We require this to be memmovable since Rust code can create and move
241 * StyleChildrenIterators.
243 class MOZ_NEEDS_MEMMOVABLE_MEMBERS StyleChildrenIterator
244 : private AllChildrenIterator {
245 public:
246 static nsIContent* GetParent(const nsIContent& aContent) {
247 nsINode* node = aContent.GetFlattenedTreeParentNodeForStyle();
248 return node && node->IsContent() ? node->AsContent() : nullptr;
251 explicit StyleChildrenIterator(const nsIContent* aContent,
252 bool aStartAtBeginning = true)
253 : AllChildrenIterator(
254 aContent,
255 nsIContent::eAllChildren |
256 nsIContent::eSkipDocumentLevelNativeAnonymousContent,
257 aStartAtBeginning) {
258 MOZ_COUNT_CTOR(StyleChildrenIterator);
261 StyleChildrenIterator(StyleChildrenIterator&& aOther)
262 : AllChildrenIterator(std::move(aOther)) {
263 MOZ_COUNT_CTOR(StyleChildrenIterator);
266 StyleChildrenIterator& operator=(StyleChildrenIterator&& aOther) = default;
268 MOZ_COUNTED_DTOR(StyleChildrenIterator)
270 using AllChildrenIterator::GetNextChild;
271 using AllChildrenIterator::GetPreviousChild;
272 using AllChildrenIterator::Seek;
275 } // namespace dom
276 } // namespace mozilla
278 #endif