Title: [208616] trunk
Revision
208616
Author
an...@apple.com
Date
2016-11-11 15:08:34 -0800 (Fri, 11 Nov 2016)

Log Message

Updating class name doesn't update the slotted content's style
https://bugs.webkit.org/show_bug.cgi?id=164577
<rdar://problem/29205873>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Test: fast/shadow-dom/css-scoping-slotted-invalidation.html

Teach style invalidation code for attribute/class/id mutations about slotted rules.

* dom/ShadowRoot.cpp:
(WebCore::assignedShadowRootsIfSlotted):

    Helper to find all assigned shadow roots (there may be more than one if slots are assigned to slots).

* dom/ShadowRoot.h:
* style/AttributeChangeInvalidation.cpp:
(WebCore::Style::mayBeAffectedByAttributeChange):
(WebCore::Style::mayBeAffectedByHostRules):
(WebCore::Style::mayBeAffectedBySlottedRules):
(WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
(WebCore::Style::mayBeAffectedByHostStyle): Deleted.
* style/ClassChangeInvalidation.cpp:
(WebCore::Style::mayBeAffectedByHostRules):
(WebCore::Style::mayBeAffectedBySlottedRules):
(WebCore::Style::ClassChangeInvalidation::invalidateStyle):
(WebCore::Style::mayBeAffectedByHostStyle): Deleted.
* style/ClassChangeInvalidation.h:
* style/IdChangeInvalidation.cpp:
(WebCore::Style::mayBeAffectedByHostRules):
(WebCore::Style::mayBeAffectedBySlottedRules):
(WebCore::Style::IdChangeInvalidation::invalidateStyle):
(WebCore::Style::mayBeAffectedByHostStyle): Deleted.
* style/StyleSharingResolver.cpp:
(WebCore::Style::SharingResolver::canShareStyleWithElement):

    Fix a bug in style sharing where we were checking wrong element for host rules.
    Tested by the included test too (the last empty div).

LayoutTests:

* fast/shadow-dom/css-scoping-slotted-invalidation-expected.html: Added.
* fast/shadow-dom/css-scoping-slotted-invalidation.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (208615 => 208616)


--- trunk/LayoutTests/ChangeLog	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/LayoutTests/ChangeLog	2016-11-11 23:08:34 UTC (rev 208616)
@@ -1,3 +1,14 @@
+2016-11-11  Antti Koivisto  <an...@apple.com>
+
+        Updating class name doesn't update the slotted content's style
+        https://bugs.webkit.org/show_bug.cgi?id=164577
+        <rdar://problem/29205873>
+
+        Reviewed by Ryosuke Niwa.
+
+        * fast/shadow-dom/css-scoping-slotted-invalidation-expected.html: Added.
+        * fast/shadow-dom/css-scoping-slotted-invalidation.html: Added.
+
 2016-11-11  Chris Dumez  <cdu...@apple.com>
 
         WorkerGlobalScope's indexedDB property should be on the prototype, not the instance

Added: trunk/LayoutTests/fast/shadow-dom/css-scoping-slotted-invalidation-expected.html (0 => 208616)


--- trunk/LayoutTests/fast/shadow-dom/css-scoping-slotted-invalidation-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/css-scoping-slotted-invalidation-expected.html	2016-11-11 23:08:34 UTC (rev 208616)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+    <body>
+        <p>Test passes if you see a single 100px by 100px green box below.</p>
+        <div style="width: 100px; height: 100px; background: green;"></div>
+    </body>
+</html>

Added: trunk/LayoutTests/fast/shadow-dom/css-scoping-slotted-invalidation.html (0 => 208616)


--- trunk/LayoutTests/fast/shadow-dom/css-scoping-slotted-invalidation.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/css-scoping-slotted-invalidation.html	2016-11-11 23:08:34 UTC (rev 208616)
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="t1">
+    <span>FAIL</span>
+</div>
+<div id="t2">
+    <span slot="second-slot">FAIL</span>
+</div>
+<div id="t3">
+    <span>FAIL</span>
+</div>
+<div id="t4">
+    <span>FAIL</span>
+</div>
+<div id="t5">
+    <span selected>FAIL</span>
+</div>
+<div>
+</div>
+<script>
+
+function attachShadow(host, selector)
+{
+    const shadow = host.attachShadow({mode: 'closed'});
+    shadow.innerHTML = `
+    <style>
+    :host {
+        width: 100px;
+        height: 20px;
+        background: green;
+        color: red;
+    }
+    ${selector} {
+        color: green;
+    }
+    </style>
+    <slot></slot>
+    <slot name="second-slot"></slot>`;
+    return shadow;
+}
+
+{
+    const host = document.querySelector('#t1');
+    attachShadow(host, '::slotted(.selected)');
+    const span = host.querySelector('span');
+    getComputedStyle(span).backgroundColor;
+    span.className = 'selected';
+}
+
+{
+    const host = document.querySelector('#t2');
+    attachShadow(host, '[name=second-slot]::slotted(#selected)');
+    const span = host.querySelector('span');
+    getComputedStyle(span).backgroundColor
+    span.id = 'selected';
+}
+
+{
+    const host = document.querySelector('#t3');
+    attachShadow(host, '::slotted([selected])');
+    const span = host.querySelector('span');
+    getComputedStyle(span).backgroundColor;
+    span.setAttribute('selected', 'selected');
+}
+
+{
+    const host = document.querySelector('#t4');
+    const shadow = host.attachShadow({mode: 'closed'});
+    shadow.innerHTML = `<div><slot></slot></div>`;
+    const deepHost = shadow.querySelector('div');
+    attachShadow(deepHost, '::slotted(.selected)');
+    const span = host.querySelector('span');
+    getComputedStyle(span).backgroundColor;
+    span.className = 'selected';
+}
+
+{
+    const host = document.querySelector('#t5');
+    const shadow = host.attachShadow({mode: 'closed'});
+    shadow.innerHTML = `<div><slot slot="second-slot"></slot></div>`;
+    const deepHost = shadow.querySelector('div');
+    attachShadow(deepHost, '[name=second-slot]::slotted(:not([selected]))');
+    const span = host.querySelector('span');
+    getComputedStyle(span).backgroundColor;
+    span.removeAttribute('selected');
+}
+
+</script>

Modified: trunk/Source/WebCore/ChangeLog (208615 => 208616)


--- trunk/Source/WebCore/ChangeLog	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/ChangeLog	2016-11-11 23:08:34 UTC (rev 208616)
@@ -1,3 +1,44 @@
+2016-11-11  Antti Koivisto  <an...@apple.com>
+
+        Updating class name doesn't update the slotted content's style
+        https://bugs.webkit.org/show_bug.cgi?id=164577
+        <rdar://problem/29205873>
+
+        Reviewed by Ryosuke Niwa.
+
+        Test: fast/shadow-dom/css-scoping-slotted-invalidation.html
+
+        Teach style invalidation code for attribute/class/id mutations about slotted rules.
+
+        * dom/ShadowRoot.cpp:
+        (WebCore::assignedShadowRootsIfSlotted):
+
+            Helper to find all assigned shadow roots (there may be more than one if slots are assigned to slots).
+
+        * dom/ShadowRoot.h:
+        * style/AttributeChangeInvalidation.cpp:
+        (WebCore::Style::mayBeAffectedByAttributeChange):
+        (WebCore::Style::mayBeAffectedByHostRules):
+        (WebCore::Style::mayBeAffectedBySlottedRules):
+        (WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
+        (WebCore::Style::mayBeAffectedByHostStyle): Deleted.
+        * style/ClassChangeInvalidation.cpp:
+        (WebCore::Style::mayBeAffectedByHostRules):
+        (WebCore::Style::mayBeAffectedBySlottedRules):
+        (WebCore::Style::ClassChangeInvalidation::invalidateStyle):
+        (WebCore::Style::mayBeAffectedByHostStyle): Deleted.
+        * style/ClassChangeInvalidation.h:
+        * style/IdChangeInvalidation.cpp:
+        (WebCore::Style::mayBeAffectedByHostRules):
+        (WebCore::Style::mayBeAffectedBySlottedRules):
+        (WebCore::Style::IdChangeInvalidation::invalidateStyle):
+        (WebCore::Style::mayBeAffectedByHostStyle): Deleted.
+        * style/StyleSharingResolver.cpp:
+        (WebCore::Style::SharingResolver::canShareStyleWithElement):
+
+            Fix a bug in style sharing where we were checking wrong element for host rules.
+            Tested by the included test too (the last empty div).
+
 2016-11-11  Dave Hyatt  <hy...@apple.com>
 
         [CSS Parser] Support the spring animation timing function

Modified: trunk/Source/WebCore/dom/ShadowRoot.cpp (208615 => 208616)


--- trunk/Source/WebCore/dom/ShadowRoot.cpp	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/dom/ShadowRoot.cpp	2016-11-11 23:08:34 UTC (rev 208616)
@@ -31,6 +31,7 @@
 #include "CSSStyleSheet.h"
 #include "ElementTraversal.h"
 #include "ExceptionCode.h"
+#include "HTMLSlotElement.h"
 #include "RenderElement.h"
 #include "RuntimeEnabledFeatures.h"
 #include "SlotAssignment.h"
@@ -183,5 +184,14 @@
     return m_slotAssignment->assignedNodesForSlot(slot, *this);
 }
 
+Vector<ShadowRoot*> assignedShadowRootsIfSlotted(const Node& node)
+{
+    Vector<ShadowRoot*> result;
+    for (auto* slot = node.assignedSlot(); slot; slot = slot->assignedSlot()) {
+        ASSERT(slot->containingShadowRoot());
+        result.append(slot->containingShadowRoot());
+    }
+    return result;
+}
 
 }

Modified: trunk/Source/WebCore/dom/ShadowRoot.h (208615 => 208616)


--- trunk/Source/WebCore/dom/ShadowRoot.h	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/dom/ShadowRoot.h	2016-11-11 23:08:34 UTC (rev 208616)
@@ -133,6 +133,8 @@
     return node.parentNode() && node.parentNode()->isShadowRoot();
 }
 
+Vector<ShadowRoot*> assignedShadowRootsIfSlotted(const Node&);
+
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ShadowRoot)

Modified: trunk/Source/WebCore/style/AttributeChangeInvalidation.cpp (208615 => 208616)


--- trunk/Source/WebCore/style/AttributeChangeInvalidation.cpp	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/style/AttributeChangeInvalidation.cpp	2016-11-11 23:08:34 UTC (rev 208616)
@@ -36,16 +36,36 @@
 namespace WebCore {
 namespace Style {
 
-static bool mayBeAffectedByHostStyle(ShadowRoot& shadowRoot, bool isHTML, const QualifiedName& attributeName)
+static bool mayBeAffectedByAttributeChange(DocumentRuleSets& ruleSets, bool isHTML, const QualifiedName& attributeName)
 {
-    auto& shadowRuleSets = shadowRoot.styleScope().resolver().ruleSets();
+    auto& nameSet = isHTML ? ruleSets.features().attributeCanonicalLocalNamesInRules : ruleSets.features().attributeLocalNamesInRules;
+    return nameSet.contains(attributeName.localName().impl());
+}
+
+static bool mayBeAffectedByHostRules(const Element& element, const QualifiedName& attributeName)
+{
+    auto* shadowRoot = element.shadowRoot();
+    if (!shadowRoot)
+        return false;
+    auto& shadowRuleSets = shadowRoot->styleScope().resolver().ruleSets();
     if (shadowRuleSets.authorStyle().hostPseudoClassRules().isEmpty())
         return false;
 
-    auto& nameSet = isHTML ? shadowRuleSets.features().attributeCanonicalLocalNamesInRules : shadowRuleSets.features().attributeLocalNamesInRules;
-    return nameSet.contains(attributeName.localName().impl());
+    return mayBeAffectedByAttributeChange(shadowRuleSets, element.isHTMLElement(), attributeName);
 }
 
+static bool mayBeAffectedBySlottedRules(const Element& element, const QualifiedName& attributeName)
+{
+    for (auto* shadowRoot : assignedShadowRootsIfSlotted(element)) {
+        auto& ruleSets = shadowRoot->styleScope().resolver().ruleSets();
+        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
+            continue;
+        if (mayBeAffectedByAttributeChange(ruleSets, element.isHTMLElement(), attributeName))
+            return true;
+    }
+    return false;
+}
+
 void AttributeChangeInvalidation::invalidateStyle(const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
 {
     if (newValue == oldValue)
@@ -54,13 +74,10 @@
     auto& ruleSets = m_element.styleResolver().ruleSets();
     bool isHTML = m_element.isHTMLElement();
 
-    auto& nameSet = isHTML ? ruleSets.features().attributeCanonicalLocalNamesInRules : ruleSets.features().attributeLocalNamesInRules;
-    bool mayAffectStyle = nameSet.contains(attributeName.localName().impl());
+    bool mayAffectStyle = mayBeAffectedByAttributeChange(ruleSets, isHTML, attributeName)
+        || mayBeAffectedByHostRules(m_element, attributeName)
+        || mayBeAffectedBySlottedRules(m_element, attributeName);
 
-    auto* shadowRoot = m_element.shadowRoot();
-    if (!mayAffectStyle && shadowRoot && mayBeAffectedByHostStyle(*shadowRoot, isHTML, attributeName))
-        mayAffectStyle = true;
-
     if (!mayAffectStyle)
         return;
 

Modified: trunk/Source/WebCore/style/ClassChangeInvalidation.cpp (208615 => 208616)


--- trunk/Source/WebCore/style/ClassChangeInvalidation.cpp	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/style/ClassChangeInvalidation.cpp	2016-11-11 23:08:34 UTC (rev 208616)
@@ -86,14 +86,28 @@
     return changedClasses;
 }
 
-static bool mayBeAffectedByHostStyle(ShadowRoot& shadowRoot, AtomicStringImpl* changedClass)
+static bool mayBeAffectedByHostRules(ShadowRoot* shadowRoot, AtomicStringImpl* changedClass)
 {
-    auto& shadowRuleSets = shadowRoot.styleScope().resolver().ruleSets();
+    if (!shadowRoot)
+        return false;
+    auto& shadowRuleSets = shadowRoot->styleScope().resolver().ruleSets();
     if (shadowRuleSets.authorStyle().hostPseudoClassRules().isEmpty())
         return false;
     return shadowRuleSets.features().classesInRules.contains(changedClass);
 }
 
+static bool mayBeAffectedBySlottedRules(const Vector<ShadowRoot*>& assignedShadowRoots, AtomicStringImpl* changedClass)
+{
+    for (auto& assignedShadowRoot : assignedShadowRoots) {
+        auto& ruleSets = assignedShadowRoot->styleScope().resolver().ruleSets();
+        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
+            continue;
+        if (ruleSets.features().classesInRules.contains(changedClass))
+            return true;
+    }
+    return false;
+}
+
 void ClassChangeInvalidation::invalidateStyle(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
 {
     auto changedClasses = computeClassChange(oldClasses, newClasses);
@@ -100,14 +114,13 @@
 
     auto& ruleSets = m_element.styleResolver().ruleSets();
     auto* shadowRoot = m_element.shadowRoot();
+    auto assignedShadowRoots = assignedShadowRootsIfSlotted(m_element);
 
     ClassChangeVector changedClassesAffectingStyle;
     for (auto* changedClass : changedClasses) {
-        bool mayAffectStyle = ruleSets.features().classesInRules.contains(changedClass);
-
-        if (!mayAffectStyle && shadowRoot && mayBeAffectedByHostStyle(*shadowRoot, changedClass))
-            mayAffectStyle = true;
-
+        bool mayAffectStyle = ruleSets.features().classesInRules.contains(changedClass)
+            || mayBeAffectedByHostRules(shadowRoot, changedClass)
+            || mayBeAffectedBySlottedRules(assignedShadowRoots, changedClass);
         if (mayAffectStyle)
             changedClassesAffectingStyle.append(changedClass);
     };

Modified: trunk/Source/WebCore/style/ClassChangeInvalidation.h (208615 => 208616)


--- trunk/Source/WebCore/style/ClassChangeInvalidation.h	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/style/ClassChangeInvalidation.h	2016-11-11 23:08:34 UTC (rev 208616)
@@ -69,7 +69,7 @@
         return;
     invalidateDescendantStyle();
 }
-    
+
 }
 }
 

Modified: trunk/Source/WebCore/style/IdChangeInvalidation.cpp (208615 => 208616)


--- trunk/Source/WebCore/style/IdChangeInvalidation.cpp	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/style/IdChangeInvalidation.cpp	2016-11-11 23:08:34 UTC (rev 208616)
@@ -35,15 +35,29 @@
 namespace WebCore {
 namespace Style {
 
-static bool mayBeAffectedByHostStyle(ShadowRoot& shadowRoot, const AtomicString& changedId)
+static bool mayBeAffectedByHostRules(const Element& element, const AtomicString& changedId)
 {
-    auto& shadowRuleSets = shadowRoot.styleScope().resolver().ruleSets();
+    auto* shadowRoot = element.shadowRoot();
+    if (!shadowRoot)
+        return false;
+    auto& shadowRuleSets = shadowRoot->styleScope().resolver().ruleSets();
     if (shadowRuleSets.authorStyle().hostPseudoClassRules().isEmpty())
         return false;
-
     return shadowRuleSets.features().idsInRules.contains(changedId.impl());
 }
 
+static bool mayBeAffectedBySlottedRules(const Element& element, const AtomicString& changedId)
+{
+    for (auto* shadowRoot : assignedShadowRootsIfSlotted(element)) {
+        auto& ruleSets = shadowRoot->styleScope().resolver().ruleSets();
+        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
+            continue;
+        if (ruleSets.features().idsInRules.contains(changedId.impl()))
+            return true;
+    }
+    return false;
+}
+
 void IdChangeInvalidation::invalidateStyle(const AtomicString& changedId)
 {
     if (changedId.isEmpty())
@@ -51,12 +65,10 @@
 
     auto& ruleSets = m_element.styleResolver().ruleSets();
 
-    bool mayAffectStyle = ruleSets.features().idsInRules.contains(changedId.impl());
+    bool mayAffectStyle = ruleSets.features().idsInRules.contains(changedId.impl())
+        || mayBeAffectedByHostRules(m_element, changedId)
+        || mayBeAffectedBySlottedRules(m_element, changedId);
 
-    auto* shadowRoot = m_element.shadowRoot();
-    if (!mayAffectStyle && shadowRoot && mayBeAffectedByHostStyle(*shadowRoot, changedId))
-        mayAffectStyle = true;
-
     if (!mayAffectStyle)
         return;
 

Modified: trunk/Source/WebCore/style/StyleSharingResolver.cpp (208615 => 208616)


--- trunk/Source/WebCore/style/StyleSharingResolver.cpp	2016-11-11 23:04:55 UTC (rev 208615)
+++ trunk/Source/WebCore/style/StyleSharingResolver.cpp	2016-11-11 23:08:34 UTC (rev 208616)
@@ -288,7 +288,7 @@
     if (candidateElement.matchesDefaultPseudoClass() != element.matchesDefaultPseudoClass())
         return false;
 
-    if (element.shadowRoot() && !element.shadowRoot()->styleScope().resolver().ruleSets().authorStyle().hostPseudoClassRules().isEmpty())
+    if (candidateElement.shadowRoot() && !candidateElement.shadowRoot()->styleScope().resolver().ruleSets().authorStyle().hostPseudoClassRules().isEmpty())
         return false;
 
 #if ENABLE(FULLSCREEN_API)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to