OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Neither the name of Google Inc. nor the names of its | 10 * * Neither the name of Google Inc. nor the names of its |
(...skipping 12 matching lines...) Expand all Loading... | |
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 */ | 25 */ |
26 | 26 |
27 #include "config.h" | 27 #include "config.h" |
28 #include "core/dom/shadow/ComposedTreeTraversal.h" | 28 #include "core/dom/shadow/ComposedTreeTraversal.h" |
29 | 29 |
30 #include "core/dom/Element.h" | 30 #include "core/dom/Element.h" |
31 #include "core/dom/shadow/ElementShadow.h" | 31 #include "core/dom/shadow/ElementShadow.h" |
32 #include "core/html/HTMLShadowElement.h" | 32 #include "core/html/HTMLShadowElement.h" |
33 #include "core/html/HTMLSlotElement.h" | |
33 | 34 |
34 namespace blink { | 35 namespace blink { |
35 | 36 |
36 static inline ElementShadow* shadowFor(const Node& node) | 37 static inline ElementShadow* shadowFor(const Node& node) |
37 { | 38 { |
38 return node.isElementNode() ? toElement(node).shadow() : nullptr; | 39 return node.isElementNode() ? toElement(node).shadow() : nullptr; |
39 } | 40 } |
40 | 41 |
41 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection direction) | 42 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection direction) |
42 { | 43 { |
43 ElementShadow* shadow = shadowFor(node); | 44 ElementShadow* shadow = shadowFor(node); |
44 if (shadow) { | 45 if (shadow) { |
45 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); | 46 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); |
46 return resolveDistributionStartingAt(direction == TraversalDirectionForw ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); | 47 return resolveDistributionStartingAt(direction == TraversalDirectionForw ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); |
47 } | 48 } |
48 return resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.firstChild() : node.lastChild(), direction); | 49 return resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.firstChild() : node.lastChild(), direction); |
49 } | 50 } |
50 | 51 |
51 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra versalDirection direction) | 52 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra versalDirection direction) |
52 { | 53 { |
53 for (const Node* sibling = node; sibling; sibling = (direction == TraversalD irectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | 54 if (!node) |
55 return nullptr; | |
56 if (node->isInShadowTree() && node->containingShadowRoot()->isV1()) | |
57 return v1ResolveDistributionStartingAt(*node, direction); | |
58 return v0ResolveDistributionStartingAt(*node, direction); | |
59 } | |
60 | |
61 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T raversalDirection direction) | |
62 { | |
63 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | |
54 if (!isActiveInsertionPoint(*sibling)) | 64 if (!isActiveInsertionPoint(*sibling)) |
55 return const_cast<Node*>(sibling); | 65 return const_cast<Node*>(sibling); |
56 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); | 66 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); |
57 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) | 67 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) |
58 return found; | 68 return found; |
59 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse rtionPoint) && !insertionPoint.hasChildren())); | 69 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse rtionPoint) && !insertionPoint.hasChildren())); |
60 } | 70 } |
61 return nullptr; | 71 return nullptr; |
62 } | 72 } |
63 | 73 |
74 Node* ComposedTreeTraversal::v1ResolveDistributionStartingAt(const Node& node, T raversalDirection direction) | |
75 { | |
76 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | |
77 if (!isHTMLSlotElement(*sibling)) | |
78 return const_cast<Node*>(sibling); | |
79 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); | |
80 if (Node* found = (direction == TraversalDirectionForward ? slot.firstDi stributedNode() : slot.lastDistributedNode())) | |
81 return found; | |
82 } | |
83 return nullptr; | |
84 } | |
85 | |
86 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) | |
87 { | |
88 HTMLSlotElement* slot = node.assignedSlot(); | |
89 if (!slot) | |
90 return nullptr; | |
91 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign edSlot()) { | |
92 slot = next; | |
93 } | |
94 return slot; | |
95 } | |
96 | |
97 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti on direction) | |
98 { | |
99 Node* parent = node.parentNode(); | |
100 if (!parent) | |
101 return nullptr; | |
102 if (parent->isElementNode()) { | |
103 if (ElementShadow* shadow = toElement(parent)->shadow()) { | |
104 if (shadow->isV1()) { | |
105 return v1TraverseSiblings(node, direction); | |
106 } | |
107 } | |
108 } | |
109 return v0TraverseSiblings(node, direction); | |
110 } | |
111 | |
64 // TODO(hayato): This may return a wrong result for a node which is not in a | 112 // TODO(hayato): This may return a wrong result for a node which is not in a |
65 // document composed tree. See ComposedTreeTraversalTest's redistribution test for details. | 113 // document composed tree. See ComposedTreeTraversalTest's redistribution test for details. |
66 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti on direction) | 114 // TODO(hayato): Fix for v1 |
kochi
2015/12/09 12:02:27
Could you be more specific about what to be fixed?
hayato
2015/12/10 02:17:31
Done. I've removed this.
| |
115 Node* ComposedTreeTraversal::v0TraverseSiblings(const Node& node, TraversalDirec tion direction) | |
67 { | 116 { |
68 if (!shadowWhereNodeCanBeDistributed(node)) | 117 if (!shadowWhereNodeCanBeDistributed(node)) |
69 return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); | 118 return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); |
70 | 119 |
71 const InsertionPoint* finalDestination = resolveReprojection(&node); | 120 const InsertionPoint* finalDestination = resolveReprojection(&node); |
72 if (!finalDestination) | 121 if (!finalDestination) |
73 return nullptr; | 122 return nullptr; |
74 if (Node* found = (direction == TraversalDirectionForward ? finalDestination ->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no de))) | 123 if (Node* found = (direction == TraversalDirectionForward ? finalDestination ->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no de))) |
75 return found; | 124 return found; |
76 return traverseSiblings(*finalDestination, direction); | 125 return traverseSiblings(*finalDestination, direction); |
77 } | 126 } |
78 | 127 |
128 Node* ComposedTreeTraversal::v1TraverseSiblings(const Node& node, TraversalDirec tion direction) | |
129 { | |
130 HTMLSlotElement* slot = finalDestinationSlotFor(node); | |
131 if (!slot) | |
132 return resolveDistributionStartingAt(direction == TraversalDirectionForw ard ? node.nextSibling() : node.previousSibling(), direction); | |
133 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) | |
134 return siblingInDistributedNodes; | |
135 return v1TraverseSiblings(*slot, direction); | |
136 } | |
137 | |
79 Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(cons t Node& node, TraversalDirection direction) | 138 Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(cons t Node& node, TraversalDirection direction) |
80 { | 139 { |
81 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect ionForward ? node.nextSibling() : node.previousSibling(), direction)) | 140 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect ionForward ? node.nextSibling() : node.previousSibling(), direction)) |
82 return found; | 141 return found; |
83 | 142 |
84 if (node.parentNode() && node.parentNode()->isShadowRoot()) { | 143 if (node.parentNode() && node.parentNode()->isShadowRoot()) { |
85 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); | 144 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); |
86 if (!parentShadowRoot->isYoungest()) { | 145 if (!parentShadowRoot->isYoungest()) { |
87 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow InsertionPointOfYoungerShadowRoot(); | 146 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow InsertionPointOfYoungerShadowRoot(); |
88 ASSERT(assignedInsertionPoint); | 147 ASSERT(assignedInsertionPoint); |
89 return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInser tionPoint, direction); | 148 return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInser tionPoint, direction); |
90 } | 149 } |
91 } | 150 } |
92 return nullptr; | 151 return nullptr; |
93 } | 152 } |
94 | 153 |
95 // FIXME: Use an iterative algorithm so that it can be inlined. | 154 static ElementShadow* parentElementShadow(const Node& node) |
kochi
2015/12/09 12:02:27
nit: this function looks a part of Node::assignedS
hayato
2015/12/10 02:17:31
This function is too specific to the file. Let me
| |
96 // https://bugs.webkit.org/show_bug.cgi?id=90415 | 155 { |
156 Node* parent = node.parentNode(); | |
157 if (!parent) | |
158 return nullptr; | |
159 if (parent->isElementNode()) | |
160 return toElement(parent)->shadow(); | |
161 return nullptr; | |
162 } | |
163 | |
97 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra versalDetails* details) | 164 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra versalDetails* details) |
98 { | 165 { |
99 // TODO(hayato): Stop this hack for a pseudo element because a pseudo elemen t is not a child of its parentOrShadowHostNode() in a composed tree. | 166 // TODO(hayato): Stop this hack for a pseudo element because a pseudo elemen t is not a child of its parentOrShadowHostNode() in a composed tree. |
100 if (node.isPseudoElement()) | 167 if (node.isPseudoElement()) |
101 return node.parentOrShadowHostNode(); | 168 return node.parentOrShadowHostNode(); |
102 | 169 |
103 if (shadowWhereNodeCanBeDistributed(node)) { | 170 ElementShadow* shadow = parentElementShadow(node); |
104 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { | 171 if (shadow && shadow->isV1()) |
105 if (details) | 172 return v1TraverseParent(node); |
106 details->didTraverseInsertionPoint(insertionPoint); | 173 if (shadowWhereNodeCanBeDistributed(node)) |
107 // The node is distributed. But the distribution was stopped at this insertion point. | 174 return v0TraverseParent(node, details); |
108 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) | 175 return traverseParentOrHost(node); |
109 return nullptr; | 176 } |
110 return traverseParentOrHost(*insertionPoint); | 177 |
111 } | 178 ContainerNode* ComposedTreeTraversal::v1TraverseParent(const Node& node) |
179 { | |
180 HTMLSlotElement* slot = finalDestinationSlotFor(node); | |
181 if (!slot) | |
182 return nullptr; | |
183 if (parentElementShadow(*slot)) { | |
184 // The node is distributed to the |slot|, however, |slot|, which is a | |
185 // child of a shadow host, is not assigned to any slots. | |
112 return nullptr; | 186 return nullptr; |
113 } | 187 } |
114 return traverseParentOrHost(node); | 188 return traverseParentOrHost(*slot); |
189 } | |
190 | |
191 ContainerNode* ComposedTreeTraversal::v0TraverseParent(const Node& node, ParentT raversalDetails* details) | |
192 { | |
193 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { | |
194 if (details) | |
195 details->didTraverseInsertionPoint(insertionPoint); | |
196 // The node is distributed. But the distribution was stopped at this ins ertion point. | |
197 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) | |
198 return nullptr; | |
199 return traverseParentOrHost(*insertionPoint); | |
200 } | |
201 return nullptr; | |
115 } | 202 } |
116 | 203 |
117 inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& no de) | 204 inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& no de) |
118 { | 205 { |
206 // TODO(hayato): Support fallback contents of slots. The parent can be a slo t. | |
119 ContainerNode* parent = node.parentNode(); | 207 ContainerNode* parent = node.parentNode(); |
120 if (!parent) | 208 if (!parent) |
121 return nullptr; | 209 return nullptr; |
122 if (!parent->isShadowRoot()) | 210 if (!parent->isShadowRoot()) |
123 return parent; | 211 return parent; |
124 ShadowRoot* shadowRoot = toShadowRoot(parent); | 212 ShadowRoot* shadowRoot = toShadowRoot(parent); |
125 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); | 213 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); |
126 if (!shadowRoot->isYoungest()) | 214 if (!shadowRoot->isYoungest()) |
127 return nullptr; | 215 return nullptr; |
128 Element* host = shadowRoot->host(); | 216 Element* host = shadowRoot->host(); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) | 365 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) |
278 { | 366 { |
279 assertPrecondition(node); | 367 assertPrecondition(node); |
280 Node* lastDescendant = lastWithin(node); | 368 Node* lastDescendant = lastWithin(node); |
281 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); | 369 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); |
282 assertPostcondition(&result); | 370 assertPostcondition(&result); |
283 return result; | 371 return result; |
284 } | 372 } |
285 | 373 |
286 } // namespace | 374 } // namespace |
OLD | NEW |