• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (C) 2012 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Neither the name of Google Inc. nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 #include "core/dom/shadow/ComposedTreeWalker.h"
30 
31 #include "core/dom/Element.h"
32 #include "core/dom/shadow/ElementShadow.h"
33 #include "core/html/HTMLShadowElement.h"
34 
35 namespace WebCore {
36 
shadowFor(const Node * node)37 static inline ElementShadow* shadowFor(const Node* node)
38 {
39     if (node && node->isElementNode())
40         return toElement(node)->shadow();
41     return 0;
42 }
43 
traverseChild(const Node * node,TraversalDirection direction) const44 Node* ComposedTreeWalker::traverseChild(const Node* node, TraversalDirection direction) const
45 {
46     ASSERT(node);
47     ElementShadow* shadow = shadowFor(node);
48     return shadow ? traverseLightChildren(shadow->youngestShadowRoot(), direction)
49             : traverseLightChildren(node, direction);
50 }
51 
traverseLightChildren(const Node * node,TraversalDirection direction)52 Node* ComposedTreeWalker::traverseLightChildren(const Node* node, TraversalDirection direction)
53 {
54     ASSERT(node);
55     return traverseSiblings(direction == TraversalDirectionForward ? node->firstChild() : node->lastChild(), direction);
56 }
57 
traverseSiblings(const Node * node,TraversalDirection direction)58 Node* ComposedTreeWalker::traverseSiblings(const Node* node, TraversalDirection direction)
59 {
60     for (const Node* sibling = node; sibling; sibling = (direction == TraversalDirectionForward ? sibling->nextSibling() : sibling->previousSibling())) {
61         if (Node* found = traverseNode(sibling, direction))
62             return found;
63     }
64     return 0;
65 }
66 
traverseNode(const Node * node,TraversalDirection direction)67 Node* ComposedTreeWalker::traverseNode(const Node* node, TraversalDirection direction)
68 {
69     ASSERT(node);
70     if (!isActiveInsertionPoint(*node))
71         return const_cast<Node*>(node);
72     const InsertionPoint* insertionPoint = toInsertionPoint(node);
73     if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->first() : insertionPoint->last(), insertionPoint, direction))
74         return found;
75     ASSERT(isHTMLShadowElement(node) || (isHTMLContentElement(node) && !node->hasChildren()));
76     return 0;
77 }
78 
traverseDistributedNodes(const Node * node,const InsertionPoint * insertionPoint,TraversalDirection direction)79 Node* ComposedTreeWalker::traverseDistributedNodes(const Node* node, const InsertionPoint* insertionPoint, TraversalDirection direction)
80 {
81     for (const Node* next = node; next; next = (direction == TraversalDirectionForward ? insertionPoint->nextTo(next) : insertionPoint->previousTo(next))) {
82         if (Node* found = traverseNode(next, direction))
83             return found;
84     }
85     return 0;
86 }
87 
traverseSiblingOrBackToInsertionPoint(const Node * node,TraversalDirection direction)88 Node* ComposedTreeWalker::traverseSiblingOrBackToInsertionPoint(const Node* node, TraversalDirection direction)
89 {
90     ASSERT(node);
91 
92     if (!shadowWhereNodeCanBeDistributed(*node))
93         return traverseSiblingInCurrentTree(node, direction);
94 
95     const InsertionPoint* insertionPoint = resolveReprojection(node);
96     if (!insertionPoint)
97         return traverseSiblingInCurrentTree(node, direction);
98 
99     if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->nextTo(node) : insertionPoint->previousTo(node), insertionPoint, direction))
100         return found;
101     return traverseSiblingOrBackToInsertionPoint(insertionPoint, direction);
102 }
103 
traverseSiblingInCurrentTree(const Node * node,TraversalDirection direction)104 Node* ComposedTreeWalker::traverseSiblingInCurrentTree(const Node* node, TraversalDirection direction)
105 {
106     ASSERT(node);
107     if (Node* found = traverseSiblings(direction == TraversalDirectionForward ? node->nextSibling() : node->previousSibling(), direction))
108         return found;
109     if (Node* next = traverseBackToYoungerShadowRoot(node, direction))
110         return next;
111     return 0;
112 }
113 
traverseBackToYoungerShadowRoot(const Node * node,TraversalDirection direction)114 Node* ComposedTreeWalker::traverseBackToYoungerShadowRoot(const Node* node, TraversalDirection direction)
115 {
116     ASSERT(node);
117     if (node->parentNode() && node->parentNode()->isShadowRoot()) {
118         ShadowRoot* parentShadowRoot = toShadowRoot(node->parentNode());
119         if (!parentShadowRoot->isYoungest()) {
120             HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadowInsertionPointOfYoungerShadowRoot();
121             ASSERT(assignedInsertionPoint);
122             return traverseSiblingInCurrentTree(assignedInsertionPoint, direction);
123         }
124     }
125     return 0;
126 }
127 
128 // FIXME: Use an iterative algorithm so that it can be inlined.
129 // https://bugs.webkit.org/show_bug.cgi?id=90415
traverseParent(const Node * node,ParentTraversalDetails * details) const130 Node* ComposedTreeWalker::traverseParent(const Node* node, ParentTraversalDetails* details) const
131 {
132     if (node->isPseudoElement())
133         return node->parentOrShadowHostNode();
134 
135     if (shadowWhereNodeCanBeDistributed(*node)) {
136         if (const InsertionPoint* insertionPoint = resolveReprojection(node)) {
137             if (details)
138                 details->didTraverseInsertionPoint(insertionPoint);
139             // The node is distributed. But the distribution was stopped at this insertion point.
140             if (shadowWhereNodeCanBeDistributed(*insertionPoint))
141                 return 0;
142             return traverseParentOrHost(insertionPoint);
143         }
144         return 0;
145     }
146     return traverseParentOrHost(node);
147 }
148 
traverseParentOrHost(const Node * node) const149 inline Node* ComposedTreeWalker::traverseParentOrHost(const Node* node) const
150 {
151     Node* parent = node->parentNode();
152     if (!parent)
153         return 0;
154     if (!parent->isShadowRoot())
155         return parent;
156     ShadowRoot* shadowRoot = toShadowRoot(parent);
157     ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot());
158     if (!shadowRoot->isYoungest())
159         return 0;
160     return shadowRoot->host();
161 }
162 
163 } // namespace
164