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

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: Refactor 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 30 matching lines...) Expand all
170 { 189 {
171 for (auto& node : m_distributedNodes) 190 for (auto& node : m_distributedNodes)
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 if (root->isV1() && oldValue != newValue)
202 root->assignV1();
203 }
182 } 204 }
183 HTMLElement::attributeChanged(name, oldValue, newValue, reason); 205 HTMLElement::attributeChanged(name, oldValue, newValue, reason);
184 } 206 }
185 207
186 void HTMLSlotElement::childrenChanged(const ChildrenChange& change) 208 void HTMLSlotElement::childrenChanged(const ChildrenChange& change)
187 { 209 {
188 HTMLElement::childrenChanged(change); 210 HTMLElement::childrenChanged(change);
189 if (ShadowRoot* root = containingShadowRoot()) { 211 if (ShadowRoot* root = containingShadowRoot()) {
190 if (ElementShadow* rootOwner = root->owner()) 212 if (ElementShadow* rootOwner = root->owner()) {
191 rootOwner->setNeedsDistributionRecalc(); 213 rootOwner->setNeedsDistributionRecalc();
214 }
215 if (m_assignedNodes.isEmpty() && root->isV1())
216 root->assignV1();
192 } 217 }
193 } 218 }
194 219
195 Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode* insertionPoint) 220 Node::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode* insertionPoint)
196 { 221 {
197 HTMLElement::insertedInto(insertionPoint); 222 HTMLElement::insertedInto(insertionPoint);
198 if (ShadowRoot* root = containingShadowRoot()) { 223 ShadowRoot* root = containingShadowRoot();
224 if (root) {
199 if (ElementShadow* rootOwner = root->owner()) 225 if (ElementShadow* rootOwner = root->owner())
200 rootOwner->setNeedsDistributionRecalc(); 226 rootOwner->setNeedsDistributionRecalc();
201 if (root == insertionPoint->treeScope().rootNode()) 227 if (root == insertionPoint->treeScope().rootNode())
202 root->didAddSlot(); 228 root->didAddSlot();
203 } 229 }
204 230
205 // We could have been distributed into in a detached subtree, make sure to 231 // We could have been distributed into in a detached subtree, make sure to
206 // clear the distribution when inserted again to avoid cycles. 232 // clear the distribution when inserted again to avoid cycles.
207 clearDistribution(); 233 clearDistribution();
208 234
235 if (root && root->isV1())
236 root->assignV1();
237
209 return InsertionDone; 238 return InsertionDone;
210 } 239 }
211 240
212 void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint) 241 void HTMLSlotElement::removedFrom(ContainerNode* insertionPoint)
213 { 242 {
214 ShadowRoot* root = containingShadowRoot(); 243 ShadowRoot* root = containingShadowRoot();
215 if (!root) 244 if (!root)
216 root = insertionPoint->containingShadowRoot(); 245 root = insertionPoint->containingShadowRoot();
217 if (root) { 246 if (root) {
218 if (ElementShadow* rootOwner = root->owner()) 247 if (ElementShadow* rootOwner = root->owner())
219 rootOwner->setNeedsDistributionRecalc(); 248 rootOwner->setNeedsDistributionRecalc();
220 } 249 }
221 250
222 // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up. 251 // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
223 clearDistribution(); 252 clearDistribution();
224 253
225 if (root == insertionPoint->treeScope().rootNode()) 254 ContainerNode& rootNode = insertionPoint->treeScope().rootNode();
255 if (root == &rootNode)
226 root->didRemoveSlot(); 256 root->didRemoveSlot();
257 else if (rootNode.isShadowRoot() && toShadowRoot(rootNode).isV1())
258 toShadowRoot(rootNode).assignV1();
227 259
260 if (root && root->isV1())
261 root->assignV1();
228 HTMLElement::removedFrom(insertionPoint); 262 HTMLElement::removedFrom(insertionPoint);
229 } 263 }
230 264
231 void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change) 265 void HTMLSlotElement::willRecalcStyle(StyleRecalcChange change)
232 { 266 {
233 if (change < Inherit && getStyleChangeType() < SubtreeStyleChange) 267 if (change < Inherit && getStyleChangeType() < SubtreeStyleChange)
234 return; 268 return;
235 269
236 for (auto& node : m_distributedNodes) 270 for (auto& node : m_distributedNodes)
237 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing: :create(StyleChangeReason::PropagateInheritChangeToDistributedNodes)); 271 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing: :create(StyleChangeReason::PropagateInheritChangeToDistributedNodes));
238 } 272 }
239 273
240 void HTMLSlotElement::updateDistributedNodesWithFallback() 274 void HTMLSlotElement::updateFallbackNodes()
241 { 275 {
242 if (!m_distributedNodes.isEmpty()) 276 if (!m_fallbackNodes.isEmpty())
243 return; 277 return;
244 for (auto& child : NodeTraversal::childrenOf(*this)) { 278 for (auto& child : NodeTraversal::childrenOf(*this)) {
245 if (!child.isSlotAssignable()) 279 if (!child.isSlotAssignable())
246 continue; 280 continue;
247 // Insertion points are not supported as slots fallback 281 // Insertion points are not supported as slots fallback
248 if (isActiveInsertionPoint(child)) 282 if (isActiveInsertionPoint(child))
249 continue; 283 continue;
250 if (isHTMLSlotElement(child)) 284 appendFallbackNode(child);
251 appendDistributedNodesFrom(toHTMLSlotElement(child)); 285 }
286 }
287
288 void HTMLSlotElement::updateDistributedNodesWithFallback()
289 {
290 if (!m_distributedNodes.isEmpty())
291 return;
292 for (auto node : m_fallbackNodes) {
293 if (isHTMLSlotElement(node))
294 appendDistributedNodesFrom(*toHTMLSlotElement(node));
252 else 295 else
253 appendDistributedNode(child); 296 appendDistributedNode(*node);
254 } 297 }
255 } 298 }
256 299
300 bool HTMLSlotElement::assignmentChanged()
301 {
302 ASSERT(m_assignmentState != AssignmentOnGoing);
303 if (m_assignmentState == AssignmentDone)
304 m_assignmentState = m_oldAssignedNodes == m_assignedNodes ? AssignmentUn changed : AssignmentChanged;
305 return m_assignmentState == AssignmentChanged;
306 }
307
257 bool HTMLSlotElement::distributionChanged() 308 bool HTMLSlotElement::distributionChanged()
258 { 309 {
259 ASSERT(m_distributionState != DistributionOnGoing); 310 ASSERT(m_distributionState != DistributionOnGoing);
260 if (m_distributionState == DistributionDone) 311 if (m_distributionState == DistributionDone)
261 m_distributionState = m_oldDistributedNodes == m_distributedNodes ? Dist ributionUnchanged : DistributionChanged; 312 m_distributionState = m_oldDistributedNodes == m_distributedNodes ? Dist ributionUnchanged : DistributionChanged;
262 return m_distributionState == DistributionChanged; 313 return m_distributionState == DistributionChanged;
263 } 314 }
264 315
316 bool HTMLSlotElement::fallbackChanged()
317 {
318 return m_oldFallbackNodes == m_fallbackNodes;
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
265 void HTMLSlotElement::didUpdateDistribution() 329 void HTMLSlotElement::didUpdateDistribution()
266 { 330 {
267 ASSERT(m_distributionState == DistributionOnGoing); 331 ASSERT(m_distributionState == DistributionOnGoing);
268 m_distributionState = DistributionDone; 332 m_distributionState = DistributionDone;
269 if (isChildOfV1ShadowHost()) { 333 if (isChildOfV1ShadowHost()) {
270 ElementShadow* shadow = parentElementShadow(); 334 ElementShadow* shadow = parentElementShadow();
271 ASSERT(shadow); 335 ASSERT(shadow);
272 if (!shadow->needsDistributionRecalc() && distributionChanged()) 336 if (!shadow->needsDistributionRecalc() && distributionChanged())
273 shadow->setNeedsDistributionRecalc(); 337 shadow->setNeedsDistributionRecalc();
274 } 338 }
275 if (hasSlotChangeEventListener() && distributionChanged()) { 339 }
276 // TODO(hayato): Do not enqueue a slotchange event for the same slot twi ce in the microtask queue 340
277 Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChan geEvent, this)); 341 void HTMLSlotElement::fireSlotChangeEvent()
342 {
343 ASSERT(!m_slotchangeEventAdded);
344 Microtask::enqueueMicrotask(WTF::bind(&HTMLSlotElement::dispatchSlotChangeEv ent, this));
345 m_slotchangeEventAdded = true;
346
347 Element* shadowHost = isShadowHost(parentElement()) ? parentElement() : null ptr;
348 ShadowRoot* shadowRoot = shadowRootIfV1();
hayato 2016/04/22 05:33:22 This would be: shadowHost.shadowRootIfV1()
yuzuchan 2016/04/22 06:59:11 Done.
349 // If this slot is assigned to another slot, fire slot change event of that slot too.
350 if (shadowHost && shadowRoot) {
351 if (HTMLSlotElement* assigned = assignedSlot())
352 assigned->fireSlotChangeEvent();
278 } 353 }
279 } 354 }
280 355
281 void HTMLSlotElement::clearDistribution() 356 void HTMLSlotElement::clearDistribution()
282 { 357 {
283 willUpdateDistribution(); 358 willUpdateDistribution();
284 didUpdateDistribution(); 359 didUpdateDistribution();
285 } 360 }
286 361
287 short HTMLSlotElement::tabIndex() const 362 short HTMLSlotElement::tabIndex() const
288 { 363 {
289 return Element::tabIndex(); 364 return Element::tabIndex();
290 } 365 }
291 366
292 DEFINE_TRACE(HTMLSlotElement) 367 DEFINE_TRACE(HTMLSlotElement)
293 { 368 {
294 visitor->trace(m_assignedNodes); 369 visitor->trace(m_assignedNodes);
295 visitor->trace(m_distributedNodes); 370 visitor->trace(m_distributedNodes);
371 visitor->trace(m_fallbackNodes);
296 visitor->trace(m_distributedIndices); 372 visitor->trace(m_distributedIndices);
373 visitor->trace(m_oldAssignedNodes);
297 visitor->trace(m_oldDistributedNodes); 374 visitor->trace(m_oldDistributedNodes);
375 visitor->trace(m_oldFallbackNodes);
298 HTMLElement::trace(visitor); 376 HTMLElement::trace(visitor);
299 } 377 }
300 378
301 } // namespace blink 379 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698