Updating class name of a shadow host does not update the style applied by :host()
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Jun 2016 08:52:10 +0000 (08:52 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Jun 2016 08:52:10 +0000 (08:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158900
<rdar://problem/26883707>

Reviewed by Simon Fraser.

Source/WebCore:

Test: fast/shadow-dom/shadow-host-style-update.html

Teach style invalidation optimization code about :host.

* style/AttributeChangeInvalidation.cpp:
(WebCore::Style::mayBeAffectedByHostStyle):
(WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
* style/ClassChangeInvalidation.cpp:
(WebCore::Style::computeClassChange):
(WebCore::Style::mayBeAffectedByHostStyle):
(WebCore::Style::ClassChangeInvalidation::invalidateStyle):
* style/IdChangeInvalidation.cpp:
(WebCore::Style::mayBeAffectedByHostStyle):
(WebCore::Style::IdChangeInvalidation::invalidateStyle):

LayoutTests:

* fast/shadow-dom/shadow-host-style-update-expected.html: Added.
* fast/shadow-dom/shadow-host-style-update.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@202227 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/shadow-dom/shadow-host-style-update-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/shadow-host-style-update.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/style/AttributeChangeInvalidation.cpp
Source/WebCore/style/ClassChangeInvalidation.cpp
Source/WebCore/style/IdChangeInvalidation.cpp

index 17a2000..8896663 100644 (file)
@@ -1,3 +1,14 @@
+2016-06-19  Antti Koivisto  <antti@apple.com>
+
+        Updating class name of a shadow host does not update the style applied by :host()
+        https://bugs.webkit.org/show_bug.cgi?id=158900
+        <rdar://problem/26883707>
+
+        Reviewed by Simon Fraser.
+
+        * fast/shadow-dom/shadow-host-style-update-expected.html: Added.
+        * fast/shadow-dom/shadow-host-style-update.html: Added.
+
 2016-06-19  Alexey Proskuryakov  <ap@apple.com>
 
         Test expectation gardening.
diff --git a/LayoutTests/fast/shadow-dom/shadow-host-style-update-expected.html b/LayoutTests/fast/shadow-dom/shadow-host-style-update-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -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>
diff --git a/LayoutTests/fast/shadow-dom/shadow-host-style-update.html b/LayoutTests/fast/shadow-dom/shadow-host-style-update.html
new file mode 100644 (file)
index 0000000..7ea5bae
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.test {
+    width: 100px;
+    height: 25px;
+    background: red;
+}
+</style>
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p> 
+<div id="host1" class="test"></div>
+<div id="host2" class="test"></div>
+<div id="host3" class="test"></div>
+<div id="host4" class="test" attr="red"></div>
+<script>
+
+var host1 = document.getElementById('host1');
+host1.attachShadow({mode: 'closed'}).innerHTML = `
+    <style>
+    :host(.green) {
+        background: green !important;
+    }
+    </style>
+`;
+
+getComputedStyle(host1).backgroundColor;
+host1.classList.toggle('green');
+
+var host2 = document.getElementById('host2');
+host2.attachShadow({mode: 'closed'}).innerHTML = `
+    <style>
+    :host(#greenID) {
+        background: green !important;
+    }
+    </style>
+`;
+
+getComputedStyle(host2).backgroundColor;
+host2.id = 'greenID';
+
+var host3 = document.getElementById('host3');
+host3.attachShadow({mode: 'closed'}).innerHTML = `
+    <style>
+    :host([greenAttr]) {
+        background: green !important;
+    }
+    </style>
+`;
+
+getComputedStyle(host3).backgroundColor;
+host3.setAttribute('greenAttr', '');
+
+var host4 = document.getElementById('host4');
+host4.attachShadow({mode: 'closed'}).innerHTML = `
+    <style>
+    :host([attr=green]) {
+        background: green !important;
+    }
+    </style>
+`;
+
+getComputedStyle(host4).backgroundColor;
+host4.setAttribute('attr', 'green');
+
+</script>
+</body>
+</html>
index 6617781..142a643 100644 (file)
@@ -1,3 +1,26 @@
+2016-06-19  Antti Koivisto  <antti@apple.com>
+
+        Updating class name of a shadow host does not update the style applied by :host()
+        https://bugs.webkit.org/show_bug.cgi?id=158900
+        <rdar://problem/26883707>
+
+        Reviewed by Simon Fraser.
+
+        Test: fast/shadow-dom/shadow-host-style-update.html
+
+        Teach style invalidation optimization code about :host.
+
+        * style/AttributeChangeInvalidation.cpp:
+        (WebCore::Style::mayBeAffectedByHostStyle):
+        (WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
+        * style/ClassChangeInvalidation.cpp:
+        (WebCore::Style::computeClassChange):
+        (WebCore::Style::mayBeAffectedByHostStyle):
+        (WebCore::Style::ClassChangeInvalidation::invalidateStyle):
+        * style/IdChangeInvalidation.cpp:
+        (WebCore::Style::mayBeAffectedByHostStyle):
+        (WebCore::Style::IdChangeInvalidation::invalidateStyle):
+
 2016-06-19  Gavin & Ellie Barraclough  <barraclough@apple.com>
 
         Remove hasStaticPropertyTable (part 5: done!)
index 3479ab6..2a7ea03 100644 (file)
 
 #include "DocumentRuleSets.h"
 #include "ElementIterator.h"
+#include "ShadowRoot.h"
 #include "StyleInvalidationAnalysis.h"
 #include "StyleResolver.h"
 
 namespace WebCore {
 namespace Style {
 
+static bool mayBeAffectedByHostStyle(ShadowRoot& shadowRoot, bool isHTML, const QualifiedName& attributeName)
+{
+    auto& shadowRuleSets = shadowRoot.styleResolver().ruleSets();
+    if (shadowRuleSets.authorStyle()->hostPseudoClassRules().isEmpty())
+        return false;
+
+    auto& nameSet = isHTML ? shadowRuleSets.features().attributeCanonicalLocalNamesInRules : shadowRuleSets.features().attributeLocalNamesInRules;
+    return nameSet.contains(attributeName.localName().impl());
+}
+
 void AttributeChangeInvalidation::invalidateStyle(const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
 {
     if (newValue == oldValue)
@@ -43,8 +54,13 @@ void AttributeChangeInvalidation::invalidateStyle(const QualifiedName& attribute
     bool isHTML = m_element.isHTMLElement();
 
     auto& nameSet = isHTML ? ruleSets.features().attributeCanonicalLocalNamesInRules : ruleSets.features().attributeLocalNamesInRules;
-    bool shouldInvalidate = nameSet.contains(attributeName.localName().impl());
-    if (!shouldInvalidate)
+    bool mayAffectStyle = nameSet.contains(attributeName.localName().impl());
+
+    auto* shadowRoot = m_element.shadowRoot();
+    if (!mayAffectStyle && shadowRoot && mayBeAffectedByHostStyle(*shadowRoot, isHTML, attributeName))
+        mayAffectStyle = true;
+
+    if (!mayAffectStyle)
         return;
 
     if (!isHTML) {
index 1830a0f..48c5b18 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "DocumentRuleSets.h"
 #include "ElementChildIterator.h"
+#include "ShadowRoot.h"
 #include "SpaceSplitString.h"
 #include "StyleInvalidationAnalysis.h"
 #include "StyleResolver.h"
@@ -84,22 +85,36 @@ static ClassChangeVector computeClassChange(const SpaceSplitString& oldClasses,
     return changedClasses;
 }
 
+static bool mayBeAffectedByHostStyle(ShadowRoot& shadowRoot, AtomicStringImpl* changedClass)
+{
+    auto& shadowRuleSets = shadowRoot.styleResolver().ruleSets();
+    if (shadowRuleSets.authorStyle()->hostPseudoClassRules().isEmpty())
+        return false;
+    return shadowRuleSets.features().classesInRules.contains(changedClass);
+}
+
 void ClassChangeInvalidation::invalidateStyle(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
 {
     auto changedClasses = computeClassChange(oldClasses, newClasses);
 
     auto& ruleSets = m_element.styleResolver().ruleSets();
+    auto* shadowRoot = m_element.shadowRoot();
 
     ClassChangeVector changedClassesAffectingStyle;
     for (auto* changedClass : changedClasses) {
-        if (ruleSets.features().classesInRules.contains(changedClass))
+        bool mayAffectStyle = ruleSets.features().classesInRules.contains(changedClass);
+
+        if (!mayAffectStyle && shadowRoot && mayBeAffectedByHostStyle(*shadowRoot, changedClass))
+            mayAffectStyle = true;
+
+        if (mayAffectStyle)
             changedClassesAffectingStyle.append(changedClass);
     };
 
     if (changedClassesAffectingStyle.isEmpty())
         return;
 
-    if (m_element.shadowRoot() && ruleSets.authorStyle()->hasShadowPseudoElementRules()) {
+    if (shadowRoot && ruleSets.authorStyle()->hasShadowPseudoElementRules()) {
         m_element.setNeedsStyleRecalc(FullStyleChange);
         return;
     }
index 6ae98dd..b2d4ce4 100644 (file)
 
 #include "DocumentRuleSets.h"
 #include "ElementChildIterator.h"
+#include "ShadowRoot.h"
 #include "StyleResolver.h"
 
 namespace WebCore {
 namespace Style {
 
+static bool mayBeAffectedByHostStyle(ShadowRoot& shadowRoot, const AtomicString& changedId)
+{
+    auto& shadowRuleSets = shadowRoot.styleResolver().ruleSets();
+    if (shadowRuleSets.authorStyle()->hostPseudoClassRules().isEmpty())
+        return false;
+
+    return shadowRuleSets.features().idsInRules.contains(changedId.impl());
+}
+
 void IdChangeInvalidation::invalidateStyle(const AtomicString& changedId)
 {
     if (changedId.isEmpty())
@@ -41,6 +51,11 @@ void IdChangeInvalidation::invalidateStyle(const AtomicString& changedId)
     auto& ruleSets = m_element.styleResolver().ruleSets();
 
     bool mayAffectStyle = ruleSets.features().idsInRules.contains(changedId.impl());
+
+    auto* shadowRoot = m_element.shadowRoot();
+    if (!mayAffectStyle && shadowRoot && mayBeAffectedByHostStyle(*shadowRoot, changedId))
+        mayAffectStyle = true;
+
     if (!mayAffectStyle)
         return;