Title: [235458] trunk
Revision
235458
Author
rn...@webkit.org
Date
2018-08-28 22:31:57 -0700 (Tue, 28 Aug 2018)

Log Message

Changes to slot children should trigger slotchange
https://bugs.webkit.org/show_bug.cgi?id=169718
<rdar://problem/43317496>

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Rebaselined the test now that relevant test cases pass.

* web-platform-tests/shadow-dom/slotchange-expected.txt:

Source/WebCore:

Fix the bug that slotchange event is not fired when a slot's fallback content is updated now that slotchange event
is more formally specified.

This particular behavior corresponds to step 7.5. of the concept *to insert a node* where it says:
"[I]f parent’s root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run signal
a slot change for parent."

See https://dom.spec.whatwg.org/#concept-node-insert

Tests: fast/shadow-dom/slotchange-in-fallback.html
       imported/w3c/web-platform-tests/shadow-dom/slotchange.html 

* dom/Element.cpp:
(WebCore::Element::childrenChanged): Updated the comment.
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::addSlotElementByName): Added an assertion.
(WebCore::ShadowRoot::slotFallbackDidChange): Added.
* dom/ShadowRoot.h:
* dom/SlotAssignment.cpp:
(WebCore::SlotAssignment::slotFallbackDidChange): Added. When the assigned nodes is empty, we enqueue a slotchange.
Because assignedNodesForSlot invokes assignSlots, this can be O(n) but we don't expect mutating slot's fallback
contents and shadow host's children in turn to be a common scenario so this shouldn't be an issue in practice.
* dom/SlotAssignment.h:
* html/HTMLSlotElement.cpp:
(WebCore::HTMLSlotElement::insertedIntoAncestor): Be explicit about auto* being used here.
(WebCore::HTMLSlotElement::childrenChanged): Added. Invokes slotFallbackDidChange whenver child node is muated.
* html/HTMLSlotElement.h:

LayoutTests:

Added a W3C style testharness.js test for firing slotchange event for the fallback content change
since web-platform-tests/shadow-dom/slotchange.html doesn't have adequate set of tests.

Chrome and Firefox pass all test cases. WebKit used to fail all test cases before this patch.

* fast/shadow-dom/slotchange-in-fallback-expected.txt: Added.
* fast/shadow-dom/slotchange-in-fallback.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (235457 => 235458)


--- trunk/LayoutTests/ChangeLog	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/LayoutTests/ChangeLog	2018-08-29 05:31:57 UTC (rev 235458)
@@ -1,3 +1,19 @@
+2018-08-28  Ryosuke Niwa  <rn...@webkit.org>
+
+        Changes to slot children should trigger slotchange
+        https://bugs.webkit.org/show_bug.cgi?id=169718
+        <rdar://problem/43317496>
+
+        Reviewed by Darin Adler.
+
+        Added a W3C style testharness.js test for firing slotchange event for the fallback content change
+        since web-platform-tests/shadow-dom/slotchange.html doesn't have adequate set of tests.
+
+        Chrome and Firefox pass all test cases. WebKit used to fail all test cases before this patch.
+
+        * fast/shadow-dom/slotchange-in-fallback-expected.txt: Added.
+        * fast/shadow-dom/slotchange-in-fallback.html: Added.
+
 2018-08-28  Don Olmstead  <don.olmst...@sony.com>
 
         Check for null renderer in canBeScrolledIntoView

Added: trunk/LayoutTests/fast/shadow-dom/slotchange-in-fallback-expected.txt (0 => 235458)


--- trunk/LayoutTests/fast/shadow-dom/slotchange-in-fallback-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/slotchange-in-fallback-expected.txt	2018-08-29 05:31:57 UTC (rev 235458)
@@ -0,0 +1,66 @@
+
+PASS slotchange event should be fired when appending a text node to a default slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when appending a text node to a default slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when appending a text node to a default slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when appending a text node to a default slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when appending a text node to a named slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when appending a text node to a named slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when appending a text node to a named slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when appending a text node to a named slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when appending a div to a default slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when appending a div to a default slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when appending a div to a default slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when appending a div to a default slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when appending a div to a named slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when appending a div to a named slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when appending a div to a named slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when appending a div to a named slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when removing a text node from a default slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when removing a text node from a default slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when removing a text node from a default slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when removing a text node from a default slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when removing a text node from a named slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when removing a text node from a named slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when removing a text node from a named slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when removing a text node from a named slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when removing a div from a default slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when removing a div from a default slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when removing a div from a default slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when removing a div from a default slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should be fired when removing a div from a named slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should be fired when removing a div from a named slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should be fired when removing a div from a named slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should be fired when removing a div from a named slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a default slot whose assigned nodes is not empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a default slot whose assigned nodes is not empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a default slot whose assigned nodes is not empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a default slot whose assigned nodes is not empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a named slot whose assigned nodes is not empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a named slot whose assigned nodes is not empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a named slot whose assigned nodes is not empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when appending a text node to a named slot whose assigned nodes is not empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when appending a div to a default slot whose assigned nodes is not empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when appending a div to a default slot whose assigned nodes is not empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when appending a div to a default slot whose assigned nodes is not empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when appending a div to a default slot whose assigned nodes is not empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when appending a div to a named slot whose assigned nodes is not empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when appending a div to a named slot whose assigned nodes is not empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when appending a div to a named slot whose assigned nodes is not empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when appending a div to a named slot whose assigned nodes is not empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a default slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a default slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a default slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a default slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a named slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a named slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a named slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when removing a text node from a named slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when removing a div from a default slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when removing a div from a default slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when removing a div from a default slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when removing a div from a default slot whose assigned nodes is empty in a disconnected open mode shadow root 
+PASS slotchange event should not be fired when removing a div from a named slot whose assigned nodes is empty in a connected closed mode shadow root 
+PASS slotchange event should not be fired when removing a div from a named slot whose assigned nodes is empty in a disconnected closed mode shadow root 
+PASS slotchange event should not be fired when removing a div from a named slot whose assigned nodes is empty in a connected open mode shadow root 
+PASS slotchange event should not be fired when removing a div from a named slot whose assigned nodes is empty in a disconnected open mode shadow root 
+

Added: trunk/LayoutTests/fast/shadow-dom/slotchange-in-fallback.html (0 => 235458)


--- trunk/LayoutTests/fast/shadow-dom/slotchange-in-fallback.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/slotchange-in-fallback.html	2018-08-29 05:31:57 UTC (rev 235458)
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: slotchange event in fallback content</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<link rel="help" href=""
+<link rel="help" href=""
+<script src=""
+<script src=""
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+function generateTests(...args) {
+    testMutatingSlot('closed', true, ...args);
+    testMutatingSlot('closed', false, ...args);
+    testMutatingSlot('open', true, ...args);
+    testMutatingSlot('open', false, ...args);
+}
+
+function testMutatingSlot(mode, connectedToDocument, shadowContent, slotName, prepareSlot, mutateSlot, description)
+{
+    promise_test(async function () {
+        const host = document.createElement('div');
+        if (connectedToDocument)
+            document.body.appendChild(host);
+        if (shadowContent)
+            host.innerHTML = shadowContent;
+
+        const shadowRoot = host.attachShadow({mode});
+
+        const slot = document.createElement('slot');
+        let eventCount = 0;
+        if (slotName)
+            slot.name = slotName;
+        prepareSlot(slot);
+        slot.addEventListener('slotchange', () => eventCount++);
+
+        shadowRoot.appendChild(slot);
+
+        await Promise.resolve();
+        eventCount = 0;
+
+        mutateSlot(slot);
+        await Promise.resolve();
+        assert_equals(eventCount, shadowContent ? 0 : 1);
+
+        slot.remove();
+    }, description + ` in a ${connectedToDocument ? 'connected' : 'disconnected'} ${mode} mode shadow root`);
+}
+
+generateTests(null, null, () => { }, (slot) => slot.append('some text'),
+    'slotchange event should be fired when appending a text node to a default slot whose assigned nodes is empty');
+generateTests(null, 'foo', () => { },  (slot) => slot.append('some text'),
+    'slotchange event should be fired when appending a text node to a named slot whose assigned nodes is empty');
+generateTests(null, null, () => { }, (slot) => slot.append(document.createTextNode('div')),
+    'slotchange event should be fired when appending a div to a default slot whose assigned nodes is empty');
+generateTests(null, 'foo', () => { }, (slot) => slot.append(document.createTextNode('div')),
+    'slotchange event should be fired when appending a div to a named slot whose assigned nodes is empty');
+
+generateTests(null, null, (slot) => slot.append('hello'), (slot) => slot.firstChild.remove(),
+    'slotchange event should be fired when removing a text node from a default slot whose assigned nodes is empty');
+generateTests(null, 'foo', (slot) => slot.append('hello'), (slot) => slot.firstChild.remove(),
+    'slotchange event should be fired when removing a text node from a named slot whose assigned nodes is empty');
+generateTests(null, 'foo', (slot) => slot.append(document.createElement('div')), (slot) => slot.firstChild.remove(),
+    'slotchange event should be fired when removing a div from a default slot whose assigned nodes is empty');
+generateTests(null, 'foo', (slot) => slot.append(document.createElement('div')), (slot) => slot.firstChild.remove(),
+    'slotchange event should be fired when removing a div from a named slot whose assigned nodes is empty');
+
+generateTests('hello', null, () => { }, (slot) => slot.append('some text'),
+    'slotchange event should not be fired when appending a text node to a default slot whose assigned nodes is not empty');
+generateTests('<div slot="foo"></div>', 'foo', () => { }, (slot) => slot.append('some text'),
+    'slotchange event should not be fired when appending a text node to a named slot whose assigned nodes is not empty');
+generateTests('<div></div>', null, () => { }, (slot) => slot.append(document.createTextNode('div')),
+    'slotchange event should not be fired when appending a div to a default slot whose assigned nodes is not empty');
+generateTests('<div slot="foo"></div>', 'foo', () => { }, (slot) => slot.append(document.createTextNode('div')),
+    'slotchange event should not be fired when appending a div to a named slot whose assigned nodes is not empty');
+
+generateTests('<span></span>', null, (slot) => slot.append('hello'), (slot) => slot.firstChild.remove(),
+    'slotchange event should not be fired when removing a text node from a default slot whose assigned nodes is empty');
+generateTests('<span slot="foo"></span>', 'foo', (slot) => slot.append('hello'), (slot) => slot.firstChild.remove(),
+    'slotchange event should not be fired when removing a text node from a named slot whose assigned nodes is empty');
+generateTests('<span></span>', null, (slot) => slot.append(document.createElement('div')), (slot) => slot.firstChild.remove(),
+    'slotchange event should not be fired when removing a div from a default slot whose assigned nodes is empty');
+generateTests('<span slot="foo"></span>', 'foo', (slot) => slot.append(document.createElement('div')), (slot) => slot.firstChild.remove(),
+    'slotchange event should not be fired when removing a div from a named slot whose assigned nodes is empty');
+
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (235457 => 235458)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2018-08-29 05:31:57 UTC (rev 235458)
@@ -1,3 +1,15 @@
+2018-08-28  Ryosuke Niwa  <rn...@webkit.org>
+
+        Changes to slot children should trigger slotchange
+        https://bugs.webkit.org/show_bug.cgi?id=169718
+        <rdar://problem/43317496>
+
+        Reviewed by Darin Adler.
+
+        Rebaselined the test now that relevant test cases pass.
+
+        * web-platform-tests/shadow-dom/slotchange-expected.txt:
+
 2018-08-28  Aditya Keerthi  <akeer...@apple.com>
 
         [iOS] Support inputmode=none

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/slotchange-expected.txt (235457 => 235458)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/slotchange-expected.txt	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/slotchange-expected.txt	2018-08-29 05:31:57 UTC (rev 235458)
@@ -10,8 +10,8 @@
 TIMEOUT slotchange event: Change slot's name= attribute so that a node is assigned to the slot. Test timed out
 PASS slotchange event: Add a fallback content. 
 PASS slotchange event: Remove a fallback content. 
-TIMEOUT slotchange event: Add a fallback content to nested slots. Test timed out
-TIMEOUT slotchange event: Remove a fallback content from nested slots. Test timed out
+PASS slotchange event: Add a fallback content to nested slots. 
+PASS slotchange event: Remove a fallback content from nested slots. 
 TIMEOUT slotchange event: Insert a slot before an existing slot. Test timed out
 TIMEOUT slotchange event: Remove a preceding slot. Test timed out
 PASS slotchange event: A slot is assigned to another slot. 

Modified: trunk/Source/WebCore/ChangeLog (235457 => 235458)


--- trunk/Source/WebCore/ChangeLog	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/ChangeLog	2018-08-29 05:31:57 UTC (rev 235458)
@@ -1,3 +1,39 @@
+2018-08-28  Ryosuke Niwa  <rn...@webkit.org>
+
+        Changes to slot children should trigger slotchange
+        https://bugs.webkit.org/show_bug.cgi?id=169718
+        <rdar://problem/43317496>
+
+        Reviewed by Darin Adler.
+
+        Fix the bug that slotchange event is not fired when a slot's fallback content is updated now that slotchange event
+        is more formally specified.
+
+        This particular behavior corresponds to step 7.5. of the concept *to insert a node* where it says:
+        "[I]f parent’s root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run signal
+        a slot change for parent."
+
+        See https://dom.spec.whatwg.org/#concept-node-insert
+
+        Tests: fast/shadow-dom/slotchange-in-fallback.html
+               imported/w3c/web-platform-tests/shadow-dom/slotchange.html 
+
+        * dom/Element.cpp:
+        (WebCore::Element::childrenChanged): Updated the comment.
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::addSlotElementByName): Added an assertion.
+        (WebCore::ShadowRoot::slotFallbackDidChange): Added.
+        * dom/ShadowRoot.h:
+        * dom/SlotAssignment.cpp:
+        (WebCore::SlotAssignment::slotFallbackDidChange): Added. When the assigned nodes is empty, we enqueue a slotchange.
+        Because assignedNodesForSlot invokes assignSlots, this can be O(n) but we don't expect mutating slot's fallback
+        contents and shadow host's children in turn to be a common scenario so this shouldn't be an issue in practice.
+        * dom/SlotAssignment.h:
+        * html/HTMLSlotElement.cpp:
+        (WebCore::HTMLSlotElement::insertedIntoAncestor): Be explicit about auto* being used here.
+        (WebCore::HTMLSlotElement::childrenChanged): Added. Invokes slotFallbackDidChange whenver child node is muated.
+        * html/HTMLSlotElement.h:
+
 2018-08-28  Don Olmstead  <don.olmst...@sony.com>
 
         Check for null renderer in canBeScrolledIntoView

Modified: trunk/Source/WebCore/dom/Element.cpp (235457 => 235458)


--- trunk/Source/WebCore/dom/Element.cpp	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/dom/Element.cpp	2018-08-29 05:31:57 UTC (rev 235458)
@@ -2178,7 +2178,7 @@
         switch (change.type) {
         case ElementInserted:
         case ElementRemoved:
-            // For elements, we notify shadowRoot in Element::insertedInto and Element::removedFrom.
+            // For elements, we notify shadowRoot in Element::insertedIntoAncestor and Element::removedFromAncestor.
             break;
         case AllChildrenRemoved:
         case AllChildrenReplaced:

Modified: trunk/Source/WebCore/dom/ShadowRoot.cpp (235457 => 235458)


--- trunk/Source/WebCore/dom/ShadowRoot.cpp	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/dom/ShadowRoot.cpp	2018-08-29 05:31:57 UTC (rev 235458)
@@ -183,6 +183,7 @@
 
 void ShadowRoot::addSlotElementByName(const AtomicString& name, HTMLSlotElement& slot)
 {
+    ASSERT(&slot.rootNode() == this);
     if (!m_slotAssignment)
         m_slotAssignment = std::make_unique<SlotAssignment>();
 
@@ -194,6 +195,12 @@
     return m_slotAssignment->removeSlotElementByName(name, slot, *this);
 }
 
+void ShadowRoot::slotFallbackDidChange(HTMLSlotElement& slot)
+{
+    ASSERT(&slot.rootNode() == this);
+    return m_slotAssignment->slotFallbackDidChange(slot, *this);
+}
+
 const Vector<Node*>* ShadowRoot::assignedNodesForSlot(const HTMLSlotElement& slot)
 {
     if (!m_slotAssignment)

Modified: trunk/Source/WebCore/dom/ShadowRoot.h (235457 => 235458)


--- trunk/Source/WebCore/dom/ShadowRoot.h	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/dom/ShadowRoot.h	2018-08-29 05:31:57 UTC (rev 235458)
@@ -74,6 +74,7 @@
 
     void addSlotElementByName(const AtomicString&, HTMLSlotElement&);
     void removeSlotElementByName(const AtomicString&, HTMLSlotElement&);
+    void slotFallbackDidChange(HTMLSlotElement&);
 
     void didRemoveAllChildrenOfShadowHost();
     void didChangeDefaultSlot();
@@ -107,7 +108,6 @@
     Element* m_host { nullptr };
 
     std::unique_ptr<Style::Scope> m_styleScope;
-
     std::unique_ptr<SlotAssignment> m_slotAssignment;
 };
 

Modified: trunk/Source/WebCore/dom/SlotAssignment.cpp (235457 => 235458)


--- trunk/Source/WebCore/dom/SlotAssignment.cpp	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/dom/SlotAssignment.cpp	2018-08-29 05:31:57 UTC (rev 235458)
@@ -123,6 +123,16 @@
     ASSERT(slotInfo.element || m_needsToResolveSlotElements);
 }
 
+void SlotAssignment::slotFallbackDidChange(HTMLSlotElement& slotElement, ShadowRoot& shadowRoot)
+{
+    if (shadowRoot.mode() == ShadowRootMode::UserAgent)
+        return;
+
+    bool usesFallbackContent = !assignedNodesForSlot(slotElement, shadowRoot);
+    if (usesFallbackContent)
+        slotElement.enqueueSlotChangeEvent();
+}
+
 void SlotAssignment::didChangeSlot(const AtomicString& slotAttrValue, ShadowRoot& shadowRoot)
 {
     auto& slotName = slotNameFromAttributeValue(slotAttrValue);

Modified: trunk/Source/WebCore/dom/SlotAssignment.h (235457 => 235458)


--- trunk/Source/WebCore/dom/SlotAssignment.h	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/dom/SlotAssignment.h	2018-08-29 05:31:57 UTC (rev 235458)
@@ -51,6 +51,7 @@
 
     void addSlotElementByName(const AtomicString&, HTMLSlotElement&, ShadowRoot&);
     void removeSlotElementByName(const AtomicString&, HTMLSlotElement&, ShadowRoot&);
+    void slotFallbackDidChange(HTMLSlotElement&, ShadowRoot&);
 
     void didChangeSlot(const AtomicString&, ShadowRoot&);
     void enqueueSlotChangeEvent(const AtomicString&, ShadowRoot&);

Modified: trunk/Source/WebCore/html/HTMLSlotElement.cpp (235457 => 235458)


--- trunk/Source/WebCore/html/HTMLSlotElement.cpp	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/html/HTMLSlotElement.cpp	2018-08-29 05:31:57 UTC (rev 235458)
@@ -57,7 +57,7 @@
     ASSERT_UNUSED(insertionResult, insertionResult == InsertedIntoAncestorResult::Done);
 
     if (insertionType.treeScopeChanged && isInShadowTree()) {
-        if (auto shadowRoot = containingShadowRoot())
+        if (auto* shadowRoot = containingShadowRoot())
             shadowRoot->addSlotElementByName(attributeWithoutSynchronization(nameAttr), *this);
     }
 
@@ -75,6 +75,16 @@
     HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
 }
 
+void HTMLSlotElement::childrenChanged(const ChildChange& childChange)
+{
+    HTMLElement::childrenChanged(childChange);
+
+    if (isInShadowTree()) {
+        if (auto* shadowRoot = containingShadowRoot())
+            shadowRoot->slotFallbackDidChange(*this);
+    }
+}
+
 void HTMLSlotElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
 {
     HTMLElement::attributeChanged(name, oldValue, newValue, reason);

Modified: trunk/Source/WebCore/html/HTMLSlotElement.h (235457 => 235458)


--- trunk/Source/WebCore/html/HTMLSlotElement.h	2018-08-29 05:05:23 UTC (rev 235457)
+++ trunk/Source/WebCore/html/HTMLSlotElement.h	2018-08-29 05:31:57 UTC (rev 235458)
@@ -51,6 +51,7 @@
 
     InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
     void removedFromAncestor(RemovalType, ContainerNode&) final;
+    void childrenChanged(const ChildChange&) final;
     void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) final;
 
     bool m_inSignalSlotList { false };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to