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"
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
{
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
44 nsIContent
* GetPreviousChild();
46 bool ShadowDOMInvolved() const { return mShadowDOMInvolved
; }
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;
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;
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
{
85 AllChildrenIterator(const nsIContent
* aNode
, uint32_t aFlags
,
86 bool aStartAtBeginning
= true)
87 : FlattenedChildIterator(aNode
, aStartAtBeginning
),
88 mAnonKidsIdx(aStartAtBeginning
? UINT32_MAX
: 0),
90 mPhase(aStartAtBeginning
? eAtBegin
: eAtEnd
) {}
93 AllChildrenIterator(AllChildrenIterator
&&) = default;
95 AllChildrenIterator
& operator=(AllChildrenIterator
&& aOther
) {
96 // Explicitly call the destructor to ensure the assertion in the destructor
98 this->~AllChildrenIterator();
99 new (this) AllChildrenIterator(std::move(aOther
));
103 ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard
.Mutated(0)); }
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();
127 IteratorPhase
Phase() const { return mPhase
; }
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
;
143 IteratorPhase mPhase
;
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
;
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
{
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(
180 nsIContent::eAllChildren
|
181 nsIContent::eSkipDocumentLevelNativeAnonymousContent
,
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