1/*
2 * Copyright (C) 2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#pragma once
27
28#include "HTMLSlotElement.h"
29#include "PseudoElement.h"
30#include "ShadowRoot.h"
31
32namespace WebCore {
33
34class HTMLSlotElement;
35
36class ComposedTreeAncestorIterator {
37public:
38 ComposedTreeAncestorIterator();
39 ComposedTreeAncestorIterator(Node& current);
40
41 Element& operator*() { return get(); }
42 Element* operator->() { return &get(); }
43
44 bool operator==(const ComposedTreeAncestorIterator& other) const { return m_current == other.m_current; }
45 bool operator!=(const ComposedTreeAncestorIterator& other) const { return m_current != other.m_current; }
46
47 ComposedTreeAncestorIterator& operator++() { return traverseParent(); }
48
49 Element& get() { return downcast<Element>(*m_current); }
50 ComposedTreeAncestorIterator& traverseParent();
51
52private:
53 void traverseParentInShadowTree();
54
55 Node* m_current { 0 };
56};
57
58inline ComposedTreeAncestorIterator::ComposedTreeAncestorIterator()
59{
60}
61
62inline ComposedTreeAncestorIterator::ComposedTreeAncestorIterator(Node& current)
63 : m_current(&current)
64{
65 ASSERT(!is<ShadowRoot>(m_current));
66}
67
68inline ComposedTreeAncestorIterator& ComposedTreeAncestorIterator::traverseParent()
69{
70 auto* parent = m_current->parentNode();
71 if (!parent) {
72 m_current = nullptr;
73 return *this;
74 }
75 if (is<ShadowRoot>(*parent)) {
76 m_current = downcast<ShadowRoot>(*parent).host();
77 return *this;
78 }
79 if (!is<Element>(*parent)) {
80 m_current = nullptr;
81 return *this;
82 };
83
84 if (auto* shadowRoot = parent->shadowRoot()) {
85 m_current = shadowRoot->findAssignedSlot(*m_current);
86 return *this;
87 }
88
89 m_current = parent;
90 return *this;
91}
92
93class ComposedTreeAncestorAdapter {
94public:
95 using iterator = ComposedTreeAncestorIterator;
96
97 ComposedTreeAncestorAdapter(Node& node)
98 : m_node(node)
99 { }
100
101 iterator begin()
102 {
103 if (is<ShadowRoot>(m_node))
104 return iterator(*downcast<ShadowRoot>(m_node).host());
105 if (is<PseudoElement>(m_node))
106 return iterator(*downcast<PseudoElement>(m_node).hostElement());
107 return iterator(m_node).traverseParent();
108 }
109 iterator end()
110 {
111 return iterator();
112 }
113 Element* first()
114 {
115 auto it = begin();
116 if (it == end())
117 return nullptr;
118 return &it.get();
119 }
120
121private:
122 Node& m_node;
123};
124
125// FIXME: We should have const versions too.
126inline ComposedTreeAncestorAdapter composedTreeAncestors(Node& node)
127{
128 return ComposedTreeAncestorAdapter(node);
129}
130
131} // namespace WebCore
132