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