Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / ChildIterator.h
blobaf6b867883a4b22f21ac55ce12e38a30e444aab1
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 class nsIContent;
16 namespace mozilla::dom {
18 // Iterates over the flattened children of a node, that is, the regular DOM
19 // child nodes of a given DOM node, with assigned nodes as slot children, and
20 // shadow host children replaced by their shadow root.
22 // The iterator can be initialized to start at the end by providing false for
23 // aStartAtBeginning in order to start iterating in reverse from the last child.
24 class FlattenedChildIterator {
25 public:
26 explicit FlattenedChildIterator(const nsIContent* aParent,
27 bool aStartAtBeginning = true);
29 nsIContent* GetNextChild();
31 // Looks for aChildToFind respecting insertion points until aChildToFind is
32 // found. This can be O(1) instead of O(N) in many cases.
33 bool Seek(const nsIContent* aChildToFind);
35 // Returns the current target of this iterator (which might be an explicit
36 // child of the node, or a node assigned to a slot.
37 nsIContent* Get() const { return mChild; }
39 // Returns the original parent we were initialized with.
40 const nsIContent* Parent() const { return mOriginalParent; }
42 // The inverse of GetNextChild. Properly steps in and out of insertion
43 // points.
44 nsIContent* GetPreviousChild();
46 bool ShadowDOMInvolved() const { return mShadowDOMInvolved; }
48 protected:
49 // The parent of the children being iterated. For shadow hosts this will point
50 // to its shadow root.
51 const nsIContent* mParent;
53 // If parent is a slot element with assigned slots, this points to the parent
54 // as HTMLSlotElement, otherwise, it's null.
55 const HTMLSlotElement* mParentAsSlot = nullptr;
57 const nsIContent* mOriginalParent = nullptr;
59 // The current child.
60 nsIContent* mChild = nullptr;
62 // A flag to let us know that we haven't started iterating yet.
63 bool mIsFirst = false;
65 // The index of the current element in the slot assigned nodes. One-past the
66 // end to represent the last position.
67 uint32_t mIndexInInserted = 0u;
69 // For certain optimizations, nsCSSFrameConstructor needs to know if the child
70 // list of the element that we're iterating matches its .childNodes.
71 bool mShadowDOMInvolved = false;
74 /**
75 * AllChildrenIterator traverses the children of an element including before /
76 * after content and shadow DOM. The iterator can be initialized to start at
77 * the end by providing false for aStartAtBeginning in order to start iterating
78 * in reverse from the last child.
80 * Note: it assumes that no mutation of the DOM or frame tree takes place during
81 * iteration, and will break horribly if that is not true.
83 class AllChildrenIterator : private FlattenedChildIterator {
84 public:
85 AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
86 bool aStartAtBeginning = true)
87 : FlattenedChildIterator(aNode, aStartAtBeginning),
88 mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
89 mFlags(aFlags),
90 mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) {}
92 #ifdef DEBUG
93 AllChildrenIterator(AllChildrenIterator&&) = default;
95 AllChildrenIterator& operator=(AllChildrenIterator&& aOther) {
96 // Explicitly call the destructor to ensure the assertion in the destructor
97 // is checked.
98 this->~AllChildrenIterator();
99 new (this) AllChildrenIterator(std::move(aOther));
100 return *this;
103 ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
104 #endif
106 // Returns the current target the iterator is at, or null if the iterator
107 // doesn't point to any child node (either eAtBegin or eAtEnd phase).
108 nsIContent* Get() const;
110 // Seeks the given node in children of a parent element, starting from
111 // the current iterator's position, and sets the iterator at the given child
112 // node if it was found.
113 bool Seek(const nsIContent* aChildToFind);
115 nsIContent* GetNextChild();
116 nsIContent* GetPreviousChild();
118 enum IteratorPhase {
119 eAtBegin,
120 eAtMarkerKid,
121 eAtBeforeKid,
122 eAtFlatTreeKids,
123 eAtAnonKids,
124 eAtAfterKid,
125 eAtEnd
127 IteratorPhase Phase() const { return mPhase; }
129 private:
130 // Helpers.
131 void AppendNativeAnonymousChildren();
133 // mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
134 // in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
135 // eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
136 // mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
137 // the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
138 // is somewhere before the first native anon child.
139 nsTArray<nsIContent*> mAnonKids;
140 uint32_t mAnonKidsIdx;
142 uint32_t mFlags;
143 IteratorPhase mPhase;
144 #ifdef DEBUG
145 // XXX we should really assert there are no frame tree changes as well, but
146 // there's no easy way to do that.
147 nsMutationGuard mMutationGuard;
148 #endif
152 * StyleChildrenIterator traverses the children of the element from the
153 * perspective of the style system, particularly the children we need to
154 * traverse during restyle.
156 * At present, this is identical to AllChildrenIterator with
157 * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent). We used to have
158 * detect and skip any native anonymous children that are used to implement some
159 * special magic in here that went away, but we keep the separate class so
160 * we can reintroduce special magic back if needed.
162 * Note: it assumes that no mutation of the DOM or frame tree takes place during
163 * iteration, and will break horribly if that is not true.
165 * We require this to be memmovable since Rust code can create and move
166 * StyleChildrenIterators.
168 class MOZ_NEEDS_MEMMOVABLE_MEMBERS StyleChildrenIterator
169 : private AllChildrenIterator {
170 public:
171 static nsIContent* GetParent(const nsIContent& aContent) {
172 nsINode* node = aContent.GetFlattenedTreeParentNodeForStyle();
173 return node && node->IsContent() ? node->AsContent() : nullptr;
176 explicit StyleChildrenIterator(const nsIContent* aContent,
177 bool aStartAtBeginning = true)
178 : AllChildrenIterator(
179 aContent,
180 nsIContent::eAllChildren |
181 nsIContent::eSkipDocumentLevelNativeAnonymousContent,
182 aStartAtBeginning) {
183 MOZ_COUNT_CTOR(StyleChildrenIterator);
186 StyleChildrenIterator(StyleChildrenIterator&& aOther)
187 : AllChildrenIterator(std::move(aOther)) {
188 MOZ_COUNT_CTOR(StyleChildrenIterator);
191 StyleChildrenIterator& operator=(StyleChildrenIterator&& aOther) = default;
193 MOZ_COUNTED_DTOR(StyleChildrenIterator)
195 using AllChildrenIterator::GetNextChild;
196 using AllChildrenIterator::GetPreviousChild;
197 using AllChildrenIterator::Seek;
200 } // namespace mozilla::dom
202 #endif