Factor common code in Style::*ChangeInvalidation into helper functions
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Aug 2017 14:45:29 +0000 (14:45 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Aug 2017 14:45:29 +0000 (14:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174312

Reviewed by Andreas Kling.

There is a lot of copy code here.

* Style/StyleInvalidationFunctions.h: Added.
(WebCore::Style::traverseRuleFeaturesInShadowTree):
(WebCore::Style::traverseRuleFeaturesForSlotted):
(WebCore::Style::traverseRuleFeatures):

    Add functions for traversing rule features that may affect style of an element.
    Use lambdas to implement client-specific behavior.

* WebCore.xcodeproj/project.pbxproj:
* style/AttributeChangeInvalidation.cpp:
(WebCore::Style::mayBeAffectedByAttributeChange):
(WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
(WebCore::Style::mayBeAffectedByHostRules): Deleted.
(WebCore::Style::mayBeAffectedBySlottedRules): Deleted.
* style/ClassChangeInvalidation.cpp:
(WebCore::Style::ClassChangeInvalidation::invalidateStyle):
(WebCore::Style::mayBeAffectedByHostRules): Deleted.
(WebCore::Style::mayBeAffectedBySlottedRules): Deleted.
* style/IdChangeInvalidation.cpp:
(WebCore::Style::IdChangeInvalidation::invalidateStyle):
(WebCore::Style::mayBeAffectedByHostRules): Deleted.
(WebCore::Style::mayBeAffectedBySlottedRules): Deleted.

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

Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/style/AttributeChangeInvalidation.cpp
Source/WebCore/style/ClassChangeInvalidation.cpp
Source/WebCore/style/IdChangeInvalidation.cpp
Source/WebCore/style/StyleInvalidationFunctions.h [new file with mode: 0644]

index 7666b4a..7b068e1 100644 (file)
@@ -1,3 +1,35 @@
+2017-08-03  Antti Koivisto  <antti@apple.com>
+
+        Factor common code in Style::*ChangeInvalidation into helper functions
+        https://bugs.webkit.org/show_bug.cgi?id=174312
+
+        Reviewed by Andreas Kling.
+
+        There is a lot of copy code here.
+
+        * Style/StyleInvalidationFunctions.h: Added.
+        (WebCore::Style::traverseRuleFeaturesInShadowTree):
+        (WebCore::Style::traverseRuleFeaturesForSlotted):
+        (WebCore::Style::traverseRuleFeatures):
+
+            Add functions for traversing rule features that may affect style of an element.
+            Use lambdas to implement client-specific behavior.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * style/AttributeChangeInvalidation.cpp:
+        (WebCore::Style::mayBeAffectedByAttributeChange):
+        (WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
+        (WebCore::Style::mayBeAffectedByHostRules): Deleted.
+        (WebCore::Style::mayBeAffectedBySlottedRules): Deleted.
+        * style/ClassChangeInvalidation.cpp:
+        (WebCore::Style::ClassChangeInvalidation::invalidateStyle):
+        (WebCore::Style::mayBeAffectedByHostRules): Deleted.
+        (WebCore::Style::mayBeAffectedBySlottedRules): Deleted.
+        * style/IdChangeInvalidation.cpp:
+        (WebCore::Style::IdChangeInvalidation::invalidateStyle):
+        (WebCore::Style::mayBeAffectedByHostRules): Deleted.
+        (WebCore::Style::mayBeAffectedBySlottedRules): Deleted.
+
 2017-08-03  Zan Dobersek  <zdobersek@igalia.com>
 
         [EME] CDM constructor assigns CDMPrivate member multiple times
index 135c6d3..80c4471 100644 (file)
                E46A2B1C17CA65B9000DBCD8 /* TypedElementDescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E46A2B1B17CA65B9000DBCD8 /* TypedElementDescendantIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E46A2B1E17CA76B1000DBCD8 /* ElementChildIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E46A2B1D17CA76B1000DBCD8 /* ElementChildIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E46B41F91CB24E70008F11DE /* NoEventDispatchAssertion.h in Headers */ = {isa = PBXBuildFile; fileRef = E46B41F81CB24E70008F11DE /* NoEventDispatchAssertion.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E46C794B1F13E82B00F371E1 /* StyleInvalidationFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A1822F1F13BE5800FEF698 /* StyleInvalidationFunctions.h */; };
                E47127CA163438A100ED6F5A /* StyleInvalidator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E47A97CE163059FC005DCD99 /* StyleInvalidator.cpp */; };
                E47127CB163438AE00ED6F5A /* StyleInvalidator.h in Headers */ = {isa = PBXBuildFile; fileRef = E47A97CF163059FC005DCD99 /* StyleInvalidator.h */; };
                E4778B7F115A581A00B5D372 /* JSCustomEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4778B7D115A581A00B5D372 /* JSCustomEvent.cpp */; };
                E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSValuePool.cpp; sourceTree = "<group>"; };
                E4A007821B820EC8002C5A6E /* DataURLDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataURLDecoder.h; sourceTree = "<group>"; };
                E4A007841B820ED3002C5A6E /* DataURLDecoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataURLDecoder.cpp; sourceTree = "<group>"; };
+               E4A1822F1F13BE5800FEF698 /* StyleInvalidationFunctions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StyleInvalidationFunctions.h; sourceTree = "<group>"; };
                E4A814D31C6DEC4000BF85AC /* ClassChangeInvalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassChangeInvalidation.h; sourceTree = "<group>"; };
                E4A814D51C6DEE8D00BF85AC /* ClassChangeInvalidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassChangeInvalidation.cpp; sourceTree = "<group>"; };
                E4A814D71C70E10500BF85AC /* AttributeChangeInvalidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttributeChangeInvalidation.cpp; sourceTree = "<group>"; };
                                E401E0A31C3C0B8300F34D10 /* StyleChange.h */,
                                E4D58EB617B4ED8900CBDCA8 /* StyleFontSizeFunctions.cpp */,
                                E4D58EB717B4ED8900CBDCA8 /* StyleFontSizeFunctions.h */,
+                               E4A1822F1F13BE5800FEF698 /* StyleInvalidationFunctions.h */,
                                E47A97CE163059FC005DCD99 /* StyleInvalidator.cpp */,
                                E47A97CF163059FC005DCD99 /* StyleInvalidator.h */,
                                E4DACE6B1D12E1160075980F /* StylePendingResources.cpp */,
                                5EBB89371C77782900C65D41 /* MediaEndpointConfiguration.h in Headers */,
                                5E16A2E41BFA650B0029A21E /* MediaEndpointPeerConnection.h in Headers */,
                                5EBB89321C77782300C65D41 /* MediaEndpointSessionConfiguration.h in Headers */,
+                               E46C794B1F13E82B00F371E1 /* StyleInvalidationFunctions.h in Headers */,
                                5E4EAB041D07166A0006A184 /* MediaEndpointSessionDescription.h in Headers */,
                                E44613AD0CD6331000FADA75 /* MediaError.h in Headers */,
                                4E1959220A39DABA00220FE5 /* MediaFeatureNames.h in Headers */,
index 128cc88..16bd776 100644 (file)
 #include "config.h"
 #include "AttributeChangeInvalidation.h"
 
-#include "DocumentRuleSets.h"
 #include "ElementIterator.h"
-#include "HTMLSlotElement.h"
-#include "ShadowRoot.h"
+#include "StyleInvalidationFunctions.h"
 #include "StyleInvalidator.h"
-#include "StyleResolver.h"
-#include "StyleScope.h"
 
 namespace WebCore {
 namespace Style {
 
-static bool mayBeAffectedByAttributeChange(DocumentRuleSets& ruleSets, bool isHTML, const QualifiedName& attributeName)
+static bool mayBeAffectedByAttributeChange(const RuleFeatureSet& features, bool isHTML, const QualifiedName& attributeName)
 {
-    auto& nameSet = isHTML ? ruleSets.features().attributeCanonicalLocalNamesInRules : ruleSets.features().attributeLocalNamesInRules;
+    auto& nameSet = isHTML ? features.attributeCanonicalLocalNamesInRules : features.attributeLocalNamesInRules;
     return nameSet.contains(attributeName.localName());
 }
 
-static bool mayBeAffectedByHostRules(const Element& element, const QualifiedName& attributeName, bool& mayAffectShadowTree)
-{
-    // FIXME: More of this code should be shared between Class/Attribute/IdInvalidation.
-    auto* shadowRoot = element.shadowRoot();
-    if (!shadowRoot)
-        return false;
-    auto& shadowRuleSets = shadowRoot->styleScope().resolver().ruleSets();
-    auto& authorStyle = shadowRuleSets.authorStyle();
-    if (authorStyle.hostPseudoClassRules().isEmpty() && !authorStyle.hasHostPseudoClassRulesMatchingInShadowTree())
-        return false;
-
-    if (!mayBeAffectedByAttributeChange(shadowRuleSets, element.isHTMLElement(), attributeName))
-        return false;
-
-    if (authorStyle.hasHostPseudoClassRulesMatchingInShadowTree())
-        mayAffectShadowTree = true;
-    return true;
-}
-
-static bool mayBeAffectedBySlottedRules(const Element& element, const QualifiedName& attributeName)
-{
-    for (auto* shadowRoot : assignedShadowRootsIfSlotted(element)) {
-        auto& ruleSets = shadowRoot->styleScope().resolver().ruleSets();
-        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
-            continue;
-        if (mayBeAffectedByAttributeChange(ruleSets, element.isHTMLElement(), attributeName))
-            return true;
-    }
-    return false;
-}
-
 void AttributeChangeInvalidation::invalidateStyle(const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
 {
     if (newValue == oldValue)
         return;
 
-    auto& ruleSets = m_element.styleResolver().ruleSets();
     bool isHTML = m_element.isHTMLElement();
-    bool mayAffectShadowTree = false;
 
-    bool mayAffectStyle = mayBeAffectedByAttributeChange(ruleSets, isHTML, attributeName)
-        || mayBeAffectedByHostRules(m_element, attributeName, mayAffectShadowTree)
-        || mayBeAffectedBySlottedRules(m_element, attributeName);
+    bool mayAffectStyle = false;
+    bool mayAffectStyleInShadowTree = false;
+
+    traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) {
+        if (!mayBeAffectedByAttributeChange(features, isHTML, attributeName))
+            return;
+        mayAffectStyle = true;
+        if (mayAffectShadowTree)
+            mayAffectStyleInShadowTree = true;
+    });
 
     if (!mayAffectStyle)
         return;
@@ -95,13 +65,8 @@ void AttributeChangeInvalidation::invalidateStyle(const QualifiedName& attribute
         return;
     }
 
-    if (m_element.shadowRoot() && ruleSets.authorStyle().hasShadowPseudoElementRules())
-        mayAffectShadowTree = true;
-
-    if (is<HTMLSlotElement>(m_element) && !ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
-        mayAffectShadowTree = true;
-
-    if (mayAffectShadowTree) {
+    if (mayAffectStyleInShadowTree) {
+        // FIXME: More fine-grained invalidation.
         m_element.invalidateStyleForSubtree();
         return;
     }
@@ -111,6 +76,7 @@ void AttributeChangeInvalidation::invalidateStyle(const QualifiedName& attribute
     if (!childrenOfType<Element>(m_element).first())
         return;
 
+    auto& ruleSets = m_element.styleResolver().ruleSets();
     auto* attributeRules = ruleSets.ancestorAttributeRulesForHTML(attributeName.localName());
     if (!attributeRules)
         return;
index 8cdff65..dba2381 100644 (file)
 #include "config.h"
 #include "ClassChangeInvalidation.h"
 
-#include "DocumentRuleSets.h"
 #include "ElementChildIterator.h"
-#include "HTMLSlotElement.h"
-#include "ShadowRoot.h"
 #include "SpaceSplitString.h"
+#include "StyleInvalidationFunctions.h"
 #include "StyleInvalidator.h"
-#include "StyleResolver.h"
-#include "StyleScope.h"
 #include <wtf/BitVector.h>
 
 namespace WebCore {
@@ -87,64 +83,27 @@ static ClassChangeVector computeClassChange(const SpaceSplitString& oldClasses,
     return changedClasses;
 }
 
-static bool mayBeAffectedByHostRules(ShadowRoot* shadowRoot, AtomicStringImpl* changedClass, bool& mayAffectShadowTree)
-{
-    // FIXME: More of this code should be shared between Class/Attribute/IdInvalidation.
-    if (!shadowRoot)
-        return false;
-    auto& shadowRuleSets = shadowRoot->styleScope().resolver().ruleSets();
-    auto& authorStyle = shadowRuleSets.authorStyle();
-    if (authorStyle.hostPseudoClassRules().isEmpty() && !authorStyle.hasHostPseudoClassRulesMatchingInShadowTree())
-        return false;
-
-    if (!shadowRuleSets.features().classesInRules.contains(changedClass))
-        return false;
-
-    if (authorStyle.hasHostPseudoClassRulesMatchingInShadowTree())
-        mayAffectShadowTree = true;
-    return true;
-}
-
-static bool mayBeAffectedBySlottedRules(const Vector<ShadowRoot*>& assignedShadowRoots, AtomicStringImpl* changedClass)
-{
-    for (auto& assignedShadowRoot : assignedShadowRoots) {
-        auto& ruleSets = assignedShadowRoot->styleScope().resolver().ruleSets();
-        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
-            continue;
-        if (ruleSets.features().classesInRules.contains(changedClass))
-            return true;
-    }
-    return false;
-}
-
 void ClassChangeInvalidation::invalidateStyle(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
 {
     auto changedClasses = computeClassChange(oldClasses, newClasses);
-    bool mayAffectShadowTree = false;
-
-    auto& ruleSets = m_element.styleResolver().ruleSets();
-    auto* shadowRoot = m_element.shadowRoot();
-    auto assignedShadowRoots = assignedShadowRootsIfSlotted(m_element);
 
     ClassChangeVector changedClassesAffectingStyle;
-    for (auto* changedClass : changedClasses) {
-        bool mayAffectStyle = ruleSets.features().classesInRules.contains(changedClass)
-            || mayBeAffectedByHostRules(shadowRoot, changedClass, mayAffectShadowTree)
-            || mayBeAffectedBySlottedRules(assignedShadowRoots, changedClass);
-        if (mayAffectStyle)
+    bool mayAffectStyleInShadowTree = false;
+
+    traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) {
+        for (auto* changedClass : changedClasses) {
+            if (!features.classesInRules.contains(changedClass))
+                continue;
             changedClassesAffectingStyle.append(changedClass);
-    };
+            if (mayAffectShadowTree)
+                mayAffectStyleInShadowTree = true;
+        }
+    });
 
     if (changedClassesAffectingStyle.isEmpty())
         return;
 
-    if (shadowRoot && ruleSets.authorStyle().hasShadowPseudoElementRules())
-        mayAffectShadowTree = true;
-
-    if (is<HTMLSlotElement>(m_element) && !ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
-        mayAffectShadowTree = true;
-
-    if (mayAffectShadowTree) {
+    if (mayAffectStyleInShadowTree) {
         // FIXME: We should do fine-grained invalidation for shadow tree.
         m_element.invalidateStyleForSubtree();
         return;
@@ -155,6 +114,7 @@ void ClassChangeInvalidation::invalidateStyle(const SpaceSplitString& oldClasses
     if (!childrenOfType<Element>(m_element).first())
         return;
 
+    auto& ruleSets = m_element.styleResolver().ruleSets();
     for (auto* changedClass : changedClassesAffectingStyle) {
         auto* ancestorClassRules = ruleSets.ancestorClassRules(changedClass);
         if (!ancestorClassRules)
index 9f8f0ab..9691a8d 100644 (file)
 #include "config.h"
 #include "IdChangeInvalidation.h"
 
-#include "DocumentRuleSets.h"
 #include "ElementChildIterator.h"
-#include "HTMLSlotElement.h"
-#include "ShadowRoot.h"
-#include "StyleResolver.h"
-#include "StyleScope.h"
+#include "StyleInvalidationFunctions.h"
 
 namespace WebCore {
 namespace Style {
 
-static bool mayBeAffectedByHostRules(const Element& element, const AtomicString& changedId, bool& mayAffectShadowTree)
-{
-    auto* shadowRoot = element.shadowRoot();
-    if (!shadowRoot)
-        return false;
-    auto& shadowRuleSets = shadowRoot->styleScope().resolver().ruleSets();
-    auto& authorStyle = shadowRuleSets.authorStyle();
-    if (authorStyle.hostPseudoClassRules().isEmpty() && !authorStyle.hasHostPseudoClassRulesMatchingInShadowTree())
-        return false;
-
-    if (!shadowRuleSets.features().idsInRules.contains(changedId))
-        return false;
-
-    if (authorStyle.hasHostPseudoClassRulesMatchingInShadowTree())
-        mayAffectShadowTree = true;
-    return true;
-}
-
-static bool mayBeAffectedBySlottedRules(const Element& element, const AtomicString& changedId)
-{
-    for (auto* shadowRoot : assignedShadowRootsIfSlotted(element)) {
-        auto& ruleSets = shadowRoot->styleScope().resolver().ruleSets();
-        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
-            continue;
-        if (ruleSets.features().idsInRules.contains(changedId))
-            return true;
-    }
-    return false;
-}
-
 void IdChangeInvalidation::invalidateStyle(const AtomicString& changedId)
 {
     if (changedId.isEmpty())
         return;
 
-    auto& ruleSets = m_element.styleResolver().ruleSets();
-    bool mayAffectShadowTree = false;
+    bool mayAffectStyle = false;
+    bool mayAffectStyleInShadowTree = false;
 
-    bool mayAffectStyle = ruleSets.features().idsInRules.contains(changedId)
-        || mayBeAffectedByHostRules(m_element, changedId, mayAffectShadowTree)
-        || mayBeAffectedBySlottedRules(m_element, changedId);
+    traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) {
+        if (!features.idsInRules.contains(changedId))
+            return;
+        mayAffectStyle = true;
+        if (mayAffectShadowTree)
+            mayAffectStyleInShadowTree = true;
+    });
 
     if (!mayAffectStyle)
         return;
 
-    if (m_element.shadowRoot() && ruleSets.authorStyle().hasShadowPseudoElementRules())
-        mayAffectShadowTree = true;
-
-    if (is<HTMLSlotElement>(m_element) && !ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
-        mayAffectShadowTree = true;
-
-    if (mayAffectShadowTree) {
+    if (mayAffectStyleInShadowTree) {
         m_element.invalidateStyleForSubtree();
         return;
     }
@@ -96,6 +60,7 @@ void IdChangeInvalidation::invalidateStyle(const AtomicString& changedId)
 
     // This could be easily optimized for fine-grained descendant invalidation similar to ClassChangeInvalidation.
     // However using ids for dynamic styling is rare and this is probably not worth the memory cost of the required data structures.
+    auto& ruleSets = m_element.styleResolver().ruleSets();
     bool mayAffectDescendantStyle = ruleSets.features().idsMatchingAncestorsInRules.contains(changedId);
     if (mayAffectDescendantStyle)
         m_element.invalidateStyleForSubtree();
diff --git a/Source/WebCore/style/StyleInvalidationFunctions.h b/Source/WebCore/style/StyleInvalidationFunctions.h
new file mode 100644 (file)
index 0000000..02ffd40
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "DocumentRuleSets.h"
+#include "HTMLSlotElement.h"
+#include "ShadowRoot.h"
+#include "StyleResolver.h"
+#include "StyleScope.h"
+
+namespace WebCore {
+namespace Style {
+
+template <typename TraverseFunction>
+inline void traverseRuleFeaturesInShadowTree(Element& element, TraverseFunction&& function)
+{
+    if (!element.shadowRoot())
+        return;
+    auto& shadowRuleSets = element.shadowRoot()->styleScope().resolver().ruleSets();
+    auto& authorStyle = shadowRuleSets.authorStyle();
+    bool hasHostPseudoClassRulesMatchingInShadowTree = authorStyle.hasHostPseudoClassRulesMatchingInShadowTree();
+    if (authorStyle.hostPseudoClassRules().isEmpty() && !hasHostPseudoClassRulesMatchingInShadowTree)
+        return;
+    function(shadowRuleSets.features(), hasHostPseudoClassRulesMatchingInShadowTree);
+}
+
+template <typename TraverseFunction>
+inline void traverseRuleFeaturesForSlotted(Element& element, TraverseFunction&& function)
+{
+    auto assignedShadowRoots = assignedShadowRootsIfSlotted(element);
+    for (auto& assignedShadowRoot : assignedShadowRoots) {
+        auto& ruleSets = assignedShadowRoot->styleScope().resolver().ruleSets();
+        if (ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
+            continue;
+        function(ruleSets.features(), false);
+    }
+}
+
+template <typename TraverseFunction>
+inline void traverseRuleFeatures(Element& element, TraverseFunction&& function)
+{
+    auto& ruleSets = element.styleResolver().ruleSets();
+
+    auto mayAffectShadowTree = [&] {
+        if (element.shadowRoot() && ruleSets.authorStyle().hasShadowPseudoElementRules())
+            return true;
+        if (is<HTMLSlotElement>(element) && !ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
+            return true;
+        return false;
+    };
+
+    function(ruleSets.features(), mayAffectShadowTree());
+
+    traverseRuleFeaturesInShadowTree(element, function);
+    traverseRuleFeaturesForSlotted(element, function);
+}
+
+}
+}
+