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 20 matching lines...) Expand all Loading... |
31 #include "core/html/HTMLShadowElement.h" | 31 #include "core/html/HTMLShadowElement.h" |
32 #include "core/html/HTMLSlotElement.h" | 32 #include "core/html/HTMLSlotElement.h" |
33 | 33 |
34 namespace blink { | 34 namespace blink { |
35 | 35 |
36 static inline ElementShadow* shadowFor(const Node& node) | 36 static inline ElementShadow* shadowFor(const Node& node) |
37 { | 37 { |
38 return node.isElementNode() ? toElement(node).shadow() : nullptr; | 38 return node.isElementNode() ? toElement(node).shadow() : nullptr; |
39 } | 39 } |
40 | 40 |
| 41 static inline bool canBeDistributedToInsertionPoint(const Node& node) |
| 42 { |
| 43 return node.isInV0ShadowTree() || node.isChildOfV0ShadowHost(); |
| 44 } |
| 45 |
41 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection
direction) | 46 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection
direction) |
42 { | 47 { |
43 ElementShadow* shadow = shadowFor(node); | 48 ElementShadow* shadow = shadowFor(node); |
44 if (shadow) { | 49 if (shadow) { |
45 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); | 50 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); |
46 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); | 51 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); |
47 } | 52 } |
48 return resolveDistributionStartingAt(direction == TraversalDirectionForward
? node.firstChild() : node.lastChild(), direction); | 53 return resolveDistributionStartingAt(direction == TraversalDirectionForward
? node.firstChild() : node.lastChild(), direction); |
49 } | 54 } |
50 | 55 |
51 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra
versalDirection direction) | 56 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra
versalDirection direction) |
52 { | 57 { |
53 if (!node) | 58 if (!node) |
54 return nullptr; | 59 return nullptr; |
55 if (node->isInShadowTree() && node->containingShadowRoot()->isV1()) | 60 for (const Node* sibling = node; sibling; sibling = (direction == TraversalD
irectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
56 return v1ResolveDistributionStartingAt(*node, direction); | 61 if (isHTMLSlotElement(*sibling)) { |
57 return v0ResolveDistributionStartingAt(*node, direction); | 62 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); |
| 63 if (Node* found = (direction == TraversalDirectionForward ? slot.fir
stDistributedNode() : slot.lastDistributedNode())) |
| 64 return found; |
| 65 continue; |
| 66 } |
| 67 if (node->isInV0ShadowTree()) |
| 68 return v0ResolveDistributionStartingAt(*sibling, direction); |
| 69 return const_cast<Node*>(sibling); |
| 70 } |
| 71 return nullptr; |
58 } | 72 } |
59 | 73 |
60 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T
raversalDirection direction) | 74 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T
raversalDirection direction) |
61 { | 75 { |
| 76 ASSERT(!isHTMLSlotElement(node)); |
62 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | 77 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
63 if (!isActiveInsertionPoint(*sibling)) | 78 if (!isActiveInsertionPoint(*sibling)) |
64 return const_cast<Node*>(sibling); | 79 return const_cast<Node*>(sibling); |
65 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); | 80 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); |
66 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi
nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) | 81 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi
nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) |
67 return found; | 82 return found; |
68 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse
rtionPoint) && !insertionPoint.hasChildren())); | 83 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse
rtionPoint) && !insertionPoint.hasChildren())); |
69 } | 84 } |
70 return nullptr; | 85 return nullptr; |
71 } | 86 } |
72 | 87 |
73 Node* ComposedTreeTraversal::v1ResolveDistributionStartingAt(const Node& node, T
raversalDirection direction) | |
74 { | |
75 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | |
76 if (!isHTMLSlotElement(*sibling)) | |
77 return const_cast<Node*>(sibling); | |
78 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); | |
79 if (Node* found = (direction == TraversalDirectionForward ? slot.firstDi
stributedNode() : slot.lastDistributedNode())) | |
80 return found; | |
81 } | |
82 return nullptr; | |
83 } | |
84 | |
85 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) | 88 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) |
86 { | 89 { |
87 HTMLSlotElement* slot = node.assignedSlot(); | 90 HTMLSlotElement* slot = node.assignedSlot(); |
88 if (!slot) | 91 if (!slot) |
89 return nullptr; | 92 return nullptr; |
90 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign
edSlot()) { | 93 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign
edSlot()) { |
91 slot = next; | 94 slot = next; |
92 } | 95 } |
93 return slot; | 96 return slot; |
94 } | 97 } |
95 | 98 |
96 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti
on direction) | |
97 { | |
98 Node* parent = node.parentNode(); | |
99 if (!parent) | |
100 return nullptr; | |
101 if (parent->isElementNode()) { | |
102 if (ElementShadow* shadow = toElement(parent)->shadow()) { | |
103 if (shadow->isV1()) { | |
104 return v1TraverseSiblings(node, direction); | |
105 } | |
106 } | |
107 } | |
108 return v0TraverseSiblings(node, direction); | |
109 } | |
110 | |
111 // TODO(hayato): This may return a wrong result for a node which is not in a | 99 // TODO(hayato): This may return a wrong result for a node which is not in a |
112 // document composed tree. See ComposedTreeTraversalTest's redistribution test
for details. | 100 // document composed tree. See ComposedTreeTraversalTest's redistribution test
for details. |
113 Node* ComposedTreeTraversal::v0TraverseSiblings(const Node& node, TraversalDirec
tion direction) | 101 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti
on direction) |
114 { | 102 { |
115 if (!shadowWhereNodeCanBeDistributed(node)) | 103 if (node.isChildOfV1ShadowHost()) |
116 return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); | 104 return traverseSiblingsForV1HostChild(node, direction); |
117 | 105 |
| 106 if (shadowWhereNodeCanBeDistributed(node)) |
| 107 return traverseSiblingsForV0Distribution(node, direction); |
| 108 |
| 109 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect
ionForward ? node.nextSibling() : node.previousSibling(), direction)) |
| 110 return found; |
| 111 |
| 112 if (!node.isInV0ShadowTree()) |
| 113 return nullptr; |
| 114 |
| 115 // For v0 older shadow tree |
| 116 if (node.parentNode() && node.parentNode()->isShadowRoot()) { |
| 117 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); |
| 118 if (!parentShadowRoot->isYoungest()) { |
| 119 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow
InsertionPointOfYoungerShadowRoot(); |
| 120 ASSERT(assignedInsertionPoint); |
| 121 return traverseSiblings(*assignedInsertionPoint, direction); |
| 122 } |
| 123 } |
| 124 return nullptr; |
| 125 } |
| 126 |
| 127 Node* ComposedTreeTraversal::traverseSiblingsForV1HostChild(const Node& node, Tr
aversalDirection direction) |
| 128 { |
| 129 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
| 130 if (!slot) |
| 131 return nullptr; |
| 132 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar
d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) |
| 133 return siblingInDistributedNodes; |
| 134 return traverseSiblings(*slot, direction); |
| 135 } |
| 136 |
| 137 Node* ComposedTreeTraversal::traverseSiblingsForV0Distribution(const Node& node,
TraversalDirection direction) |
| 138 { |
118 const InsertionPoint* finalDestination = resolveReprojection(&node); | 139 const InsertionPoint* finalDestination = resolveReprojection(&node); |
119 if (!finalDestination) | 140 if (!finalDestination) |
120 return nullptr; | 141 return nullptr; |
121 if (Node* found = (direction == TraversalDirectionForward ? finalDestination
->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no
de))) | 142 if (Node* found = (direction == TraversalDirectionForward ? finalDestination
->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no
de))) |
122 return found; | 143 return found; |
123 return traverseSiblings(*finalDestination, direction); | 144 return traverseSiblings(*finalDestination, direction); |
124 } | |
125 | 145 |
126 Node* ComposedTreeTraversal::v1TraverseSiblings(const Node& node, TraversalDirec
tion direction) | |
127 { | |
128 HTMLSlotElement* slot = finalDestinationSlotFor(node); | |
129 if (!slot) | |
130 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? node.nextSibling() : node.previousSibling(), direction); | |
131 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar
d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) | |
132 return siblingInDistributedNodes; | |
133 return v1TraverseSiblings(*slot, direction); | |
134 } | |
135 | |
136 Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(cons
t Node& node, TraversalDirection direction) | |
137 { | |
138 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect
ionForward ? node.nextSibling() : node.previousSibling(), direction)) | |
139 return found; | |
140 | |
141 if (node.parentNode() && node.parentNode()->isShadowRoot()) { | |
142 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); | |
143 if (!parentShadowRoot->isYoungest()) { | |
144 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow
InsertionPointOfYoungerShadowRoot(); | |
145 ASSERT(assignedInsertionPoint); | |
146 return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInser
tionPoint, direction); | |
147 } | |
148 } | |
149 return nullptr; | |
150 } | |
151 | |
152 static ElementShadow* parentElementShadow(const Node& node) | |
153 { | |
154 Node* parent = node.parentNode(); | |
155 if (!parent) | |
156 return nullptr; | |
157 if (parent->isElementNode()) | |
158 return toElement(parent)->shadow(); | |
159 return nullptr; | |
160 } | 146 } |
161 | 147 |
162 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra
versalDetails* details) | 148 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra
versalDetails* details) |
163 { | 149 { |
164 // 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. | 150 // 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. |
165 if (node.isPseudoElement()) | 151 if (node.isPseudoElement()) |
166 return node.parentOrShadowHostNode(); | 152 return node.parentOrShadowHostNode(); |
167 | 153 |
168 ElementShadow* shadow = parentElementShadow(node); | 154 if (node.isChildOfV1ShadowHost()) { |
169 if (shadow && shadow->isV1()) | 155 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
170 return v1TraverseParent(node); | 156 if (!slot) |
171 if (shadowWhereNodeCanBeDistributed(node)) | 157 return nullptr; |
172 return v0TraverseParent(node, details); | 158 return traverseParent(*slot); |
| 159 } |
| 160 |
| 161 Element* parent = node.parentElement(); |
| 162 if (parent && isHTMLSlotElement(parent)) { |
| 163 HTMLSlotElement& slot = toHTMLSlotElement(*parent); |
| 164 if (!slot.getAssignedNodes().isEmpty()) |
| 165 return nullptr; |
| 166 return traverseParent(slot, details); |
| 167 } |
| 168 |
| 169 if (canBeDistributedToInsertionPoint(node)) |
| 170 return traverseParentForV0(node, details); |
| 171 |
| 172 ASSERT(!shadowWhereNodeCanBeDistributed(node)); |
173 return traverseParentOrHost(node); | 173 return traverseParentOrHost(node); |
174 } | 174 } |
175 | 175 |
176 ContainerNode* ComposedTreeTraversal::v1TraverseParent(const Node& node) | 176 ContainerNode* ComposedTreeTraversal::traverseParentForV0(const Node& node, Pare
ntTraversalDetails* details) |
177 { | 177 { |
178 HTMLSlotElement* slot = finalDestinationSlotFor(node); | 178 if (shadowWhereNodeCanBeDistributed(node)) { |
179 if (!slot) | 179 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { |
180 return nullptr; | 180 if (details) |
181 if (parentElementShadow(*slot)) { | 181 details->didTraverseInsertionPoint(insertionPoint); |
182 // The node is distributed to the |slot|, however, |slot|, which is a | 182 // The node is distributed. But the distribution was stopped at this
insertion point. |
183 // child of a shadow host, is not assigned to any slots. | 183 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) |
| 184 return nullptr; |
| 185 return traverseParent(*insertionPoint); |
| 186 } |
184 return nullptr; | 187 return nullptr; |
185 } | 188 } |
186 return traverseParentOrHost(*slot); | 189 ContainerNode* parent = traverseParentOrHost(node); |
| 190 if (isActiveInsertionPoint(*parent)) |
| 191 return nullptr; |
| 192 return parent; |
187 } | 193 } |
188 | 194 |
189 ContainerNode* ComposedTreeTraversal::v0TraverseParent(const Node& node, ParentT
raversalDetails* details) | 195 ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& node) |
190 { | 196 { |
191 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { | |
192 if (details) | |
193 details->didTraverseInsertionPoint(insertionPoint); | |
194 // The node is distributed. But the distribution was stopped at this ins
ertion point. | |
195 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) | |
196 return nullptr; | |
197 return traverseParentOrHost(*insertionPoint); | |
198 } | |
199 return nullptr; | |
200 } | |
201 | |
202 inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& no
de) | |
203 { | |
204 // TODO(hayato): Support fallback contents of slots. The parent can be a slo
t. | |
205 ContainerNode* parent = node.parentNode(); | 197 ContainerNode* parent = node.parentNode(); |
206 if (!parent) | 198 if (!parent) |
207 return nullptr; | 199 return nullptr; |
208 if (!parent->isShadowRoot()) | 200 if (!parent->isShadowRoot()) |
209 return parent; | 201 return parent; |
210 ShadowRoot* shadowRoot = toShadowRoot(parent); | 202 ShadowRoot* shadowRoot = toShadowRoot(parent); |
211 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); | 203 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); |
212 if (!shadowRoot->isYoungest()) | 204 if (!shadowRoot->isYoungest()) |
213 return nullptr; | 205 return nullptr; |
214 Element* host = shadowRoot->host(); | 206 return shadowRoot->host(); |
215 if (isActiveInsertionPoint(*host)) | |
216 return nullptr; | |
217 return host; | |
218 } | 207 } |
219 | 208 |
220 Node* ComposedTreeTraversal::childAt(const Node& node, unsigned index) | 209 Node* ComposedTreeTraversal::childAt(const Node& node, unsigned index) |
221 { | 210 { |
222 assertPrecondition(node); | 211 assertPrecondition(node); |
223 Node* child = traverseFirstChild(node); | 212 Node* child = traverseFirstChild(node); |
224 while (child && index--) | 213 while (child && index--) |
225 child = nextSibling(*child); | 214 child = nextSibling(*child); |
226 assertPostcondition(child); | 215 assertPostcondition(child); |
227 return child; | 216 return child; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) | 352 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) |
364 { | 353 { |
365 assertPrecondition(node); | 354 assertPrecondition(node); |
366 Node* lastDescendant = lastWithin(node); | 355 Node* lastDescendant = lastWithin(node); |
367 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); | 356 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); |
368 assertPostcondition(&result); | 357 assertPostcondition(&result); |
369 return result; | 358 return result; |
370 } | 359 } |
371 | 360 |
372 } // namespace | 361 } // namespace |
OLD | NEW |