Mutating styleSheet in shadow tree doesn't update the style
https://bugs.webkit.org/show_bug.cgi?id=162744
<rdar://problem/28550588>

Reviewed by Ryosuke Niwa.

Source/WebCore:

We weren't always invalidating the right AuthorStyleSheets (to be renamed) instance
for the scope after mutations.

Test: fast/shadow-dom/mutating-stylesheet-in-shadow-tree.html

* css/CSSStyleSheet.cpp:
(WebCore::CSSStyleSheet::didMutateRules):
(WebCore::CSSStyleSheet::didMutate):
(WebCore::CSSStyleSheet::clearOwnerNode):
(WebCore::CSSStyleSheet::rootStyleSheet):
(WebCore::CSSStyleSheet::ownerDocument):
(WebCore::CSSStyleSheet::styleSheetScope):

    Invalidate the right scope after stylesheet mutations.

* css/CSSStyleSheet.h:
* dom/AuthorStyleSheets.cpp:
(WebCore::AuthorStyleSheets::styleResolver):
(WebCore::AuthorStyleSheets::styleResolverIfExists):

    Take care to update the right style resolver.

(WebCore::AuthorStyleSheets::forNode):
(WebCore::AuthorStyleSheets::removeStyleSheetCandidateNode):

    Start the update timer so clients don't need to request update separately.

(WebCore::AuthorStyleSheets::analyzeStyleSheetChange):
(WebCore::AuthorStyleSheets::updateActiveStyleSheets):
(WebCore::AuthorStyleSheets::updateStyleResolver):
* dom/AuthorStyleSheets.h:
* dom/InlineStyleSheetOwner.cpp:
(WebCore::InlineStyleSheetOwner::insertedIntoDocument):

    Save the scope we were inserted into so removals can be done reliably.

(WebCore::InlineStyleSheetOwner::removedFromDocument):

    Use and clear the saved scope.
    Remove didChangeCandidatesForActiveSet() as it is now done by removeStyleSheetCandidateNode() call.

(WebCore::InlineStyleSheetOwner::clearDocumentData):
(WebCore::InlineStyleSheetOwner::createSheet):
(WebCore::InlineStyleSheetOwner::sheetLoaded):
(WebCore::InlineStyleSheetOwner::startLoadingDynamicSheet):
(WebCore::authorStyleSheetsForElement): Deleted.
* dom/InlineStyleSheetOwner.h:
(WebCore::InlineStyleSheetOwner::styleSheetScope):
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::styleResolverIfExists):
* dom/ShadowRoot.h:
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::removedFrom):

    Remove didChangeCandidatesForActiveSet() as it is now done by removeStyleSheetCandidateNode() call.

* html/HTMLStyleElement.cpp:
(WebCore::HTMLStyleElement::~HTMLStyleElement):
(WebCore::HTMLStyleElement::parseAttribute):

    Fix a bug where we wouldn't create stylesheet if a style element was activated by removing a media attribute.

(WebCore::HTMLStyleElement::insertedInto):
(WebCore::HTMLStyleElement::removedFrom):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::getMatchedCSSRules):
* svg/SVGStyleElement.cpp:
(WebCore::SVGStyleElement::~SVGStyleElement):
(WebCore::SVGStyleElement::insertedInto):
(WebCore::SVGStyleElement::removedFrom):

LayoutTests:

* fast/shadow-dom/mutating-stylesheet-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/mutating-stylesheet-in-shadow-tree.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@206880 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/dom/AuthorStyleSheets.cpp b/Source/WebCore/dom/AuthorStyleSheets.cpp
index cbd0bed..8743b6f 100644
--- a/Source/WebCore/dom/AuthorStyleSheets.cpp
+++ b/Source/WebCore/dom/AuthorStyleSheets.cpp
@@ -69,6 +69,31 @@
 {
 }
 
+StyleResolver& AuthorStyleSheets::styleResolver()
+{
+    if (m_shadowRoot)
+        return m_shadowRoot->styleResolver();
+
+    return m_document.ensureStyleResolver();
+}
+
+StyleResolver* AuthorStyleSheets::styleResolverIfExists()
+{
+    if (m_shadowRoot)
+        return m_shadowRoot->styleResolverIfExists();
+
+    return m_document.styleResolverIfExists();
+}
+
+AuthorStyleSheets& AuthorStyleSheets::forNode(Node& node)
+{
+    ASSERT(node.inDocument());
+    auto* shadowRoot = node.containingShadowRoot();
+    if (shadowRoot)
+        return shadowRoot->authorStyleSheets();
+    return node.document().authorStyleSheets();
+}
+
 // This method is called whenever a top-level stylesheet has finished loading.
 void AuthorStyleSheets::removePendingSheet(RemovePendingSheetNotificationType notification)
 {
@@ -133,7 +158,8 @@
 
 void AuthorStyleSheets::removeStyleSheetCandidateNode(Node& node)
 {
-    m_styleSheetCandidateNodes.remove(&node);
+    if (m_styleSheetCandidateNodes.remove(&node))
+        scheduleActiveSetUpdate();
 }
 
 void AuthorStyleSheets::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets)
@@ -220,10 +246,10 @@
     
     unsigned newStylesheetCount = newStylesheets.size();
 
-    if (!m_document.styleResolverIfExists())
+    if (!styleResolverIfExists())
         return Reconstruct;
 
-    StyleResolver& styleResolver = *m_document.styleResolverIfExists();
+    StyleResolver& styleResolver = *styleResolverIfExists();
 
     // Find out which stylesheets are new.
     unsigned oldStylesheetCount = m_activeStyleSheets.size();
@@ -306,6 +332,10 @@
         return;
     }
 
+    // FIXME: Support optimized invalidation in shadow trees.
+    if (m_shadowRoot)
+        updateType = UpdateType::ContentsOrInterpretation;
+
     m_didUpdateActiveStyleSheets = true;
 
     Vector<RefPtr<StyleSheet>> activeStyleSheets;
@@ -352,8 +382,7 @@
             m_document.clearStyleResolver();
         return;
     }
-    auto& styleResolver = m_document.ensureStyleResolver();
-    auto& userAgentShadowTreeStyleResolver = m_document.userAgentShadowTreeStyleResolver();
+    auto& styleResolver = this->styleResolver();
 
     if (updateType == Reset) {
         styleResolver.ruleSets().resetAuthorStyle();
@@ -366,10 +395,13 @@
         styleResolver.appendAuthorStyleSheets(newStyleSheets);
     }
 
-    userAgentShadowTreeStyleResolver.ruleSets().resetAuthorStyle();
-    auto& authorRuleSet = styleResolver.ruleSets().authorStyle();
-    if (authorRuleSet.hasShadowPseudoElementRules())
-        userAgentShadowTreeStyleResolver.ruleSets().authorStyle().copyShadowPseudoElementRulesFrom(authorRuleSet);
+    if (!m_shadowRoot) {
+        auto& userAgentShadowTreeStyleResolver = m_document.userAgentShadowTreeStyleResolver();
+        userAgentShadowTreeStyleResolver.ruleSets().resetAuthorStyle();
+        auto& authorRuleSet = styleResolver.ruleSets().authorStyle();
+        if (authorRuleSet.hasShadowPseudoElementRules())
+            userAgentShadowTreeStyleResolver.ruleSets().authorStyle().copyShadowPseudoElementRulesFrom(authorRuleSet);
+    }
 }
 
 const Vector<RefPtr<CSSStyleSheet>> AuthorStyleSheets::activeStyleSheetsForInspector() const
@@ -422,6 +454,11 @@
 
 void AuthorStyleSheets::scheduleActiveSetUpdate()
 {
+    if (m_shadowRoot) {
+        // FIXME: We need to flush updates recursively to support asynchronous updates in shadow trees.
+        didChangeCandidatesForActiveSet();
+        return;
+    }
     if (m_pendingUpdateTimer.isActive())
         return;
     if (!m_pendingUpdateType)