Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLSlotElement.cpp

Issue 1899653002: Support slotchange event (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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"
35 #include "core/dom/NodeTraversal.h" 36 #include "core/dom/NodeTraversal.h"
36 #include "core/dom/StyleChangeReason.h" 37 #include "core/dom/StyleChangeReason.h"
38 #include "core/dom/StyleEngine.h"
37 #include "core/dom/shadow/ElementShadow.h" 39 #include "core/dom/shadow/ElementShadow.h"
38 #include "core/dom/shadow/InsertionPoint.h" 40 #include "core/dom/shadow/InsertionPoint.h"
39 #include "core/events/Event.h" 41 #include "core/events/Event.h"
40 #include "core/html/AssignedNodesOptions.h" 42 #include "core/html/AssignedNodesOptions.h"
41 43
42 namespace blink { 44 namespace blink {
43 45
44 using namespace HTMLNames; 46 using namespace HTMLNames;
45 47
46 inline HTMLSlotElement::HTMLSlotElement(Document& document) 48 inline HTMLSlotElement::HTMLSlotElement(Document& document)
47 : HTMLElement(slotTag, document) 49 : HTMLElement(slotTag, document)
48 , m_distributionState(DistributionDone) 50 , m_distributionState(DistributionDone)
51 , m_assignmentState(AssignmentDone)
52 , m_slotchangeEventAdded(false)
49 { 53 {
50 setHasCustomStyleCallbacks(); 54 setHasCustomStyleCallbacks();
51 } 55 }
52 56
53 DEFINE_NODE_FACTORY(HTMLSlotElement); 57 DEFINE_NODE_FACTORY(HTMLSlotElement);
54 58
55 const HeapVector<Member<Node>> HTMLSlotElement::assignedNodesForBinding(const As signedNodesOptions& options) 59 const HeapVector<Member<Node>> HTMLSlotElement::assignedNodesForBinding(const As signedNodesOptions& options)
56 { 60 {
57 updateDistribution(); 61 updateDistribution();
58 if (options.hasFlatten() && options.flatten()) 62 if (options.hasFlatten() && options.flatten())
(...skipping 20 matching lines...) Expand all
79 m_distributedNodes.appendVector(toHTMLSlotElement(child).getDistribu tedNodes()); 83 m_distributedNodes.appendVector(toHTMLSlotElement(child).getDistribu tedNodes());
80 else 84 else
81 m_distributedNodes.append(&child); 85 m_distributedNodes.append(&child);
82 } 86 }
83 didUpdateDistribution(); 87 didUpdateDistribution();
84 return m_distributedNodes; 88 return m_distributedNodes;
85 } 89 }
86 90
87 void HTMLSlotElement::appendAssignedNode(Node& node) 91 void HTMLSlotElement::appendAssignedNode(Node& node)
88 { 92 {
89 ASSERT(m_distributionState == DistributionOnGoing); 93 ASSERT(m_assignmentState == AssignmentOnGoing);
90 m_assignedNodes.append(&node); 94 m_assignedNodes.append(&node);
91 } 95 }
92 96
93 void HTMLSlotElement::appendDistributedNode(Node& node) 97 void HTMLSlotElement::appendDistributedNode(Node& node)
94 { 98 {
95 ASSERT(m_distributionState == DistributionOnGoing); 99 ASSERT(m_distributionState == DistributionOnGoing);
96 size_t size = m_distributedNodes.size(); 100 size_t size = m_distributedNodes.size();
97 m_distributedNodes.append(&node); 101 m_distributedNodes.append(&node);
98 m_distributedIndices.set(&node, size); 102 m_distributedIndices.set(&node, size);
99 } 103 }
100 104
105 void HTMLSlotElement::appendFallbackNode(Node& node)
106 {
107 ASSERT(m_assignmentState == AssignmentOnGoing);
108 m_fallbackNodes.append(&node);
109 }
110
101 void HTMLSlotElement::appendDistributedNodesFrom(const HTMLSlotElement& other) 111 void HTMLSlotElement::appendDistributedNodesFrom(const HTMLSlotElement& other)
102 { 112 {
103 ASSERT(m_distributionState == DistributionOnGoing); 113 ASSERT(m_distributionState == DistributionOnGoing);
104 size_t index = m_distributedNodes.size(); 114 size_t index = m_distributedNodes.size();
105 m_distributedNodes.appendVector(other.m_distributedNodes); 115 m_distributedNodes.appendVector(other.m_distributedNodes);
106 for (const auto& node : other.m_distributedNodes) 116 for (const auto& node : other.m_distributedNodes)
107 m_distributedIndices.set(node.get(), index++); 117 m_distributedIndices.set(node.get(), index++);
108 } 118 }
109 119
120 void HTMLSlotElement::willUpdateAssignment()
121 {
122 ASSERT(m_assignmentState != AssignmentOnGoing);
123 m_assignmentState = AssignmentOnGoing;
124 m_oldAssignedNodes.swap(m_assignedNodes);
125 m_assignedNodes.clear();
126 }
127
110 void HTMLSlotElement::willUpdateDistribution() 128 void HTMLSlotElement::willUpdateDistribution()
111 { 129 {
112 ASSERT(m_distributionState != DistributionOnGoing); 130 ASSERT(m_distributionState != DistributionOnGoing);
113 m_distributionState = DistributionOnGoing; 131 m_distributionState = DistributionOnGoing;
114 m_assignedNodes.clear();
115 m_oldDistributedNodes.swap(m_distributedNodes); 132 m_oldDistributedNodes.swap(m_distributedNodes);
116 m_distributedNodes.clear(); 133 m_distributedNodes.clear();
117 m_distributedIndices.clear(); 134 m_distributedIndices.clear();
118 } 135 }
119 136
120 bool HTMLSlotElement::hasSlotChangeEventListener() 137 void HTMLSlotElement::willUpdateFallback()
121 { 138 {
122 return eventTargetData() && eventTargetData()->eventListenerMap.find(EventTy peNames::slotchange); 139 m_oldFallbackNodes.swap(m_fallbackNodes);
140 m_fallbackNodes.clear();
123 } 141 }
124 142
125 void HTMLSlotElement::dispatchSlotChangeEvent() 143 void HTMLSlotElement::dispatchSlotChangeEvent()
126 { 144 {
127 Event* event = Event::create(EventTypeNames::slotchange); 145 Event* event = Event::create(EventTypeNames::slotchange);
128 event->setTarget(this); 146 event->setTarget(this);
129 dispatchScopedEvent(event); 147 dispatchScopedEvent(event);
148 m_slotchangeEventAdded = false;
130 } 149 }
131 150
132 Node* HTMLSlotElement::distributedNodeNextTo(const Node& node) const 151 Node* HTMLSlotElement::distributedNodeNextTo(const Node& node) const
133 { 152 {
134 const auto& it = m_distributedIndices.find(&node); 153 const auto& it = m_distributedIndices.find(&node);
135 if (it == m_distributedIndices.end()) 154 if (it == m_distributedIndices.end())
136 return nullptr; 155 return nullptr;
137 size_t index = it->value; 156 size_t index = it->value;
138 if (index + 1 == m_distributedNodes.size()) 157 if (index + 1 == m_distributedNodes.size())
139 return nullptr; 158 return nullptr;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 node->lazyReattachIfAttached(); 191 node->lazyReattachIfAttached();
173 192
174 HTMLElement::detach(context); 193 HTMLElement::detach(context);
175 } 194 }
176 195
177 void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicSt ring& oldValue, const AtomicString& newValue, AttributeModificationReason reason ) 196 void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicSt ring& oldValue, const AtomicString& newValue, AttributeModificationReason reason )
178 { 197 {
179 if (name == nameAttr) { 198 if (name == nameAttr) {
180 if (ShadowRoot* root = containingShadowRoot()) 199 if (ShadowRoot* root = containingShadowRoot())
181 root->owner()->willAffectSelector(); 200 root->owner()->willAffectSelector();
201 document().updateAssignment();
182 } 202 }
183 HTMLElement::attributeChanged(name, oldValue, newValue, reason); 203 HTMLElement::attributeChanged(name, oldValue, newValue, reason);
184 } 204 }
185 205
186 void HTMLSlotElement::childrenChanged(const ChildrenChange& change) 206 void HTMLSlotElement::childrenChanged(const ChildrenChange& change)
187 { 207 {
188 HTMLElement::childrenChanged(change); 208 HTMLElement::childrenChanged(change);
189 if (ShadowRoot* root = containingShadowRoot()) { 209 if (ShadowRoot* root = containingShadowRoot()) {
190 if (ElementShadow* rootOwner = root->owner()) 210 if (ElementShadow* rootOwner = root->owner()) {
191 rootOwner->setNeedsDistributionRecalc(); 211 rootOwner->setNeedsDistributionRecalc();
212 if (document().shadowCascadeOrder() == ShadowCascadeOrder::ShadowCas cadeV1)
213 document().updateAssignment();
214 }
192 } 215 }
193 } 216 }
194 217
195 Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode* insertionPoint) 218 Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode* insertionPoint)
196 { 219 {
197 HTMLElement::insertedInto(insertionPoint); 220 HTMLElement::insertedInto(insertionPoint);
198 if (ShadowRoot* root = containingShadowRoot()) { 221 if (ShadowRoot* root = containingShadowRoot()) {
199 if (ElementShadow* rootOwner = root->owner()) 222 if (ElementShadow* rootOwner = root->owner())
200 rootOwner->setNeedsDistributionRecalc(); 223 rootOwner->setNeedsDistributionRecalc();
201 if (root == insertionPoint->treeScope().rootNode()) 224 if (root == insertionPoint->treeScope().rootNode())
202 root->didAddSlot(); 225 root->didAddSlot();
203 } 226 }
204 227
205 // We could have been distributed into in a detached subtree, make sure to 228 // We could have been distributed into in a detached subtree, make sure to
206 // clear the distribution when inserted again to avoid cycles. 229 // clear the distribution when inserted again to avoid cycles.
207 clearDistribution(); 230 clearDistribution();
208 231
232 if (document().shadowCascadeOrder() == ShadowCascadeOrder::ShadowCascadeV1)
233 document().updateAssignment();
209 return InsertionDone; 234 return InsertionDone;
210 } 235 }
211 236
212 void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint) 237 void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint)
213 { 238 {
214 ShadowRoot* root = containingShadowRoot(); 239 ShadowRoot* root = containingShadowRoot();
215 if (!root) 240 if (!root)
216 root = insertionPoint->containingShadowRoot(); 241 root = insertionPoint->containingShadowRoot();
217 if (root) { 242 if (root) {
218 if (ElementShadow* rootOwner = root->owner()) 243 if (ElementShadow* rootOwner = root->owner())
219 rootOwner->setNeedsDistributionRecalc(); 244 rootOwner->setNeedsDistributionRecalc();
220 } 245 }
221 246
222 // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up. 247 // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
223 clearDistribution(); 248 clearDistribution();
224 249
225 if (root == insertionPoint->treeScope().rootNode()) 250 if (root == insertionPoint->treeScope().rootNode())
226 root->didRemoveSlot(); 251 root->didRemoveSlot();
227 252 if (document().shadowCascadeOrder() == ShadowCascadeOrder::ShadowCascadeV1) {
253 document().updateAssignment();
254 }
228 HTMLElement::removedFrom(insertionPoint); 255 HTMLElement::removedFrom(insertionPoint);
229 } 256 }
230 257
231 void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change) 258 void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change)
232 { 259 {
233 if (change < Inherit && getStyleChangeType() < SubtreeStyleChange) 260 if (change < Inherit && getStyleChangeType() < SubtreeStyleChange)
234 return; 261 return;
235 262
236 for (auto& node : m_distributedNodes) 263 for (auto& node : m_distributedNodes)
237 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing: :create(StyleChangeReason::PropagateInheritChangeToDistributedNodes)); 264 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing: :create(StyleChangeReason::PropagateInheritChangeToDistributedNodes));
238 } 265 }
239 266
240 void HTMLSlotElement::updateDistributedNodesWithFallback() 267 void HTMLSlotElement::updateFallbackNodes()
241 { 268 {
242 if (!m_distributedNodes.isEmpty()) 269 if (!m_fallbackNodes.isEmpty())
243 return; 270 return;
244 for (auto& child : NodeTraversal::childrenOf(*this)) { 271 for (auto& child : NodeTraversal::childrenOf(*this)) {
245 if (!child.isSlotAssignable()) 272 if (!child.isSlotAssignable())
246 continue; 273 continue;
247 // Insertion points are not supported as slots fallback 274 // Insertion points are not supported as slots fallback
248 if (isActiveInsertionPoint(child)) 275 if (isActiveInsertionPoint(child))
249 continue; 276 continue;
250 if (isHTMLSlotElement(child)) 277 appendFallbackNode(child);
251 appendDistributedNodesFrom(toHTMLSlotElement(child)); 278 }
279 }
280
281 void HTMLSlotElement::updateDistributedNodesWithFallback()
282 {
283 if (!m_distributedNodes.isEmpty())
284 return;
285 for (auto node : m_fallbackNodes) {
286 if (isHTMLSlotElement(node))
287 appendDistributedNodesFrom(*toHTMLSlotElement(node));
252 else 288 else
253 appendDistributedNode(child); 289 appendDistributedNode(*node);
254 } 290 }
255 } 291 }
256 292
293 bool HTMLSlotElement::assignmentChanged()
294 {
295 ASSERT(m_assignmentState != AssignmentOnGoing);
296 if (m_assignmentState == AssignmentDone)
297 m_assignmentState = m_oldAssignedNodes == m_assignedNodes ? AssignmentUn changed : AssignmentChanged;
298 return m_assignmentState == AssignmentChanged;
299 }
300
257 bool HTMLSlotElement::distributionChanged() 301 bool HTMLSlotElement::distributionChanged()
258 { 302 {
259 ASSERT(m_distributionState != DistributionOnGoing); 303 ASSERT(m_distributionState != DistributionOnGoing);
260 if (m_distributionState == DistributionDone) 304 if (m_distributionState == DistributionDone)
261 m_distributionState = m_oldDistributedNodes == m_distributedNodes ? Dist ributionUnchanged : DistributionChanged; 305 m_distributionState = m_oldDistributedNodes == m_distributedNodes ? Dist ributionUnchanged : DistributionChanged;
262 return m_distributionState == DistributionChanged; 306 return m_distributionState == DistributionChanged;
263 } 307 }
264 308
309 bool HTMLSlotElement::fallbackChanged()
310 {
311 return m_oldFallbackNodes == m_fallbackNodes;
312 }
313
314 void HTMLSlotElement::didUpdateAssignment()
315 {
316 ASSERT(m_assignmentState == AssignmentOnGoing);
317 m_assignmentState = AssignmentDone;
318 if ((assignmentChanged() || fallbackChanged()) && !m_slotchangeEventAdded)
319 fireSlotChangeEvent();
320 }
321
265 void HTMLSlotElement::didUpdateDistribution() 322 void HTMLSlotElement::didUpdateDistribution()
266 { 323 {
267 ASSERT(m_distributionState == DistributionOnGoing); 324 ASSERT(m_distributionState == DistributionOnGoing);
268 m_distributionState = DistributionDone; 325 m_distributionState = DistributionDone;
269 if (isChildOfV1ShadowHost()) { 326 if (isChildOfV1ShadowHost()) {
270 ElementShadow* shadow = parentElementShadow(); 327 ElementShadow* shadow = parentElementShadow();
271 ASSERT(shadow); 328 ASSERT(shadow);
272 if (!shadow->needsDistributionRecalc() && distributionChanged()) 329 if (!shadow->needsDistributionRecalc() && distributionChanged())
273 shadow->setNeedsDistributionRecalc(); 330 shadow->setNeedsDistributionRecalc();
274 } 331 }
275 if (hasSlotChangeEventListener() && distributionChanged()) { 332 }
276 // TODO(hayato): Do not enqueue a slotchange event for the same slot twi ce in the microtask queue 333
277 Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChan geEvent, this)); 334 void HTMLSlotElement::fireSlotChangeEvent()
335 {
336 ASSERT(!m_slotchangeEventAdded);
337 Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChangeEv ent, this));
338 m_slotchangeEventAdded = true;
339
340 Element* shadowHost = isShadowHost(parentElement()) ? parentElement() : null ptr;
341 ShadowRoot* shadowRoot = shadowRootIfV1();
342 if (shadowHost && shadowRoot) {
343 // If this slot is assigned to another slot, fire slot change event of t hat slot too.
344 const AtomicString& assignedSlot = normalizeSlotName(fastGetAttribute(HT MLNames::slotAttr));
345 if (assignedSlot != emptyAtom) {
346 const HeapVector<Member<HTMLSlotElement>>& slots = shadowRoot->desce ndantSlots();
347 for (Member<HTMLSlotElement> slot : slots) {
348 if (slot->name() == assignedSlot && !slot->hasSlotChangeEventInM icrotask()) {
349 slot->fireSlotChangeEvent();
350 break;
351 }
352 }
353 }
278 } 354 }
279 } 355 }
280 356
281 void HTMLSlotElement::clearDistribution() 357 void HTMLSlotElement::clearDistribution()
282 { 358 {
283 willUpdateDistribution(); 359 willUpdateDistribution();
284 didUpdateDistribution(); 360 didUpdateDistribution();
285 } 361 }
286 362
287 short HTMLSlotElement::tabIndex() const 363 short HTMLSlotElement::tabIndex() const
288 { 364 {
289 return Element::tabIndex(); 365 return Element::tabIndex();
290 } 366 }
291 367
292 DEFINE_TRACE(HTMLSlotElement) 368 DEFINE_TRACE(HTMLSlotElement)
293 { 369 {
294 visitor->trace(m_assignedNodes); 370 visitor->trace(m_assignedNodes);
295 visitor->trace(m_distributedNodes); 371 visitor->trace(m_distributedNodes);
372 visitor->trace(m_fallbackNodes);
296 visitor->trace(m_distributedIndices); 373 visitor->trace(m_distributedIndices);
374 visitor->trace(m_oldAssignedNodes);
297 visitor->trace(m_oldDistributedNodes); 375 visitor->trace(m_oldDistributedNodes);
376 visitor->trace(m_oldFallbackNodes);
298 HTMLElement::trace(visitor); 377 HTMLElement::trace(visitor);
299 } 378 }
300 379
301 } // namespace blink 380 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698