OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2015 Google Inc. All rights reserved. | 2 * Copyright (C) 2015 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 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 14 matching lines...) Expand all Loading... |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "core/html/HTMLSlotElement.h" | 31 #include "core/html/HTMLSlotElement.h" |
32 | 32 |
33 #include "bindings/core/v8/Microtask.h" | 33 #include "bindings/core/v8/Microtask.h" |
34 #include "core/HTMLNames.h" | 34 #include "core/HTMLNames.h" |
35 #include "core/dom/ElementTraversal.h" | |
36 #include "core/dom/NodeTraversal.h" | 35 #include "core/dom/NodeTraversal.h" |
37 #include "core/dom/StyleChangeReason.h" | 36 #include "core/dom/StyleChangeReason.h" |
38 #include "core/dom/StyleEngine.h" | 37 #include "core/dom/StyleEngine.h" |
39 #include "core/dom/shadow/ElementShadow.h" | 38 #include "core/dom/shadow/ElementShadow.h" |
40 #include "core/dom/shadow/InsertionPoint.h" | 39 #include "core/dom/shadow/InsertionPoint.h" |
| 40 #include "core/dom/shadow/SlotAssignment.h" |
41 #include "core/events/Event.h" | 41 #include "core/events/Event.h" |
42 #include "core/html/AssignedNodesOptions.h" | 42 #include "core/html/AssignedNodesOptions.h" |
43 | 43 |
44 namespace blink { | 44 namespace blink { |
45 | 45 |
46 using namespace HTMLNames; | 46 using namespace HTMLNames; |
47 | 47 |
48 inline HTMLSlotElement::HTMLSlotElement(Document& document) | 48 inline HTMLSlotElement::HTMLSlotElement(Document& document) |
49 : HTMLElement(slotTag, document) | 49 : HTMLElement(slotTag, document) |
50 , m_distributionState(DistributionDone) | |
51 , m_assignmentState(AssignmentDone) | |
52 , m_slotchangeEventAdded(false) | |
53 { | 50 { |
54 setHasCustomStyleCallbacks(); | 51 setHasCustomStyleCallbacks(); |
55 } | 52 } |
56 | 53 |
57 DEFINE_NODE_FACTORY(HTMLSlotElement); | 54 DEFINE_NODE_FACTORY(HTMLSlotElement); |
58 | 55 |
| 56 // static |
| 57 AtomicString HTMLSlotElement::normalizeSlotName(const AtomicString& name) |
| 58 { |
| 59 return (name.isNull() || name.isEmpty()) ? emptyAtom : name; |
| 60 } |
| 61 |
| 62 const HeapVector<Member<Node>>& HTMLSlotElement::assignedNodes() |
| 63 { |
| 64 DCHECK(!needsDistributionRecalc()); |
| 65 DCHECK(isInShadowTree() || m_assignedNodes.isEmpty()); |
| 66 return m_assignedNodes; |
| 67 } |
| 68 |
59 const HeapVector<Member<Node>> HTMLSlotElement::assignedNodesForBinding(const As
signedNodesOptions& options) | 69 const HeapVector<Member<Node>> HTMLSlotElement::assignedNodesForBinding(const As
signedNodesOptions& options) |
60 { | 70 { |
61 updateDistribution(); | 71 updateDistribution(); |
62 if (options.hasFlatten() && options.flatten()) | 72 if (options.hasFlatten() && options.flatten()) |
63 return getDistributedNodes(); | 73 return getDistributedNodes(); |
64 return m_assignedNodes; | 74 return m_assignedNodes; |
65 } | 75 } |
66 | 76 |
67 const HeapVector<Member<Node>>& HTMLSlotElement::getDistributedNodes() | 77 const HeapVector<Member<Node>>& HTMLSlotElement::getDistributedNodes() |
68 { | 78 { |
69 ASSERT(!needsDistributionRecalc()); | 79 DCHECK(!needsDistributionRecalc()); |
70 if (isInShadowTree()) | 80 if (isInShadowTree()) |
71 return m_distributedNodes; | 81 return m_distributedNodes; |
72 | 82 |
73 // A slot is unlikely to be used outside of a shadow tree. | 83 // A slot is unlikely to be used outside of a shadow tree. |
74 // We do not need to optimize this case in most cases. | 84 // We do not need to optimize this case in most cases. |
75 // TODO(hayato): If this path causes a performance issue, we should move | 85 // TODO(hayato): If this path causes a performance issue, we should move |
76 // ShadowRootRaraDate::m_descendantSlots into TreeScopreRareData-ish and | 86 // ShadowRoot::m_slotAssignment into TreeScopreRareData-ish and |
77 // update the distribution code so it considers a document tree too. | 87 // update the distribution code so it considers a document tree too. |
78 willUpdateDistribution(); | 88 clearDistribution(); |
79 for (Node& child : NodeTraversal::childrenOf(*this)) { | 89 Node* child = NodeTraversal::firstChild(*this); |
80 if (!child.isSlotAssignable()) | 90 while (child) { |
| 91 if (!child->isSlotable()) { |
| 92 child = NodeTraversal::nextSkippingChildren(*child, this); |
81 continue; | 93 continue; |
82 if (isHTMLSlotElement(child)) | 94 } |
83 m_distributedNodes.appendVector(toHTMLSlotElement(child).getDistribu
tedNodes()); | 95 if (isHTMLSlotElement(child)) { |
84 else | 96 child = NodeTraversal::next(*child, this); |
85 m_distributedNodes.append(&child); | 97 } else { |
| 98 m_distributedNodes.append(child); |
| 99 child = NodeTraversal::nextSkippingChildren(*child, this); |
| 100 } |
86 } | 101 } |
87 didUpdateDistribution(); | |
88 return m_distributedNodes; | 102 return m_distributedNodes; |
89 } | 103 } |
90 | 104 |
91 void HTMLSlotElement::appendAssignedNode(Node& node) | 105 void HTMLSlotElement::appendAssignedNode(Node& hostChild) |
92 { | 106 { |
93 ASSERT(m_assignmentState == AssignmentOnGoing); | 107 DCHECK(hostChild.isSlotable()); |
94 m_assignedNodes.append(&node); | 108 m_assignedNodes.append(&hostChild); |
| 109 } |
| 110 |
| 111 void HTMLSlotElement::resolveDistributedNodes() |
| 112 { |
| 113 for (auto& node : m_assignedNodes) { |
| 114 DCHECK(node->isSlotable()); |
| 115 if (isHTMLSlotElement(*node)) |
| 116 appendDistributedNodesFrom(toHTMLSlotElement(*node)); |
| 117 else |
| 118 appendDistributedNode(*node); |
| 119 |
| 120 if (isChildOfV1ShadowHost()) |
| 121 parentElementShadow()->setNeedsDistributionRecalc(); |
| 122 } |
95 } | 123 } |
96 | 124 |
97 void HTMLSlotElement::appendDistributedNode(Node& node) | 125 void HTMLSlotElement::appendDistributedNode(Node& node) |
98 { | 126 { |
99 ASSERT(m_distributionState == DistributionOnGoing); | |
100 size_t size = m_distributedNodes.size(); | 127 size_t size = m_distributedNodes.size(); |
101 m_distributedNodes.append(&node); | 128 m_distributedNodes.append(&node); |
102 m_distributedIndices.set(&node, size); | 129 m_distributedIndices.set(&node, size); |
103 } | 130 } |
104 | 131 |
105 void HTMLSlotElement::appendFallbackNode(Node& node) | |
106 { | |
107 ASSERT(m_assignmentState == AssignmentOnGoing); | |
108 m_fallbackNodes.append(&node); | |
109 } | |
110 | |
111 void HTMLSlotElement::appendDistributedNodesFrom(const HTMLSlotElement& other) | 132 void HTMLSlotElement::appendDistributedNodesFrom(const HTMLSlotElement& other) |
112 { | 133 { |
113 ASSERT(m_distributionState == DistributionOnGoing); | |
114 size_t index = m_distributedNodes.size(); | 134 size_t index = m_distributedNodes.size(); |
115 m_distributedNodes.appendVector(other.m_distributedNodes); | 135 m_distributedNodes.appendVector(other.m_distributedNodes); |
116 for (const auto& node : other.m_distributedNodes) | 136 for (const auto& node : other.m_distributedNodes) |
117 m_distributedIndices.set(node.get(), index++); | 137 m_distributedIndices.set(node.get(), index++); |
118 } | 138 } |
119 | 139 |
120 void HTMLSlotElement::willUpdateAssignment() | 140 void HTMLSlotElement::clearDistribution() |
121 { | 141 { |
122 ASSERT(m_assignmentState != AssignmentOnGoing); | |
123 m_assignmentState = AssignmentOnGoing; | |
124 m_oldAssignedNodes.swap(m_assignedNodes); | |
125 m_assignedNodes.clear(); | 142 m_assignedNodes.clear(); |
126 } | |
127 | |
128 void HTMLSlotElement::willUpdateDistribution() | |
129 { | |
130 ASSERT(m_distributionState != DistributionOnGoing); | |
131 m_distributionState = DistributionOnGoing; | |
132 m_oldDistributedNodes.swap(m_distributedNodes); | |
133 m_distributedNodes.clear(); | 143 m_distributedNodes.clear(); |
134 m_distributedIndices.clear(); | 144 m_distributedIndices.clear(); |
135 } | 145 } |
136 | 146 |
137 void HTMLSlotElement::willUpdateFallback() | |
138 { | |
139 m_oldFallbackNodes.swap(m_fallbackNodes); | |
140 m_fallbackNodes.clear(); | |
141 } | |
142 | |
143 void HTMLSlotElement::dispatchSlotChangeEvent() | 147 void HTMLSlotElement::dispatchSlotChangeEvent() |
144 { | 148 { |
| 149 m_slotchangeEventEnqueued = false; |
145 Event* event = Event::create(EventTypeNames::slotchange); | 150 Event* event = Event::create(EventTypeNames::slotchange); |
146 event->setTarget(this); | 151 event->setTarget(this); |
147 dispatchScopedEvent(event); | 152 dispatchScopedEvent(event); |
148 m_slotchangeEventAdded = false; | |
149 } | 153 } |
150 | 154 |
151 Node* HTMLSlotElement::distributedNodeNextTo(const Node& node) const | 155 Node* HTMLSlotElement::distributedNodeNextTo(const Node& node) const |
152 { | 156 { |
153 const auto& it = m_distributedIndices.find(&node); | 157 const auto& it = m_distributedIndices.find(&node); |
154 if (it == m_distributedIndices.end()) | 158 if (it == m_distributedIndices.end()) |
155 return nullptr; | 159 return nullptr; |
156 size_t index = it->value; | 160 size_t index = it->value; |
157 if (index + 1 == m_distributedNodes.size()) | 161 if (index + 1 == m_distributedNodes.size()) |
158 return nullptr; | 162 return nullptr; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 for (auto& node : m_distributedNodes) | 194 for (auto& node : m_distributedNodes) |
191 node->lazyReattachIfAttached(); | 195 node->lazyReattachIfAttached(); |
192 | 196 |
193 HTMLElement::detach(context); | 197 HTMLElement::detach(context); |
194 } | 198 } |
195 | 199 |
196 void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicSt
ring& oldValue, const AtomicString& newValue, AttributeModificationReason reason
) | 200 void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicSt
ring& oldValue, const AtomicString& newValue, AttributeModificationReason reason
) |
197 { | 201 { |
198 if (name == nameAttr) { | 202 if (name == nameAttr) { |
199 if (ShadowRoot* root = containingShadowRoot()) { | 203 if (ShadowRoot* root = containingShadowRoot()) { |
200 root->owner()->willAffectSelector(); | |
201 if (root->isV1() && oldValue != newValue) | 204 if (root->isV1() && oldValue != newValue) |
202 root->assignV1(); | 205 root->ensureSlotAssignment().slotRenamed(normalizeSlotName(oldVa
lue), *this); |
203 } | 206 } |
204 } | 207 } |
205 HTMLElement::attributeChanged(name, oldValue, newValue, reason); | 208 HTMLElement::attributeChanged(name, oldValue, newValue, reason); |
206 } | 209 } |
207 | 210 |
208 void HTMLSlotElement::childrenChanged(const ChildrenChange& change) | 211 static bool wasInShadowTreeBeforeInserted(HTMLSlotElement& slot, ContainerNode&
insertionPoint) |
209 { | 212 { |
210 HTMLElement::childrenChanged(change); | 213 ShadowRoot* root1 = slot.containingShadowRoot(); |
211 if (ShadowRoot* root = containingShadowRoot()) { | 214 ShadowRoot* root2 = insertionPoint.containingShadowRoot(); |
212 if (ElementShadow* rootOwner = root->owner()) { | 215 if (root1 && root2 && root1 == root2) |
213 rootOwner->setNeedsDistributionRecalc(); | 216 return false; |
214 } | 217 return root1; |
215 if (m_assignedNodes.isEmpty() && root->isV1()) | |
216 root->assignV1(); | |
217 } | |
218 } | 218 } |
219 | 219 |
220 Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode*
insertionPoint) | 220 Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode*
insertionPoint) |
221 { | 221 { |
222 HTMLElement::insertedInto(insertionPoint); | 222 HTMLElement::insertedInto(insertionPoint); |
223 ShadowRoot* root = containingShadowRoot(); | 223 ShadowRoot* root = containingShadowRoot(); |
224 if (root) { | 224 if (root) { |
225 if (ElementShadow* rootOwner = root->owner()) | 225 DCHECK(root->owner()); |
226 rootOwner->setNeedsDistributionRecalc(); | 226 root->owner()->setNeedsDistributionRecalc(); |
227 if (root == insertionPoint->treeScope().rootNode()) | 227 // Relevant DOM Standard: https://dom.spec.whatwg.org/#concept-node-inse
rt |
228 root->didAddSlot(); | 228 // - 6.4: Run assign slotables for a tree with node's tree and a set co
ntaining each inclusive descendant of node that is a slot. |
| 229 if (!wasInShadowTreeBeforeInserted(*this, *insertionPoint)) |
| 230 root->ensureSlotAssignment().slotAdded(*this); |
229 } | 231 } |
230 | 232 |
231 // We could have been distributed into in a detached subtree, make sure to | 233 // We could have been distributed into in a detached subtree, make sure to |
232 // clear the distribution when inserted again to avoid cycles. | 234 // clear the distribution when inserted again to avoid cycles. |
233 clearDistribution(); | 235 clearDistribution(); |
234 | 236 |
235 if (root && root->isV1()) | 237 return InsertionDone; |
236 root->assignV1(); | 238 } |
237 | 239 |
238 return InsertionDone; | 240 static ShadowRoot* containingShadowRootBeforeRemoved(Node& removedDescendant, Co
ntainerNode& insertionPoint) |
| 241 { |
| 242 if (ShadowRoot* root = removedDescendant.containingShadowRoot()) |
| 243 return root; |
| 244 return insertionPoint.containingShadowRoot(); |
239 } | 245 } |
240 | 246 |
241 void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint) | 247 void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint) |
242 { | 248 { |
243 ShadowRoot* root = containingShadowRoot(); | 249 // `removedFrom` is called after the node is removed from the tree. |
244 if (!root) | 250 // That means: |
245 root = insertionPoint->containingShadowRoot(); | 251 // 1. If this slot is still in a tree scope, it means the slot has been in a
shadow tree. An inclusive shadow-including ancestor of the shadow host was orig
inally removed from its parent. |
| 252 // 2. Or (this slot is now not in a tree scope), this slot's inclusive ances
tor was orginally removed from its parent (== insertion point). This slot and th
e originally removed node was in the same tree. |
| 253 |
| 254 ShadowRoot* root = containingShadowRootBeforeRemoved(*this, *insertionPoint)
; |
246 if (root) { | 255 if (root) { |
247 if (ElementShadow* rootOwner = root->owner()) | 256 if (ElementShadow* rootOwner = root->owner()) |
248 rootOwner->setNeedsDistributionRecalc(); | 257 rootOwner->setNeedsDistributionRecalc(); |
249 } | 258 } |
250 | 259 |
251 // Since this insertion point is no longer visible from the shadow subtree,
it need to clean itself up. | 260 // Since this insertion point is no longer visible from the shadow subtree,
it need to clean itself up. |
252 clearDistribution(); | 261 clearDistribution(); |
253 | 262 |
254 ContainerNode& rootNode = insertionPoint->treeScope().rootNode(); | 263 if (root && root->isV1() && root == insertionPoint->treeScope().rootNode())
{ |
255 if (root == &rootNode) | 264 // This slot was in a shadow tree and got disconnected from the shadow r
oot. |
256 root->didRemoveSlot(); | 265 root->ensureSlotAssignment().slotRemoved(*this); |
257 else if (rootNode.isShadowRoot() && toShadowRoot(rootNode).isV1()) | 266 } |
258 toShadowRoot(rootNode).assignV1(); | |
259 | 267 |
260 if (root && root->isV1()) | |
261 root->assignV1(); | |
262 HTMLElement::removedFrom(insertionPoint); | 268 HTMLElement::removedFrom(insertionPoint); |
263 } | 269 } |
264 | 270 |
265 void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change) | 271 void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change) |
266 { | 272 { |
267 if (change < Inherit && getStyleChangeType() < SubtreeStyleChange) | 273 if (change < Inherit && getStyleChangeType() < SubtreeStyleChange) |
268 return; | 274 return; |
269 | 275 |
270 for (auto& node : m_distributedNodes) | 276 for (auto& node : m_distributedNodes) |
271 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing:
:create(StyleChangeReason::PropagateInheritChangeToDistributedNodes)); | 277 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing:
:create(StyleChangeReason::PropagateInheritChangeToDistributedNodes)); |
272 } | 278 } |
273 | 279 |
274 void HTMLSlotElement::updateFallbackNodes() | |
275 { | |
276 if (!m_fallbackNodes.isEmpty()) | |
277 return; | |
278 for (auto& child : NodeTraversal::childrenOf(*this)) { | |
279 if (!child.isSlotAssignable()) | |
280 continue; | |
281 // Insertion points are not supported as slots fallback | |
282 if (isActiveInsertionPoint(child)) | |
283 continue; | |
284 appendFallbackNode(child); | |
285 } | |
286 } | |
287 | |
288 void HTMLSlotElement::updateDistributedNodesWithFallback() | 280 void HTMLSlotElement::updateDistributedNodesWithFallback() |
289 { | 281 { |
290 if (!m_distributedNodes.isEmpty()) | 282 if (!m_distributedNodes.isEmpty()) |
291 return; | 283 return; |
292 for (auto node : m_fallbackNodes) { | 284 for (auto& child : NodeTraversal::childrenOf(*this)) { |
293 if (isHTMLSlotElement(node)) | 285 if (!child.isSlotable()) |
294 appendDistributedNodesFrom(*toHTMLSlotElement(node)); | 286 continue; |
| 287 if (isHTMLSlotElement(child)) |
| 288 appendDistributedNodesFrom(toHTMLSlotElement(child)); |
295 else | 289 else |
296 appendDistributedNode(*node); | 290 appendDistributedNode(child); |
297 } | 291 } |
298 } | 292 } |
299 | 293 |
300 bool HTMLSlotElement::assignmentChanged() | 294 void HTMLSlotElement::enqueueSlotChangeEvent() |
301 { | 295 { |
302 ASSERT(m_assignmentState != AssignmentOnGoing); | 296 if (!m_slotchangeEventEnqueued) { |
303 if (m_assignmentState == AssignmentDone) | 297 Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChan
geEvent, Persistent<HTMLSlotElement>(this))); |
304 m_assignmentState = m_oldAssignedNodes == m_assignedNodes ? AssignmentUn
changed : AssignmentChanged; | 298 m_slotchangeEventEnqueued = true; |
305 return m_assignmentState == AssignmentChanged; | 299 } |
306 } | |
307 | 300 |
308 bool HTMLSlotElement::distributionChanged() | 301 ShadowRoot* root = containingShadowRoot(); |
309 { | 302 DCHECK(root); |
310 ASSERT(m_distributionState != DistributionOnGoing); | 303 DCHECK(root->isV1()); |
311 if (m_distributionState == DistributionDone) | 304 root->owner()->setNeedsDistributionRecalc(); |
312 m_distributionState = m_oldDistributedNodes == m_distributedNodes ? Dist
ributionUnchanged : DistributionChanged; | |
313 return m_distributionState == DistributionChanged; | |
314 } | |
315 | 305 |
316 bool HTMLSlotElement::fallbackChanged() | 306 if (ShadowRoot* parentShadowRoot = v1ShadowRootOfParent()) { |
317 { | 307 if (HTMLSlotElement* next = parentShadowRoot->ensureSlotAssignment().fin
dSlot(*this)) |
318 return m_oldFallbackNodes == m_fallbackNodes; | 308 next->enqueueSlotChangeEvent(); |
319 } | |
320 | |
321 void HTMLSlotElement::didUpdateAssignment() | |
322 { | |
323 ASSERT(m_assignmentState == AssignmentOnGoing); | |
324 m_assignmentState = AssignmentDone; | |
325 if ((assignmentChanged() || fallbackChanged()) && !m_slotchangeEventAdded) | |
326 fireSlotChangeEvent(); | |
327 } | |
328 | |
329 void HTMLSlotElement::didUpdateDistribution() | |
330 { | |
331 ASSERT(m_distributionState == DistributionOnGoing); | |
332 m_distributionState = DistributionDone; | |
333 if (isChildOfV1ShadowHost()) { | |
334 ElementShadow* shadow = parentElementShadow(); | |
335 ASSERT(shadow); | |
336 if (!shadow->needsDistributionRecalc() && distributionChanged()) | |
337 shadow->setNeedsDistributionRecalc(); | |
338 } | 309 } |
339 } | 310 } |
340 | 311 |
341 void HTMLSlotElement::fireSlotChangeEvent() | 312 bool HTMLSlotElement::hasAssignedNodesSlow() const |
342 { | 313 { |
343 ASSERT(!m_slotchangeEventAdded); | 314 ShadowRoot* root = containingShadowRoot(); |
344 Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChangeEv
ent, this)); | 315 DCHECK(root); |
345 m_slotchangeEventAdded = true; | 316 DCHECK(root->isV1()); |
346 | 317 SlotAssignment& assignment = root->ensureSlotAssignment(); |
347 Element* shadowHost = isShadowHost(parentElement()) ? parentElement() : null
ptr; | 318 if (assignment.findSlot(*this) != this) |
348 // If this slot is assigned to another slot, fire slot change event of that
slot too. | 319 return false; |
349 if (shadowHost && shadowHost->shadowRootIfV1()) { | 320 return assignment.findHostChildBySlotName(name()); |
350 if (HTMLSlotElement* assigned = assignedSlot()) { | |
351 if (!assigned->m_slotchangeEventAdded) | |
352 assigned->fireSlotChangeEvent(); | |
353 } | |
354 } | |
355 } | 321 } |
356 | 322 |
357 void HTMLSlotElement::clearDistribution() | 323 bool HTMLSlotElement::findHostChildWithSameSlotName() const |
358 { | 324 { |
359 willUpdateDistribution(); | 325 ShadowRoot* root = containingShadowRoot(); |
360 didUpdateDistribution(); | 326 DCHECK(root); |
| 327 DCHECK(root->isV1()); |
| 328 SlotAssignment& assignment = root->ensureSlotAssignment(); |
| 329 return assignment.findHostChildBySlotName(name()); |
361 } | 330 } |
362 | 331 |
363 short HTMLSlotElement::tabIndex() const | 332 short HTMLSlotElement::tabIndex() const |
364 { | 333 { |
365 return Element::tabIndex(); | 334 return Element::tabIndex(); |
366 } | 335 } |
367 | 336 |
368 DEFINE_TRACE(HTMLSlotElement) | 337 DEFINE_TRACE(HTMLSlotElement) |
369 { | 338 { |
370 visitor->trace(m_assignedNodes); | 339 visitor->trace(m_assignedNodes); |
371 visitor->trace(m_distributedNodes); | 340 visitor->trace(m_distributedNodes); |
372 visitor->trace(m_fallbackNodes); | |
373 visitor->trace(m_distributedIndices); | 341 visitor->trace(m_distributedIndices); |
374 visitor->trace(m_oldAssignedNodes); | |
375 visitor->trace(m_oldDistributedNodes); | |
376 visitor->trace(m_oldFallbackNodes); | |
377 HTMLElement::trace(visitor); | 342 HTMLElement::trace(visitor); |
378 } | 343 } |
379 | 344 |
380 } // namespace blink | 345 } // namespace blink |
OLD | NEW |