Document style resolvers should share user rulesets
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 May 2017 14:30:30 +0000 (14:30 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 May 2017 14:30:30 +0000 (14:30 +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@216069 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/css/StyleResolver.h
Source/WebCore/style/StyleScope.cpp

index ea55068..63e2944 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  Gwang Yoon Hwang  <yoon@igalia.com>
 
         [GTK] Remove undefined nativeImage method from the ImageBuffer's header
index b7cefd3..3efb3a0 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,6 +48,13 @@ DocumentRuleSets::~DocumentRuleSets()
 {
 }
 
+RuleSet* DocumentRuleSets::userStyle() const
+{
+    if (m_usesSharedUserStyle)
+        return m_styleResolver.document().styleScope().resolver().ruleSets().userStyle();
+    return m_userStyle.get();
+}
+
 void DocumentRuleSets::initUserStyle(ExtensionStyleSheets& extensionStyleSheets, const MediaQueryEvaluator& medium, StyleResolver& resolver)
 {
     auto tempUserStyle = std::make_unique<RuleSet>();
@@ -112,8 +120,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..1d8f14c 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 setUsesSharedUserStyle(bool b) { m_usesSharedUserStyle = true; }
     void initUserStyle(ExtensionStyleSheets&, const MediaQueryEvaluator&, StyleResolver&);
+
     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..4a3b9f4 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();
@@ -278,6 +277,11 @@ StyleResolver::StyleResolver(Document& document)
 #endif
 }
 
+void StyleResolver::initializeUserStyle()
+{
+    m_ruleSets.initUserStyle(m_document.extensionStyleSheets(), m_mediaQueryEvaluator, *this);
+}
+
 void StyleResolver::appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>& styleSheets)
 {
     m_ruleSets.appendAuthorStyleSheets(styleSheets, &m_mediaQueryEvaluator, m_inspectorCSSOMWrappers, this);
index 4ac4bf1..995919d 100644 (file)
@@ -152,6 +152,7 @@ public:
     const Document& document() const { return m_document; }
     const Settings& settings() const { return m_document.settings(); }
 
+    void initializeUserStyle();
     void appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>&);
 
     DocumentRuleSets& ruleSets() { return m_ruleSets; }
index 4282fa4..6896751 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->initializeUserStyle();
+        else if (m_shadowRoot->mode() != ShadowRootMode::UserAgent)
+            m_resolver->ruleSets().setUsesSharedUserStyle();
+
         m_resolver->appendAuthorStyleSheets(m_activeStyleSheets);
     }
     ASSERT(!m_shadowRoot || &m_document == &m_shadowRoot->document());