|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 sw=2 et 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/. */ |
|
6 |
|
7 #ifndef ChildIterator_h |
|
8 #define ChildIterator_h |
|
9 |
|
10 /** |
|
11 * Iterates over the children on a node. If a child is an insertion point, |
|
12 * iterates over the children inserted there instead, or the default content |
|
13 * if no children are inserted there. |
|
14 * |
|
15 * The FlattenedChildIterator expands any anonymous content bound from an XBL |
|
16 * binding's <xbl:content> element. |
|
17 */ |
|
18 |
|
19 #include "nsIContent.h" |
|
20 |
|
21 namespace mozilla { |
|
22 namespace dom { |
|
23 |
|
24 // This class iterates normal DOM child nodes of a given DOM node with |
|
25 // <xbl:children> nodes replaced by the elements that have been filtered into that |
|
26 // insertion point. Any bindings on the given element are ignored for purposes |
|
27 // of determining which insertion point children are filtered into. The iterator |
|
28 // can be initialized to start at the end by providing false for aStartAtBeginning |
|
29 // in order to start iterating in reverse from the last child. |
|
30 class ExplicitChildIterator |
|
31 { |
|
32 public: |
|
33 ExplicitChildIterator(nsIContent* aParent, bool aStartAtBeginning = true) |
|
34 : mParent(aParent), |
|
35 mChild(nullptr), |
|
36 mDefaultChild(nullptr), |
|
37 mIndexInInserted(0), |
|
38 mIsFirst(aStartAtBeginning) |
|
39 { |
|
40 } |
|
41 |
|
42 nsIContent* GetNextChild(); |
|
43 |
|
44 // Looks for aChildToFind respecting insertion points until aChildToFind |
|
45 // or aBound is found. If aBound is nullptr then the seek is unbounded. Returns |
|
46 // whether aChildToFind was found as an explicit child prior to encountering |
|
47 // aBound. |
|
48 bool Seek(nsIContent* aChildToFind, nsIContent* aBound = nullptr) |
|
49 { |
|
50 // It would be nice to assert that we find aChildToFind, but bz thinks that |
|
51 // we might not find aChildToFind when called from ContentInserted |
|
52 // if first-letter frames are about. |
|
53 |
|
54 nsIContent* child; |
|
55 do { |
|
56 child = GetNextChild(); |
|
57 } while (child && child != aChildToFind && child != aBound); |
|
58 |
|
59 return child == aChildToFind; |
|
60 } |
|
61 |
|
62 // Returns the current target of this iterator (which might be an explicit |
|
63 // child of the node, fallback content of an insertion point or |
|
64 // a node distributed to an insertion point. |
|
65 nsIContent* Get(); |
|
66 |
|
67 // The inverse of GetNextChild. Properly steps in and out of insertion |
|
68 // points. |
|
69 nsIContent* GetPreviousChild(); |
|
70 |
|
71 protected: |
|
72 // The parent of the children being iterated. For the FlattenedChildIterator, |
|
73 // if there is a binding attached to the original parent, mParent points to |
|
74 // the <xbl:content> element for the binding. |
|
75 nsIContent* mParent; |
|
76 |
|
77 // The current child. When we encounter an insertion point, |
|
78 // mChild remains as the insertion point whose content we're iterating (and |
|
79 // our state is controled by mDefaultChild or mIndexInInserted depending on |
|
80 // whether the insertion point expands to its default content or not). |
|
81 nsIContent* mChild; |
|
82 |
|
83 // If non-null, this points to the current default content for the current |
|
84 // insertion point that we're iterating (i.e. mChild, which must be an |
|
85 // nsXBLChildrenElement or HTMLContentElement). Once this transitions back |
|
86 // to null, we continue iterating at mChild's next sibling. |
|
87 nsIContent* mDefaultChild; |
|
88 |
|
89 // If non-null, this points to an iterator of the explicit children of |
|
90 // the ShadowRoot projected by the current shadow element that we're |
|
91 // iterating. |
|
92 nsAutoPtr<ExplicitChildIterator> mShadowIterator; |
|
93 |
|
94 // If not zero, we're iterating inserted children for an insertion point. This |
|
95 // is an index into mChild's inserted children array (mChild must be an |
|
96 // nsXBLChildrenElement). The index is one past the "current" child (as |
|
97 // opposed to mChild which represents the "current" child). |
|
98 uint32_t mIndexInInserted; |
|
99 |
|
100 // A flag to let us know that we haven't started iterating yet. |
|
101 bool mIsFirst; |
|
102 }; |
|
103 |
|
104 // Iterates over the flattened children of a node, which accounts for anonymous |
|
105 // children and nodes moved by insertion points. If a node has anonymous |
|
106 // children, those are iterated over. |
|
107 class FlattenedChildIterator : public ExplicitChildIterator |
|
108 { |
|
109 public: |
|
110 FlattenedChildIterator(nsIContent* aParent); |
|
111 |
|
112 bool XBLInvolved() { return mXBLInvolved; } |
|
113 |
|
114 private: |
|
115 // For certain optimizations, nsCSSFrameConstructor needs to know if the |
|
116 // child list of the element that we're iterating matches its .childNodes. |
|
117 bool mXBLInvolved; |
|
118 }; |
|
119 |
|
120 } // namespace dom |
|
121 } // namespace mozilla |
|
122 |
|
123 #endif |