2 * Copyright (C) 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "NodeTraversal.h"
27 #include "ShadowRoot.h"
29 #ifndef ComposedTreeIterator_h
30 #define ComposedTreeIterator_h
34 class HTMLSlotElement;
36 class ComposedTreeIterator {
38 ComposedTreeIterator(ContainerNode& root);
39 ComposedTreeIterator(ContainerNode& root, Node& current);
41 Node& operator*() { return *m_current; }
42 Node* operator->() { return m_current; }
44 bool operator==(const ComposedTreeIterator& other) const { return m_current == other.m_current; }
45 bool operator!=(const ComposedTreeIterator& other) const { return m_current != other.m_current; }
47 ComposedTreeIterator& operator++() { return traverseNextSibling(); }
49 ComposedTreeIterator& traverseNext();
50 ComposedTreeIterator& traverseNextSibling();
51 ComposedTreeIterator& traversePreviousSibling();
52 ComposedTreeIterator& traverseParent();
55 void initializeShadowStack();
56 void traverseNextInShadowTree();
57 void traverseParentInShadowTree();
58 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
59 void traverseNextSiblingSlot();
60 void traversePreviousSiblingSlot();
63 ContainerNode& m_root;
64 Node* m_current { 0 };
66 struct ShadowContext {
67 ShadowContext(Element* host)
72 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
73 HTMLSlotElement* currentSlot { nullptr };
74 unsigned currentSlotNodeIndex { 0 };
77 Vector<ShadowContext, 4> m_shadowStack;
80 inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root)
83 ASSERT(!is<ShadowRoot>(m_root));
86 inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, Node& current)
90 ASSERT(!is<ShadowRoot>(m_root));
91 ASSERT(!is<ShadowRoot>(m_current));
93 bool mayNeedShadowStack = m_root.shadowRoot() || (m_current != &m_root && current.parentNode() != &m_root);
94 if (mayNeedShadowStack)
95 initializeShadowStack();
98 inline ComposedTreeIterator& ComposedTreeIterator::traverseNext()
100 if (auto* shadowRoot = m_current->shadowRoot()) {
101 m_shadowStack.append(shadowRoot->host());
102 m_current = shadowRoot;
105 if (m_shadowStack.isEmpty())
106 m_current = NodeTraversal::next(*m_current, &m_root);
108 traverseNextInShadowTree();
113 inline ComposedTreeIterator& ComposedTreeIterator::traverseNextSibling()
115 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
116 bool isAssignedToSlot = !m_shadowStack.isEmpty() && m_current->parentNode()->shadowRoot();
117 if (isAssignedToSlot) {
118 traverseNextSiblingSlot();
122 m_current = m_current->nextSibling();
126 inline ComposedTreeIterator& ComposedTreeIterator::traversePreviousSibling()
128 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
129 bool isAssignedToSlot = !m_shadowStack.isEmpty() && m_current->parentNode()->shadowRoot();
130 if (isAssignedToSlot) {
131 traversePreviousSiblingSlot();
135 m_current = m_current->previousSibling();
139 inline ComposedTreeIterator& ComposedTreeIterator::traverseParent()
141 if (m_shadowStack.isEmpty())
142 m_current = m_current->parentNode();
144 traverseParentInShadowTree();
149 class ComposedTreeDescendantAdapter {
151 ComposedTreeDescendantAdapter(ContainerNode& parent)
155 ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent, m_parent).traverseNext(); }
156 ComposedTreeIterator end() { return ComposedTreeIterator(m_parent); }
157 ComposedTreeIterator at(const Node& child) { return ComposedTreeIterator(m_parent, const_cast<Node&>(child)); }
160 ContainerNode& m_parent;
163 class ComposedTreeChildAdapter {
165 class Iterator : public ComposedTreeIterator {
167 Iterator(ContainerNode& root)
168 : ComposedTreeIterator(root)
170 Iterator(ContainerNode& root, Node& current)
171 : ComposedTreeIterator(root, current)
174 Iterator& operator++() { return static_cast<Iterator&>(traverseNextSibling()); }
175 Iterator& operator--() { return static_cast<Iterator&>(traversePreviousSibling()); }
178 ComposedTreeChildAdapter(ContainerNode& parent)
182 Iterator begin() { return static_cast<Iterator&>(Iterator(m_parent, m_parent).traverseNext()); }
183 Iterator end() { return Iterator(m_parent); }
184 Iterator at(const Node& child) { return Iterator(m_parent, const_cast<Node&>(child)); }
187 ContainerNode& m_parent;
190 // FIXME: We should have const versions too.
191 inline ComposedTreeDescendantAdapter composedTreeDescendants(ContainerNode& parent)
193 return ComposedTreeDescendantAdapter(parent);
196 inline ComposedTreeChildAdapter composedTreeChildren(ContainerNode& parent)
198 return ComposedTreeChildAdapter(parent);