Document style resolvers should share user rulesets
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 May 2017 19:02:43 +0000 (19:02 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 May 2017 19:02:43 +0000 (19:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171549

Reviewed by Andreas Kling.

Large user stylesheets (like those used by ad blockers) can end up using lots of memory if
a document uses large number of shadow trees. User style is inherently per-document and
the resulting rulesets can be shared between the document and the shadow trees.

* css/DocumentRuleSets.cpp:
(WebCore::DocumentRuleSets::DocumentRuleSets):
(WebCore::DocumentRuleSets::userStyle):

    Return per-document user style for shadow trees.

(WebCore::DocumentRuleSets::collectFeatures):
* css/DocumentRuleSets.h:
(WebCore::DocumentRuleSets::setUsesSharedUserStyle):
(WebCore::DocumentRuleSets::userStyle): Deleted.
* css/StyleResolver.cpp:
(WebCore::StyleResolver::StyleResolver):
(WebCore::StyleResolver::initializeUserStyle):

    Separate user style initialization from construction.

* css/StyleResolver.h:
* style/StyleScope.cpp:
(WebCore::Style::Scope::resolver):

    Don't initialize user style for user agents shadow trees.

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

Source/WebCore/ChangeLog
Source/WebCore/css/DocumentRuleSets.cpp
Source/WebCore/css/DocumentRuleSets.h
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/style/StyleScope.cpp

index ce94524..019ab6a 100644 (file)
@@ -1,3 +1,36 @@
+2017-05-02  Antti Koivisto  <antti@apple.com>
+
+        Document style resolvers should share user rulesets
+        https://bugs.webkit.org/show_bug.cgi?id=171549
+
+        Reviewed by Andreas Kling.
+
+        Large user stylesheets (like those used by ad blockers) can end up using lots of memory if
+        a document uses large number of shadow trees. User style is inherently per-document and
+        the resulting rulesets can be shared between the document and the shadow trees.
+
+        * css/DocumentRuleSets.cpp:
+        (WebCore::DocumentRuleSets::DocumentRuleSets):
+        (WebCore::DocumentRuleSets::userStyle):
+
+            Return per-document user style for shadow trees.
+
+        (WebCore::DocumentRuleSets::collectFeatures):
+        * css/DocumentRuleSets.h:
+        (WebCore::DocumentRuleSets::setUsesSharedUserStyle):
+        (WebCore::DocumentRuleSets::userStyle): Deleted.
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::StyleResolver):
+        (WebCore::StyleResolver::initializeUserStyle):
+
+            Separate user style initialization from construction.
+
+        * css/StyleResolver.h:
+        * style/StyleScope.cpp:
+        (WebCore::Style::Scope::resolver):
+
+            Don't initialize user style for user agents shadow trees.
+
 2017-05-02  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Font Loading API specifies font is loaded but sizing of font after load reports inconsistent values
index b7cefd3..e0fcfbc 100644 (file)
@@ -37,7 +37,8 @@
 
 namespace WebCore {
 
-DocumentRuleSets::DocumentRuleSets()
+DocumentRuleSets::DocumentRuleSets(StyleResolver& styleResolver)
+    : m_styleResolver(styleResolver)
 {
     m_authorStyle = std::make_unique<RuleSet>();
     m_authorStyle->disableAutoShrinkToFit();
@@ -47,13 +48,22 @@ DocumentRuleSets::~DocumentRuleSets()
 {
 }
 
-void DocumentRuleSets::initUserStyle(ExtensionStyleSheets& extensionStyleSheets, const MediaQueryEvaluator& medium, StyleResolver& resolver)
+RuleSet* DocumentRuleSets::userStyle() const
 {
+    if (m_usesSharedUserStyle)
+        return m_styleResolver.document().styleScope().resolver().ruleSets().userStyle();
+    return m_userStyle.get();
+}
+
+void DocumentRuleSets::initializeUserStyle()
+{
+    auto& extensionStyleSheets = m_styleResolver.document().extensionStyleSheets();
+    auto& mediaQueryEvaluator = m_styleResolver.mediaQueryEvaluator();
     auto tempUserStyle = std::make_unique<RuleSet>();
     if (CSSStyleSheet* pageUserSheet = extensionStyleSheets.pageUserSheet())
-        tempUserStyle->addRulesFromSheet(pageUserSheet->contents(), medium, &resolver);
-    collectRulesFromUserStyleSheets(extensionStyleSheets.injectedUserStyleSheets(), *tempUserStyle, medium, resolver);
-    collectRulesFromUserStyleSheets(extensionStyleSheets.documentUserStyleSheets(), *tempUserStyle, medium, resolver);
+        tempUserStyle->addRulesFromSheet(pageUserSheet->contents(), mediaQueryEvaluator, &m_styleResolver);
+    collectRulesFromUserStyleSheets(extensionStyleSheets.injectedUserStyleSheets(), *tempUserStyle, mediaQueryEvaluator, m_styleResolver);
+    collectRulesFromUserStyleSheets(extensionStyleSheets.documentUserStyleSheets(), *tempUserStyle, mediaQueryEvaluator, m_styleResolver);
     if (tempUserStyle->ruleCount() > 0 || tempUserStyle->pageRules().size() > 0)
         m_userStyle = WTFMove(tempUserStyle);
 }
@@ -112,8 +122,8 @@ void DocumentRuleSets::collectFeatures() const
 
     if (m_authorStyle)
         m_features.add(m_authorStyle->features());
-    if (m_userStyle)
-        m_features.add(m_userStyle->features());
+    if (auto* userStyle = this->userStyle())
+        m_features.add(userStyle->features());
 
     m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
     m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
index 7cdb889..0893f4c 100644 (file)
@@ -40,12 +40,12 @@ class MediaQueryEvaluator;
 
 class DocumentRuleSets {
 public:
-    DocumentRuleSets();
+    DocumentRuleSets(StyleResolver&);
     ~DocumentRuleSets();
-    
+
     bool isAuthorStyleDefined() const { return m_isAuthorStyleDefined; }
     RuleSet& authorStyle() const { return *m_authorStyle.get(); }
-    RuleSet* userStyle() const { return m_userStyle.get(); }
+    RuleSet* userStyle() const;
     const RuleFeatureSet& features() const;
     RuleSet* sibling() const { return m_siblingRuleSet.get(); }
     RuleSet* uncommonAttribute() const { return m_uncommonAttributeRuleSet.get(); }
@@ -59,7 +59,9 @@ public:
     };
     const AttributeRules* ancestorAttributeRulesForHTML(const AtomicString&) const;
 
-    void initUserStyle(ExtensionStyleSheets&, const MediaQueryEvaluator&, StyleResolver&);
+    void setUsesSharedUserStyle(bool b) { m_usesSharedUserStyle = b; }
+    void initializeUserStyle();
+
     void resetAuthorStyle();
     void appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>&, MediaQueryEvaluator*, InspectorCSSOMWrappers&, StyleResolver*);
 
@@ -72,7 +74,9 @@ private:
     bool m_isAuthorStyleDefined { false };
     std::unique_ptr<RuleSet> m_authorStyle;
     std::unique_ptr<RuleSet> m_userStyle;
+    bool m_usesSharedUserStyle { false };
 
+    StyleResolver& m_styleResolver;
     mutable RuleFeatureSet m_features;
     mutable unsigned m_defaultStyleVersionOnFeatureCollection { 0 };
     mutable std::unique_ptr<RuleSet> m_siblingRuleSet;
index a33dc71..d7e8af0 100644 (file)
@@ -228,7 +228,8 @@ void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& pro
 }
 
 StyleResolver::StyleResolver(Document& document)
-    : m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
+    : m_ruleSets(*this)
+    , m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
     , m_matchedPropertiesCacheSweepTimer(*this, &StyleResolver::sweepMatchedPropertiesCache)
     , m_document(document)
     , m_matchAuthorAndUserStyles(m_document.settings().authorAndUserStylesEnabled())
@@ -267,8 +268,6 @@ StyleResolver::StyleResolver(Document& document)
 
     m_ruleSets.resetAuthorStyle();
 
-    m_ruleSets.initUserStyle(m_document.extensionStyleSheets(), m_mediaQueryEvaluator, *this);
-
 #if ENABLE(SVG_FONTS)
     if (m_document.svgExtensions()) {
         const HashSet<SVGFontFaceElement*>& svgFontFaceElements = m_document.svgExtensions()->svgFontFaceElements();
index 4282fa4..597c5d5 100644 (file)
@@ -96,6 +96,12 @@ StyleResolver& Scope::resolver()
     if (!m_resolver) {
         SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
         m_resolver = std::make_unique<StyleResolver>(m_document);
+
+        if (!m_shadowRoot)
+            m_resolver->ruleSets().initializeUserStyle();
+        else
+            m_resolver->ruleSets().setUsesSharedUserStyle(m_shadowRoot->mode() != ShadowRootMode::UserAgent);
+
         m_resolver->appendAuthorStyleSheets(m_activeStyleSheets);
     }
     ASSERT(!m_shadowRoot || &m_document == &m_shadowRoot->document());