Use separate style resolver for user agent shadow trees
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Sep 2015 15:39:15 +0000 (15:39 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Sep 2015 15:39:15 +0000 (15:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149626

Reviewed by Andreas Kling.

We now support separate style resolvers for shadow trees. Use this mechanism to have a separate
per-document style resolver for user agent shadow trees. This isolates user agent shadow trees
from author style better and simplifies the style resolver. It can also avoid some unnecessary style recalcs.

* css/DocumentRuleSets.cpp:
(WebCore::DocumentRuleSets::resetAuthorStyle):
(WebCore::DocumentRuleSets::appendAuthorStyleSheets):

    Change interface so that only the new rules are provided.

* css/DocumentRuleSets.h:
* css/ElementRuleCollector.cpp:
(WebCore::ElementRuleCollector::addElementStyleProperties):
(WebCore::ElementRuleCollector::collectMatchingRules):

    We can remove special bailout as shadow tree style resolver won't have other author style

(WebCore::ElementRuleCollector::sortAndTransferMatchedRules):

    Remove the exception that disables property whitelists for UA stylesheets. We don't seem to use the feature.

(WebCore::ElementRuleCollector::matchUARules):
(WebCore::MatchingUARulesScope::MatchingUARulesScope): Deleted.
(WebCore::MatchingUARulesScope::~MatchingUARulesScope): Deleted.
(WebCore::MatchingUARulesScope::isMatchingUARules): Deleted.

    Remove this unnecessary hack.

* css/ElementRuleCollector.h:
(WebCore::ElementRuleCollector::ElementRuleCollector):
* css/RuleSet.cpp:
(WebCore::RuleSet::addStyleRule):
(WebCore::RuleSet::copyShadowPseudoElementRulesFrom):

    Also copy WebVTT rules. They are currently a sort of mixture of UA and author shadow tree.

(WebCore::shrinkMapVectorsToFit):
* css/RuleSet.h:
(WebCore::RuleData::containsUncommonAttributeSelector):
(WebCore::RuleData::linkMatchType):
(WebCore::RuleData::hasDocumentSecurityOrigin):
(WebCore::RuleData::propertyWhitelistType):
(WebCore::RuleData::descendantSelectorIdentifierHashes):
(WebCore::RuleSet::ruleCount):
(WebCore::RuleSet::hasShadowPseudoElementRules):
* css/StyleInvalidationAnalysis.cpp:
(WebCore::StyleInvalidationAnalysis::StyleInvalidationAnalysis):
(WebCore::StyleInvalidationAnalysis::invalidateIfNeeded):

    Don't invalidate the whole tree when author shadow pseudo element rules change. Just invalidate the shadow trees.

(WebCore::StyleInvalidationAnalysis::invalidateStyleForTree):
(WebCore::StyleInvalidationAnalysis::invalidateStyle):
(WebCore::invalidateIfNeeded): Deleted.
(WebCore::invalidateStyleForTree): Deleted.
* css/StyleInvalidationAnalysis.h:
(WebCore::StyleInvalidationAnalysis::dirtiesAllStyle):
(WebCore::StyleInvalidationAnalysis::hasShadowPseudoElementRulesInAuthorSheet):
* css/StyleResolver.cpp:
(WebCore::StyleResolver::MatchResult::addMatchedProperties):
(WebCore::StyleResolver::StyleResolver):
(WebCore::StyleResolver::appendAuthorStyleSheets):

    Simpler interface.

* css/StyleResolver.h:
(WebCore::StyleResolver::document):
(WebCore::StyleResolver::documentSettings):
(WebCore::StyleResolver::ruleSets):
* dom/AuthorStyleSheets.cpp:
(WebCore::AuthorStyleSheets::collectActiveStyleSheets):
(WebCore::AuthorStyleSheets::analyzeStyleSheetChange):

    Cleanups.

(WebCore::filterEnabledNonemptyCSSStyleSheets):
(WebCore::AuthorStyleSheets::updateActiveStyleSheets):
(WebCore::AuthorStyleSheets::updateStyleResolver):

    Factor to a function.
    Copy any author shadow pseudo elements to user agent shadow tree resolver.

(WebCore::AuthorStyleSheets::activeStyleSheetsForInspector):
* dom/AuthorStyleSheets.h:
* dom/Document.cpp:
(WebCore::Document::createStyleResolver):
(WebCore::Document::userAgentShadowTreeStyleResolver):

    Use separate resolver.

(WebCore::Document::fontsNeedUpdate):
(WebCore::Document::clearStyleResolver):
* dom/Document.h:
(WebCore::Document::ensureStyleResolver):
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::styleResolver):

    Return document-global shadow tree resolver for ua trees.

* style/StyleResolveTree.cpp:
(WebCore::Style::resolveShadowTree):

    Take styleChange of shadow root into account.

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

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/css/DocumentRuleSets.cpp
Source/WebCore/css/DocumentRuleSets.h
Source/WebCore/css/ElementRuleCollector.cpp
Source/WebCore/css/ElementRuleCollector.h
Source/WebCore/css/RuleSet.cpp
Source/WebCore/css/RuleSet.h
Source/WebCore/css/StyleInvalidationAnalysis.cpp
Source/WebCore/css/StyleInvalidationAnalysis.h
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/dom/AuthorStyleSheets.cpp
Source/WebCore/dom/AuthorStyleSheets.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ShadowRoot.cpp
Source/WebCore/style/StyleResolveTree.cpp
Source/WebCore/svg/SVGElement.cpp

index d3df5e7..da653de 100644 (file)
@@ -1,3 +1,114 @@
+2015-09-29  Antti Koivisto  <antti@apple.com>
+
+        Use separate style resolver for user agent shadow trees
+        https://bugs.webkit.org/show_bug.cgi?id=149626
+
+        Reviewed by Andreas Kling.
+
+        We now support separate style resolvers for shadow trees. Use this mechanism to have a separate
+        per-document style resolver for user agent shadow trees. This isolates user agent shadow trees
+        from author style better and simplifies the style resolver. It can also avoid some unnecessary style recalcs.
+
+        * css/DocumentRuleSets.cpp:
+        (WebCore::DocumentRuleSets::resetAuthorStyle):
+        (WebCore::DocumentRuleSets::appendAuthorStyleSheets):
+
+            Change interface so that only the new rules are provided.
+
+        * css/DocumentRuleSets.h:
+        * css/ElementRuleCollector.cpp:
+        (WebCore::ElementRuleCollector::addElementStyleProperties):
+        (WebCore::ElementRuleCollector::collectMatchingRules):
+
+            We can remove special bailout as shadow tree style resolver won't have other author style
+
+        (WebCore::ElementRuleCollector::sortAndTransferMatchedRules):
+
+            Remove the exception that disables property whitelists for UA stylesheets. We don't seem to use the feature.
+
+        (WebCore::ElementRuleCollector::matchUARules):
+        (WebCore::MatchingUARulesScope::MatchingUARulesScope): Deleted.
+        (WebCore::MatchingUARulesScope::~MatchingUARulesScope): Deleted.
+        (WebCore::MatchingUARulesScope::isMatchingUARules): Deleted.
+
+            Remove this unnecessary hack.
+
+        * css/ElementRuleCollector.h:
+        (WebCore::ElementRuleCollector::ElementRuleCollector):
+        * css/RuleSet.cpp:
+        (WebCore::RuleSet::addStyleRule):
+        (WebCore::RuleSet::copyShadowPseudoElementRulesFrom):
+
+            Also copy WebVTT rules. They are currently a sort of mixture of UA and author shadow tree.
+
+        (WebCore::shrinkMapVectorsToFit):
+        * css/RuleSet.h:
+        (WebCore::RuleData::containsUncommonAttributeSelector):
+        (WebCore::RuleData::linkMatchType):
+        (WebCore::RuleData::hasDocumentSecurityOrigin):
+        (WebCore::RuleData::propertyWhitelistType):
+        (WebCore::RuleData::descendantSelectorIdentifierHashes):
+        (WebCore::RuleSet::ruleCount):
+        (WebCore::RuleSet::hasShadowPseudoElementRules):
+        * css/StyleInvalidationAnalysis.cpp:
+        (WebCore::StyleInvalidationAnalysis::StyleInvalidationAnalysis):
+        (WebCore::StyleInvalidationAnalysis::invalidateIfNeeded):
+
+            Don't invalidate the whole tree when author shadow pseudo element rules change. Just invalidate the shadow trees.
+
+        (WebCore::StyleInvalidationAnalysis::invalidateStyleForTree):
+        (WebCore::StyleInvalidationAnalysis::invalidateStyle):
+        (WebCore::invalidateIfNeeded): Deleted.
+        (WebCore::invalidateStyleForTree): Deleted.
+        * css/StyleInvalidationAnalysis.h:
+        (WebCore::StyleInvalidationAnalysis::dirtiesAllStyle):
+        (WebCore::StyleInvalidationAnalysis::hasShadowPseudoElementRulesInAuthorSheet):
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::MatchResult::addMatchedProperties):
+        (WebCore::StyleResolver::StyleResolver):
+        (WebCore::StyleResolver::appendAuthorStyleSheets):
+
+            Simpler interface.
+
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::document):
+        (WebCore::StyleResolver::documentSettings):
+        (WebCore::StyleResolver::ruleSets):
+        * dom/AuthorStyleSheets.cpp:
+        (WebCore::AuthorStyleSheets::collectActiveStyleSheets):
+        (WebCore::AuthorStyleSheets::analyzeStyleSheetChange):
+
+            Cleanups.
+
+        (WebCore::filterEnabledNonemptyCSSStyleSheets):
+        (WebCore::AuthorStyleSheets::updateActiveStyleSheets):
+        (WebCore::AuthorStyleSheets::updateStyleResolver):
+
+            Factor to a function.
+            Copy any author shadow pseudo elements to user agent shadow tree resolver.
+
+        (WebCore::AuthorStyleSheets::activeStyleSheetsForInspector):
+        * dom/AuthorStyleSheets.h:
+        * dom/Document.cpp:
+        (WebCore::Document::createStyleResolver):
+        (WebCore::Document::userAgentShadowTreeStyleResolver):
+
+            Use separate resolver.
+
+        (WebCore::Document::fontsNeedUpdate):
+        (WebCore::Document::clearStyleResolver):
+        * dom/Document.h:
+        (WebCore::Document::ensureStyleResolver):
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::styleResolver):
+
+            Return document-global shadow tree resolver for ua trees.
+
+        * style/StyleResolveTree.cpp:
+        (WebCore::Style::resolveShadowTree):
+
+            Take styleChange of shadow root into account.
+
 2015-09-30  Gwang Yoon Hwang  <yoon@igalia.com>
 
         [GTK] Support HiDPI Properly in WebKitGtk+ with the TextureMapper
index 818a4d7..44aa598 100644 (file)
@@ -83,18 +83,16 @@ void DocumentRuleSets::resetAuthorStyle()
     m_authorStyle->disableAutoShrinkToFit();
 }
 
-void DocumentRuleSets::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet>>& styleSheets, MediaQueryEvaluator* medium, InspectorCSSOMWrappers& inspectorCSSOMWrappers, StyleResolver* resolver)
+void DocumentRuleSets::appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>& styleSheets, MediaQueryEvaluator* medium, InspectorCSSOMWrappers& inspectorCSSOMWrappers, StyleResolver* resolver)
 {
     // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver
     // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated.
-    unsigned size = styleSheets.size();
-    for (unsigned i = firstNew; i < size; ++i) {
-        CSSStyleSheet* cssSheet = styleSheets[i].get();
+    for (auto& cssSheet : styleSheets) {
         ASSERT(!cssSheet->disabled());
         if (cssSheet->mediaQueries() && !medium->eval(cssSheet->mediaQueries(), resolver))
             continue;
         m_authorStyle->addRulesFromSheet(&cssSheet->contents(), *medium, resolver);
-        inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet);
+        inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet.get());
     }
     m_authorStyle->shrinkToFit();
     collectFeatures();
index a26f95c..fdf1eea 100644 (file)
@@ -51,7 +51,7 @@ public:
 
     void initUserStyle(ExtensionStyleSheets&, const MediaQueryEvaluator&, StyleResolver&);
     void resetAuthorStyle();
-    void appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet>>&, MediaQueryEvaluator*, InspectorCSSOMWrappers&, StyleResolver*);
+    void appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>&, MediaQueryEvaluator*, InspectorCSSOMWrappers&, StyleResolver*);
 
     void collectFeatures();
 
index 73a4248..16f03b8 100644 (file)
@@ -113,35 +113,6 @@ inline void ElementRuleCollector::addElementStyleProperties(const StylePropertie
         m_result.isCacheable = false;
 }
 
-class MatchingUARulesScope {
-public:
-    MatchingUARulesScope();
-    ~MatchingUARulesScope();
-
-    static bool isMatchingUARules();
-
-private:
-    static bool m_matchingUARules;
-};
-
-MatchingUARulesScope::MatchingUARulesScope()
-{
-    ASSERT(!m_matchingUARules);
-    m_matchingUARules = true;
-}
-
-MatchingUARulesScope::~MatchingUARulesScope()
-{
-    m_matchingUARules = false;
-}
-
-inline bool MatchingUARulesScope::isMatchingUARules()
-{
-    return m_matchingUARules;
-}
-
-bool MatchingUARulesScope::m_matchingUARules = false;
-
 void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
 {
     ASSERT(matchRequest.ruleSet);
@@ -158,10 +129,6 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
         const AtomicString& pseudoId = m_element.shadowPseudoId();
         if (!pseudoId.isEmpty())
             collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange);
-
-        // Only match UA rules in shadow tree.
-        if (!MatchingUARulesScope::isMatchingUARules())
-            return;
     }
 
     // We need to collect the rules for id, class, tag, and everything else into a buffer and
@@ -215,7 +182,7 @@ void ElementRuleCollector::sortAndTransferMatchedRules()
     for (const MatchedRule& matchedRule : matchedRules) {
         if (m_style && matchedRule.ruleData->containsUncommonAttributeSelector())
             m_style->setUnique();
-        m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(MatchingUARulesScope::isMatchingUARules()));
+        m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType());
     }
 }
 
@@ -251,8 +218,6 @@ void ElementRuleCollector::matchUserRules(bool includeEmptyRules)
 
 void ElementRuleCollector::matchUARules()
 {
-    MatchingUARulesScope scope;
-
     // First we match rules from the user agent sheet.
     if (CSSDefaultStyleSheets::simpleDefaultStyleSheet)
         m_result.isCacheable = false;
index 36b31ee..abf922c 100644 (file)
@@ -50,11 +50,6 @@ public:
         , m_style(style)
         , m_ruleSets(ruleSets)
         , m_selectorFilter(selectorFilter)
-        , m_isPrintStyle(false)
-        , m_regionForStyling(nullptr)
-        , m_pseudoStyleRequest(NOPSEUDO)
-        , m_sameOriginOnly(false)
-        , m_mode(SelectorChecker::Mode::ResolvingStyle)
         , m_canUseFastReject(m_selectorFilter.parentStackIsConsistent(element.parentNode()))
     {
     }
@@ -98,11 +93,11 @@ private:
     const DocumentRuleSets& m_ruleSets;
     const SelectorFilter& m_selectorFilter;
 
-    bool m_isPrintStyle;
-    const RenderRegion* m_regionForStyling;
-    PseudoStyleRequest m_pseudoStyleRequest;
-    bool m_sameOriginOnly;
-    SelectorChecker::Mode m_mode;
+    bool m_isPrintStyle { false };
+    const RenderRegion* m_regionForStyling { nullptr };
+    PseudoStyleRequest m_pseudoStyleRequest { NOPSEUDO };
+    bool m_sameOriginOnly { false };
+    SelectorChecker::Mode m_mode { SelectorChecker::Mode::ResolvingStyle };
     bool m_canUseFastReject;
 
     std::unique_ptr<Vector<MatchedRule, 32>> m_matchedRules;
index b2f6ddf..472a02d 100644 (file)
@@ -377,6 +377,29 @@ void RuleSet::addStyleRule(StyleRule* rule, AddRuleFlags addRuleFlags)
         addRule(rule, selectorIndex, addRuleFlags);
 }
 
+bool RuleSet::hasShadowPseudoElementRules() const
+{
+    if (!m_shadowPseudoElementRules.isEmpty())
+        return true;
+#if ENABLE(VIDEO_TRACK)
+    if (!m_cuePseudoRules.isEmpty())
+        return true;
+#endif
+    return false;
+}
+
+void RuleSet::copyShadowPseudoElementRulesFrom(const RuleSet& other)
+{
+    for (auto& keyValuePair : other.m_shadowPseudoElementRules)
+        m_shadowPseudoElementRules.add(keyValuePair.key, std::make_unique<RuleDataVector>(*keyValuePair.value));
+
+#if ENABLE(VIDEO_TRACK)
+    // FIXME: We probably shouldn't treat WebVTT as author stylable user agent shadow tree.
+    for (auto& cue : other.m_cuePseudoRules)
+        m_cuePseudoRules.append(cue);
+#endif
+}
+
 static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map)
 {
     for (auto& vector : map.values())
index 1ce7065..320cc7d 100644 (file)
@@ -79,7 +79,7 @@ public:
     bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
     unsigned linkMatchType() const { return m_linkMatchType; }
     bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
-    PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
+    PropertyWhitelistType propertyWhitelistType() const { return static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
     // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance.
     static const unsigned maximumIdentifierCount = 4;
     const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }
@@ -187,7 +187,8 @@ public:
 
     unsigned ruleCount() const { return m_ruleCount; }
 
-    bool hasShadowPseudoElementRules() const { return !m_shadowPseudoElementRules.isEmpty(); }
+    bool hasShadowPseudoElementRules() const;
+    void copyShadowPseudoElementRulesFrom(const RuleSet&);
 
 private:
     void addChildRules(const Vector<RefPtr<StyleRuleBase>>&, const MediaQueryEvaluator& medium, StyleResolver*, bool hasDocumentSecurityOrigin, bool isInitiatingElementInUserAgentShadowTree, AddRuleFlags);
index 7a91c66..2b90b23 100644 (file)
@@ -31,6 +31,7 @@
 #include "ElementIterator.h"
 #include "ElementRuleCollector.h"
 #include "SelectorFilter.h"
+#include "ShadowRoot.h"
 #include "StyleRuleImport.h"
 #include "StyleSheetContents.h"
 
@@ -83,17 +84,20 @@ StyleInvalidationAnalysis::StyleInvalidationAnalysis(const Vector<StyleSheetCont
     for (auto& sheet : sheets)
         m_ruleSets.authorStyle()->addRulesFromSheet(sheet, mediaQueryEvaluator);
 
-    // FIXME: We don't descent into shadow trees or otherwise handle shadow pseudo elements.
-    if (m_ruleSets.authorStyle()->hasShadowPseudoElementRules())
-        m_dirtiesAllStyle = true;
+    m_hasShadowPseudoElementRulesInAuthorSheet = m_ruleSets.authorStyle()->hasShadowPseudoElementRules();
 }
 
-enum class CheckDescendants { Yes, No };
-static CheckDescendants invalidateIfNeeded(Element& element, SelectorFilter& filter, const DocumentRuleSets& ruleSets)
+StyleInvalidationAnalysis::CheckDescendants StyleInvalidationAnalysis::invalidateIfNeeded(Element& element, SelectorFilter& filter)
 {
+    if (m_hasShadowPseudoElementRulesInAuthorSheet) {
+        // FIXME: This could do actual rule matching too.
+        if (auto* shadowRoot = element.shadowRoot())
+            shadowRoot->setNeedsStyleRecalc();
+    }
+
     switch (element.styleChangeType()) {
     case NoStyleChange: {
-        ElementRuleCollector ruleCollector(element, nullptr, ruleSets, filter);
+        ElementRuleCollector ruleCollector(element, nullptr, m_ruleSets, filter);
         ruleCollector.setMode(SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements);
         ruleCollector.matchAuthorRules(false);
 
@@ -112,9 +116,9 @@ static CheckDescendants invalidateIfNeeded(Element& element, SelectorFilter& fil
     return CheckDescendants::Yes;
 }
 
-static void invalidateStyleForTree(Element& root, SelectorFilter& filter, const DocumentRuleSets& ruleSets)
+void StyleInvalidationAnalysis::invalidateStyleForTree(Element& root, SelectorFilter& filter)
 {
-    if (invalidateIfNeeded(root, filter, ruleSets) == CheckDescendants::No)
+    if (invalidateIfNeeded(root, filter) == CheckDescendants::No)
         return;
 
     Vector<Element*, 20> parentStack;
@@ -136,7 +140,7 @@ static void invalidateStyleForTree(Element& root, SelectorFilter& filter, const
         }
         previousElement = &descendant;
 
-        if (invalidateIfNeeded(descendant, filter, ruleSets) == CheckDescendants::Yes)
+        if (invalidateIfNeeded(descendant, filter) == CheckDescendants::Yes)
             it.traverseNext();
         else
             it.traverseNextSkippingChildren();
@@ -160,7 +164,7 @@ void StyleInvalidationAnalysis::invalidateStyle(Document& document)
 
     SelectorFilter filter;
     filter.setupParentStack(documentElement);
-    invalidateStyleForTree(*documentElement, filter, m_ruleSets);
+    invalidateStyleForTree(*documentElement, filter);
 }
 
 }
index 5c9f23a..95fb64d 100644 (file)
@@ -33,6 +33,7 @@
 namespace WebCore {
 
 class Document;
+class SelectorFilter;
 class StyleSheetContents;
 
 class StyleInvalidationAnalysis {
@@ -40,10 +41,16 @@ public:
     StyleInvalidationAnalysis(const Vector<StyleSheetContents*>&, const MediaQueryEvaluator&);
 
     bool dirtiesAllStyle() const { return m_dirtiesAllStyle; }
+    bool hasShadowPseudoElementRulesInAuthorSheet() const { return m_hasShadowPseudoElementRulesInAuthorSheet; }
     void invalidateStyle(Document&);
 
 private:
-    bool m_dirtiesAllStyle;
+    enum class CheckDescendants { Yes, No };
+    CheckDescendants invalidateIfNeeded(Element&, SelectorFilter&);
+    void invalidateStyleForTree(Element&, SelectorFilter&);
+
+    bool m_dirtiesAllStyle { false };
+    bool m_hasShadowPseudoElementRulesInAuthorSheet { false };
     DocumentRuleSets m_ruleSets;
 };
 
index eedda73..11540d1 100644 (file)
@@ -271,11 +271,11 @@ void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& pro
     }
 }
 
-StyleResolver::StyleResolver(Document& document, bool matchAuthorAndUserStyles)
+StyleResolver::StyleResolver(Document& document)
     : m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
     , m_matchedPropertiesCacheSweepTimer(*this, &StyleResolver::sweepMatchedPropertiesCache)
     , m_document(document)
-    , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles)
+    , m_matchAuthorAndUserStyles(m_document.settings() ? m_document.settings()->authorAndUserStylesEnabled() : true)
 #if ENABLE(CSS_DEVICE_ADAPTATION)
     , m_viewportStyleResolver(ViewportStyleResolver::create(&document))
 #endif
@@ -316,9 +316,9 @@ StyleResolver::StyleResolver(Document& document, bool matchAuthorAndUserStyles)
 #endif
 }
 
-void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet>>& styleSheets)
+void StyleResolver::appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>& styleSheets)
 {
-    m_ruleSets.appendAuthorStyleSheets(firstNew, styleSheets, m_medium.get(), m_inspectorCSSOMWrappers, this);
+    m_ruleSets.appendAuthorStyleSheets(styleSheets, m_medium.get(), m_inspectorCSSOMWrappers, this);
     if (auto renderView = document().renderView())
         renderView->style().fontCascade().update(&document().fontSelector());
 
index 01b3a3b..4aa74a2 100644 (file)
@@ -138,7 +138,7 @@ public:
 class StyleResolver {
     WTF_MAKE_NONCOPYABLE(StyleResolver); WTF_MAKE_FAST_ALLOCATED;
 public:
-    StyleResolver(Document&, bool matchAuthorAndUserStyles);
+    StyleResolver(Document&);
     ~StyleResolver();
 
     // Using these during tree walk will allow style selector to optimize child and descendant selector lookups.
@@ -162,9 +162,7 @@ public:
     Document& document() { return m_document; }
     Settings* documentSettings() { return m_document.settings(); }
 
-    // FIXME: It could be better to call m_ruleSets.appendAuthorStyleSheets() directly after we factor StyleRsolver further.
-    // https://bugs.webkit.org/show_bug.cgi?id=108890
-    void appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet>>&);
+    void appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>&);
 
     DocumentRuleSets& ruleSets() { return m_ruleSets; }
     const DocumentRuleSets& ruleSets() const { return m_ruleSets; }
index bea3eae..7ecaeb3 100644 (file)
@@ -211,9 +211,8 @@ void AuthorStyleSheets::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& she
     }
 }
 
-void AuthorStyleSheets::analyzeStyleSheetChange(UpdateFlag updateFlag, const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, StyleResolverUpdateType& styleResolverUpdateType, bool& requiresFullStyleRecalc)
+AuthorStyleSheets::StyleResolverUpdateType AuthorStyleSheets::analyzeStyleSheetChange(UpdateFlag updateFlag, const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, bool& requiresFullStyleRecalc)
 {
-    styleResolverUpdateType = Reconstruct;
     requiresFullStyleRecalc = true;
     
     // Stylesheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
@@ -225,30 +224,32 @@ void AuthorStyleSheets::analyzeStyleSheetChange(UpdateFlag updateFlag, const Vec
     }
     if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) {
         m_hadActiveLoadingStylesheet = false;
-        return;
+        return Reconstruct;
     }
     m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet;
 
     if (updateFlag != OptimizedUpdate)
-        return;
+        return Reconstruct;
     if (!m_document.styleResolverIfExists())
-        return;
+        return Reconstruct;
+
     StyleResolver& styleResolver = *m_document.styleResolverIfExists();
 
     // Find out which stylesheets are new.
     unsigned oldStylesheetCount = m_activeStyleSheets.size();
     if (newStylesheetCount < oldStylesheetCount)
-        return;
+        return Reconstruct;
+
     Vector<StyleSheetContents*> addedSheets;
     unsigned newIndex = 0;
     for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
         if (newIndex >= newStylesheetCount)
-            return;
+            return Reconstruct;
         while (m_activeStyleSheets[oldIndex] != newStylesheets[newIndex]) {
             addedSheets.append(&newStylesheets[newIndex]->contents());
             ++newIndex;
             if (newIndex == newStylesheetCount)
-                return;
+                return Reconstruct;
         }
         ++newIndex;
     }
@@ -259,16 +260,19 @@ void AuthorStyleSheets::analyzeStyleSheetChange(UpdateFlag updateFlag, const Vec
     }
     // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
     // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
-    styleResolverUpdateType = hasInsertions ? Reset : Additive;
+    auto styleResolverUpdateType = hasInsertions ? Reset : Additive;
 
     // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
     if (!m_document.bodyOrFrameset() || m_document.hasNodesWithPlaceholderStyle())
-        return;
+        return styleResolverUpdateType;
+
     StyleInvalidationAnalysis invalidationAnalysis(addedSheets, styleResolver.mediaQueryEvaluator());
     if (invalidationAnalysis.dirtiesAllStyle())
-        return;
+        return styleResolverUpdateType;
     invalidationAnalysis.invalidateStyle(m_document);
     requiresFullStyleRecalc = false;
+
+    return styleResolverUpdateType;
 }
 
 static void filterEnabledNonemptyCSSStyleSheets(Vector<RefPtr<CSSStyleSheet>>& result, const Vector<RefPtr<StyleSheet>>& sheets)
@@ -307,25 +311,10 @@ bool AuthorStyleSheets::updateActiveStyleSheets(UpdateFlag updateFlag)
     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
     filterEnabledNonemptyCSSStyleSheets(activeCSSStyleSheets, activeStyleSheets);
 
-    StyleResolverUpdateType styleResolverUpdateType;
     bool requiresFullStyleRecalc;
-    analyzeStyleSheetChange(updateFlag, activeCSSStyleSheets, styleResolverUpdateType, requiresFullStyleRecalc);
+    auto styleResolverUpdateType = analyzeStyleSheetChange(updateFlag, activeCSSStyleSheets, requiresFullStyleRecalc);
 
-    if (styleResolverUpdateType == Reconstruct) {
-        if (m_shadowRoot)
-            m_shadowRoot->resetStyleResolver();
-        else
-            m_document.clearStyleResolver();
-    } else {
-        StyleResolver& styleResolver = m_document.ensureStyleResolver();
-        if (styleResolverUpdateType == Reset) {
-            styleResolver.ruleSets().resetAuthorStyle();
-            styleResolver.appendAuthorStyleSheets(0, activeCSSStyleSheets);
-        } else {
-            ASSERT(styleResolverUpdateType == Additive);
-            styleResolver.appendAuthorStyleSheets(m_activeStyleSheets.size(), activeCSSStyleSheets);
-        }
-    }
+    updateStyleResolver(activeCSSStyleSheets, styleResolverUpdateType);
 
     m_weakCopyOfActiveStyleSheetListForFastLookup = nullptr;
     m_activeStyleSheets.swap(activeCSSStyleSheets);
@@ -344,6 +333,35 @@ bool AuthorStyleSheets::updateActiveStyleSheets(UpdateFlag updateFlag)
     return requiresFullStyleRecalc;
 }
 
+void AuthorStyleSheets::updateStyleResolver(Vector<RefPtr<CSSStyleSheet>>& activeStyleSheets, StyleResolverUpdateType updateType)
+{
+    if (updateType == Reconstruct) {
+        if (m_shadowRoot)
+            m_shadowRoot->resetStyleResolver();
+        else
+            m_document.clearStyleResolver();
+        return;
+    }
+    auto& styleResolver = m_document.ensureStyleResolver();
+    auto& userAgentShadowTreeStyleResolver = m_document.userAgentShadowTreeStyleResolver();
+
+    if (updateType == Reset) {
+        styleResolver.ruleSets().resetAuthorStyle();
+        styleResolver.appendAuthorStyleSheets(activeStyleSheets);
+    } else {
+        ASSERT(updateType == Additive);
+        unsigned firstNewIndex = m_activeStyleSheets.size();
+        Vector<RefPtr<CSSStyleSheet>> newStyleSheets;
+        newStyleSheets.appendRange(activeStyleSheets.begin() + firstNewIndex, activeStyleSheets.end());
+        styleResolver.appendAuthorStyleSheets(newStyleSheets);
+    }
+
+    userAgentShadowTreeStyleResolver.ruleSets().resetAuthorStyle();
+    auto& authorRuleSet = *styleResolver.ruleSets().authorStyle();
+    if (authorRuleSet.hasShadowPseudoElementRules())
+        userAgentShadowTreeStyleResolver.ruleSets().authorStyle()->copyShadowPseudoElementRulesFrom(authorRuleSet);
+}
+
 const Vector<RefPtr<CSSStyleSheet>> AuthorStyleSheets::activeStyleSheetsForInspector() const
 {
     Vector<RefPtr<CSSStyleSheet>> result;
index f16a73b..6e14f66 100644 (file)
@@ -106,7 +106,8 @@ private:
         Reset,
         Additive
     };
-    void analyzeStyleSheetChange(UpdateFlag, const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, StyleResolverUpdateType&, bool& requiresFullStyleRecalc);
+    StyleResolverUpdateType analyzeStyleSheetChange(UpdateFlag, const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, bool& requiresFullStyleRecalc);
+    void updateStyleResolver(Vector<RefPtr<CSSStyleSheet>>&, StyleResolverUpdateType);
 
     Document& m_document;
     ShadowRoot* m_shadowRoot { nullptr };
index 1fd873e..3b273c9 100644 (file)
@@ -2111,11 +2111,22 @@ void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int&
 
 void Document::createStyleResolver()
 {
-    bool matchAuthorAndUserStyles = true;
-    if (Settings* settings = this->settings())
-        matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled();
-    m_styleResolver = std::make_unique<StyleResolver>(*this, matchAuthorAndUserStyles);
-    m_styleResolver->appendAuthorStyleSheets(0, authorStyleSheets().activeStyleSheets());
+    m_styleResolver = std::make_unique<StyleResolver>(*this);
+    m_styleResolver->appendAuthorStyleSheets(authorStyleSheets().activeStyleSheets());
+}
+
+StyleResolver& Document::userAgentShadowTreeStyleResolver()
+{
+    if (!m_userAgentShadowTreeStyleResolver) {
+        m_userAgentShadowTreeStyleResolver = std::make_unique<StyleResolver>(*this);
+
+        // FIXME: Filter out shadow pseudo elements we don't want to expose to authors.
+        auto& documentAuthorStyle = *ensureStyleResolver().ruleSets().authorStyle();
+        if (documentAuthorStyle.hasShadowPseudoElementRules())
+            m_userAgentShadowTreeStyleResolver->ruleSets().authorStyle()->copyShadowPseudoElementRulesFrom(documentAuthorStyle);
+    }
+
+    return *m_userAgentShadowTreeStyleResolver;
 }
 
 void Document::fontsNeedUpdate(FontSelector&)
@@ -2139,6 +2150,7 @@ CSSFontSelector& Document::fontSelector()
 void Document::clearStyleResolver()
 {
     m_styleResolver = nullptr;
+    m_userAgentShadowTreeStyleResolver = nullptr;
 
     // FIXME: It would be better if the FontSelector could survive this operation.
     if (m_fontSelector) {
index b308ae2..5adc3c2 100644 (file)
@@ -495,6 +495,7 @@ public:
             createStyleResolver();
         return *m_styleResolver;
     }
+    StyleResolver& userAgentShadowTreeStyleResolver();
 
     CSSFontSelector& fontSelector();
 
@@ -1394,6 +1395,7 @@ private:
     unsigned m_referencingNodeCount;
 
     std::unique_ptr<StyleResolver> m_styleResolver;
+    std::unique_ptr<StyleResolver> m_userAgentShadowTreeStyleResolver;
     bool m_didCalculateStyleResolver;
     bool m_hasNodesWithPlaceholderStyle;
     bool m_needsNotifyRemoveAllPendingStylesheet;
index fc23978..46eaf27 100644 (file)
@@ -77,15 +77,14 @@ ShadowRoot::~ShadowRoot()
 
 StyleResolver& ShadowRoot::styleResolver()
 {
-    // FIXME: Use isolated style resolver for user agent shadow roots.
     if (m_type == Type::UserAgent)
-        return document().ensureStyleResolver();
+        return document().userAgentShadowTreeStyleResolver();
 
     if (!m_styleResolver) {
         // FIXME: We could share style resolver with shadow roots that have identical style.
-        m_styleResolver = std::make_unique<StyleResolver>(document(), true);
+        m_styleResolver = std::make_unique<StyleResolver>(document());
         if (m_authorStyleSheets)
-            m_styleResolver->appendAuthorStyleSheets(0, m_authorStyleSheets->activeStyleSheets());
+            m_styleResolver->appendAuthorStyleSheets(m_authorStyleSheets->activeStyleSheets());
     }
     return *m_styleResolver;
 }
index 4ac4701..1909245 100644 (file)
@@ -725,6 +725,8 @@ static void resolveShadowTree(ShadowRoot& shadowRoot, Element& host, Style::Chan
 
     ASSERT(shadowRoot.host() == &host);
     ASSERT(host.renderer());
+    if (shadowRoot.styleChangeType() >= FullStyleChange)
+        change = Force;
     RenderTreePosition renderTreePosition(*host.renderer());
     for (Node* child = shadowRoot.firstChild(); child; child = child->nextSibling()) {
         if (child->renderer())
index 08254cd..2702b83 100644 (file)
@@ -791,10 +791,11 @@ void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement)
 
 RefPtr<RenderStyle> SVGElement::customStyleForRenderer(RenderStyle& parentStyle)
 {
-    if (!correspondingElement())
-        return resolveStyle(&parentStyle);
+    // If the element is in a <use> tree we get the style from the definition tree.
+    if (auto* styleElement = this->correspondingElement())
+        return styleElement->styleResolver().styleForElement(styleElement, &parentStyle, DisallowStyleSharing);
 
-    return styleResolver().styleForElement(correspondingElement(), &parentStyle, DisallowStyleSharing);
+    return resolveStyle(&parentStyle);
 }
 
 MutableStyleProperties* SVGElement::animatedSMILStyleProperties() const