Title: [287973] trunk/Source/WebCore
Revision
287973
Author
an...@apple.com
Date
2022-01-12 23:31:50 -0800 (Wed, 12 Jan 2022)

Log Message

[:has() pseudo-class] Collect invalidation selectors for child invalidation
https://bugs.webkit.org/show_bug.cgi?id=235103

Reviewed by Dean Jackson.

Collect selectors we can use to test if :has status actually changed before invalidating.

This patch doesn't yet use the the selector.

* style/ChildChangeInvalidation.cpp:
(WebCore::Style::ChildChangeInvalidation::invalidateForChangedElement):

Use the pseudo class invalidation keys for looking up :has selectors too
instead of having a custom mechanism for doing the same thing.

* style/PseudoClassChangeInvalidation.cpp:
(WebCore::Style::makePseudoClassInvalidationKeys):
* style/PseudoClassChangeInvalidation.h:
* style/RuleFeature.cpp:
(WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):

Always return a selector for consistency.

(WebCore::Style::makePseudoClassInvalidationKey):
(WebCore::Style::RuleFeatureSet::collectFeatures):
(WebCore::Style::RuleFeatureSet::add):
(WebCore::Style::RuleFeatureSet::clear):
(WebCore::Style::RuleFeatureSet::shrinkToFit):
* style/RuleFeature.h:
* style/StyleScopeRuleSets.cpp:
(WebCore::Style::ScopeRuleSets::collectFeatures const):
(WebCore::Style::ScopeRuleSets::hasPseudoClassInvalidationRuleSets const):
(WebCore::Style::ScopeRuleSets::tagInvalidationRuleSets const): Deleted.

We don't need keep around tag rule sets anymore.

* style/StyleScopeRuleSets.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (287972 => 287973)


--- trunk/Source/WebCore/ChangeLog	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/ChangeLog	2022-01-13 07:31:50 UTC (rev 287973)
@@ -1,3 +1,43 @@
+2022-01-12  Antti Koivisto  <an...@apple.com>
+
+        [:has() pseudo-class] Collect invalidation selectors for child invalidation
+        https://bugs.webkit.org/show_bug.cgi?id=235103
+
+        Reviewed by Dean Jackson.
+
+        Collect selectors we can use to test if :has status actually changed before invalidating.
+
+        This patch doesn't yet use the the selector.
+
+        * style/ChildChangeInvalidation.cpp:
+        (WebCore::Style::ChildChangeInvalidation::invalidateForChangedElement):
+
+        Use the pseudo class invalidation keys for looking up :has selectors too
+        instead of having a custom mechanism for doing the same thing.
+
+        * style/PseudoClassChangeInvalidation.cpp:
+        (WebCore::Style::makePseudoClassInvalidationKeys):
+        * style/PseudoClassChangeInvalidation.h:
+        * style/RuleFeature.cpp:
+        (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
+
+        Always return a selector for consistency.
+
+        (WebCore::Style::makePseudoClassInvalidationKey):
+        (WebCore::Style::RuleFeatureSet::collectFeatures):
+        (WebCore::Style::RuleFeatureSet::add):
+        (WebCore::Style::RuleFeatureSet::clear):
+        (WebCore::Style::RuleFeatureSet::shrinkToFit):
+        * style/RuleFeature.h:
+        * style/StyleScopeRuleSets.cpp:
+        (WebCore::Style::ScopeRuleSets::collectFeatures const):
+        (WebCore::Style::ScopeRuleSets::hasPseudoClassInvalidationRuleSets const):
+        (WebCore::Style::ScopeRuleSets::tagInvalidationRuleSets const): Deleted.
+
+        We don't need keep around tag rule sets anymore.
+
+        * style/StyleScopeRuleSets.h:
+
 2022-01-12  John Wilander  <wilan...@apple.com>
 
         PCM: Same-site triggering events should support ephemeral measurement

Modified: trunk/Source/WebCore/style/ChildChangeInvalidation.cpp (287972 => 287973)


--- trunk/Source/WebCore/style/ChildChangeInvalidation.cpp	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/ChildChangeInvalidation.cpp	2022-01-13 07:31:50 UTC (rev 287973)
@@ -28,6 +28,7 @@
 
 #include "ElementTraversal.h"
 #include "NodeRenderStyle.h"
+#include "PseudoClassChangeInvalidation.h"
 #include "ShadowRoot.h"
 #include "SlotAssignment.h"
 #include "StyleResolver.h"
@@ -44,42 +45,27 @@
 
     bool isDescendant = changedElement.parentElement() != &parentElement();
 
+    auto canAffectAncestors = [&](MatchElement matchElement) {
+        if (!isDescendant)
+            return true;
+        return matchElement == MatchElement::HasDescendant
+            || matchElement == MatchElement::HasSiblingDescendant
+            || matchElement == MatchElement::HasNonSubject;
+    };
+
     auto addHasInvalidation = [&](const Vector<InvalidationRuleSet>* invalidationRuleSets)  {
         if (!invalidationRuleSets)
             return;
         for (auto& invalidationRuleSet : *invalidationRuleSets) {
-            if (!isHasPseudoClassMatchElement(invalidationRuleSet.matchElement))
+            if (!canAffectAncestors(invalidationRuleSet.matchElement))
                 continue;
-            if (isDescendant) {
-                // Elements deeper in the tree can't affect anything except when :has() selector uses descendant combinator.
-                if (invalidationRuleSet.matchElement != MatchElement::HasDescendant && invalidationRuleSet.matchElement != MatchElement::HasNonSubject)
-                    continue;
-            }
             Invalidator::addToMatchElementRuleSets(matchElementRuleSets, invalidationRuleSet);
         }
     };
 
-    auto tagName = changedElement.localName().convertToASCIILowercase();
-    addHasInvalidation(ruleSets.tagInvalidationRuleSets(tagName));
+    for (auto key : makePseudoClassInvalidationKeys(CSSSelector::PseudoClassHas, changedElement))
+        addHasInvalidation(ruleSets.hasPseudoClassInvalidationRuleSets(key));
 
-    if (changedElement.hasID())
-        addHasInvalidation(ruleSets.idInvalidationRuleSets(changedElement.idForStyleResolution()));
-
-    if (changedElement.hasAttributes()) {
-        for (auto& attribute : changedElement.attributesIterator()) {
-            auto attributeName = attribute.localName().convertToASCIILowercase();
-            addHasInvalidation(ruleSets.attributeInvalidationRuleSets(attributeName));
-        }
-    }
-
-    if (changedElement.hasClass()) {
-        auto count = changedElement.classNames().size();
-        for (size_t i = 0; i < count; ++i) {
-            auto& className = changedElement.classNames()[i];
-            addHasInvalidation(ruleSets.classInvalidationRuleSets(className));
-        }
-    }
-
     Invalidator::invalidateWithMatchElementRuleSets(changedElement, matchElementRuleSets);
 }
 

Modified: trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp (287972 => 287973)


--- trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp	2022-01-13 07:31:50 UTC (rev 287973)
@@ -32,7 +32,7 @@
 namespace WebCore {
 namespace Style {
 
-static Vector<PseudoClassInvalidationKey, 4> makePseudoClassInvalidationKeys(CSSSelector::PseudoClassType pseudoClass, const Element& element)
+Vector<PseudoClassInvalidationKey, 4> makePseudoClassInvalidationKeys(CSSSelector::PseudoClassType pseudoClass, const Element& element)
 {
     Vector<PseudoClassInvalidationKey, 4> keys;
 

Modified: trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h (287972 => 287973)


--- trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h	2022-01-13 07:31:50 UTC (rev 287973)
@@ -53,6 +53,8 @@
     Invalidator::MatchElementRuleSets m_afterChangeRuleSets;
 };
 
+Vector<PseudoClassInvalidationKey, 4> makePseudoClassInvalidationKeys(CSSSelector::PseudoClassType, const Element&);
+
 inline void emplace(std::optional<PseudoClassChangeInvalidation>& invalidation, Element& element, std::initializer_list<std::pair<CSSSelector::PseudoClassType, bool>> pseudoClasses)
 {
     invalidation.emplace(element, pseudoClasses);

Modified: trunk/Source/WebCore/style/RuleFeature.cpp (287972 => 287973)


--- trunk/Source/WebCore/style/RuleFeature.cpp	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/RuleFeature.cpp	2022-01-13 07:31:50 UTC (rev 287973)
@@ -216,13 +216,10 @@
             if (matchElement == MatchElement::Parent || matchElement == MatchElement::Ancestor)
                 idsMatchingAncestorsInRules.add(selector->value());
             else if (isHasPseudoClassMatchElement(matchElement))
-                selectorFeatures.ids.append({ selector->value(), matchElement, isNegation });
+                selectorFeatures.ids.append({ selector, matchElement, isNegation });
         } else if (selector->match() == CSSSelector::Class)
-            selectorFeatures.classes.append({ selector->value(), matchElement, isNegation });
-        else if (selector->match() == CSSSelector::Tag) {
-            if (isHasPseudoClassMatchElement(matchElement))
-                selectorFeatures.tags.append({ selector->tagLowercaseLocalName(), matchElement, isNegation });
-        } else if (selector->isAttributeSelector()) {
+            selectorFeatures.classes.append({ selector, matchElement, isNegation });
+        else if (selector->isAttributeSelector()) {
             auto& canonicalLocalName = selector->attributeCanonicalLocalName();
             auto& localName = selector->attribute().localName();
             attributeCanonicalLocalNamesInRules.add(canonicalLocalName);
@@ -257,6 +254,9 @@
                 if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector())
                     selectorFeatures.hasSiblingSelector = true;
                 recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, subSelectorMatchElement, subSelectorIsNegation);
+
+                if (selector->match() == CSSSelector::PseudoClass && selector->pseudoClassType() == CSSSelector::PseudoClassHas)
+                    selectorFeatures.hasPseudoClasses.append({ subSelector, subSelectorMatchElement, isNegation });
             }
         }
 
@@ -276,12 +276,8 @@
     };
 };
 
-static PseudoClassInvalidationKey makePseudoClassInvalidationKey(const CSSSelector& selector)
+static PseudoClassInvalidationKey makePseudoClassInvalidationKey(CSSSelector::PseudoClassType pseudoClassType, const CSSSelector& selector)
 {
-    ASSERT(selector.match() == CSSSelector::PseudoClass);
-
-    auto pseudoClassType = selector.pseudoClassType();
-
     AtomString className;
     AtomString tagName;
     for (auto* simpleSelector = selector.firstInCompound(); simpleSelector; simpleSelector = simpleSelector->tagHistory()) {
@@ -303,7 +299,7 @@
     if (!tagName.isEmpty() && tagName != starAtom())
         return makePseudoClassInvalidationKey(pseudoClassType, InvalidationKeyType::Tag, tagName);
 
-    return makePseudoClassInvalidationKey(selector.pseudoClassType(), InvalidationKeyType::Universal);
+    return makePseudoClassInvalidationKey(pseudoClassType, InvalidationKeyType::Universal);
 };
 
 void RuleFeatureSet::collectFeatures(const RuleData& ruleData)
@@ -317,7 +313,9 @@
 
     auto addToMap = [&](auto& map, auto& entries, auto hostAffectingNames) {
         for (auto& entry : entries) {
-            auto& [name, matchElement, isNegation] = entry;
+            auto& [selector, matchElement, isNegation] = entry;
+            auto& name = selector->value();
+
             map.ensure(name, [] {
                 return makeUnique<RuleFeatureVector>();
             }).iterator->value->append({ ruleData, matchElement, isNegation });
@@ -331,7 +329,6 @@
         }
     };
 
-    addToMap(tagRules, selectorFeatures.tags, nullptr);
     addToMap(idRules, selectorFeatures.ids, nullptr);
     addToMap(classRules, selectorFeatures.classes, &classesAffectingHost);
 
@@ -347,7 +344,7 @@
 
     for (auto& entry : selectorFeatures.pseudoClasses) {
         auto [selector, matchElement, isNegation] = entry;
-        pseudoClassRules.ensure(makePseudoClassInvalidationKey(*selector), [] {
+        pseudoClassRules.ensure(makePseudoClassInvalidationKey(selector->pseudoClassType(), *selector), [] {
             return makeUnique<Vector<RuleFeature>>();
         }).iterator->value->append({ ruleData, matchElement, isNegation });
 
@@ -357,6 +354,16 @@
 
         setUsesMatchElement(matchElement);
     }
+
+    for (auto& entry : selectorFeatures.hasPseudoClasses) {
+        auto [selector, matchElement, isNegation] = entry;
+        // The selector argument points to a selector inside :has() selector list instead of :has() itself.
+        hasPseudoClassRules.ensure(makePseudoClassInvalidationKey(CSSSelector::PseudoClassHas, *selector), [] {
+            return makeUnique<Vector<RuleFeatureWithInvalidationSelector>>();
+        }).iterator->value->append({ ruleData, matchElement, isNegation, selector });
+
+        setUsesMatchElement(matchElement);
+    }
 }
 
 void RuleFeatureSet::add(const RuleFeatureSet& other)
@@ -377,7 +384,6 @@
         }
     };
 
-    addMap(tagRules, other.tagRules);
     addMap(idRules, other.idRules);
 
     addMap(classRules, other.classRules);
@@ -390,6 +396,8 @@
     pseudoClassesAffectingHost.add(other.pseudoClassesAffectingHost.begin(), other.pseudoClassesAffectingHost.end());
     pseudoClassTypes.add(other.pseudoClassTypes.begin(), other.pseudoClassTypes.end());
 
+    addMap(hasPseudoClassRules, other.hasPseudoClassRules);
+
     for (size_t i = 0; i < usedMatchElements.size(); ++i)
         usedMatchElements[i] = usedMatchElements[i] || other.usedMatchElements[i];
 
@@ -413,9 +421,9 @@
     contentAttributeNamesInRules.clear();
     siblingRules.clear();
     uncommonAttributeRules.clear();
-    tagRules.clear();
     idRules.clear();
     classRules.clear();
+    hasPseudoClassRules.clear();
     classesAffectingHost.clear();
     attributeRules.clear();
     attributesAffectingHost.clear();
@@ -430,8 +438,6 @@
 {
     siblingRules.shrinkToFit();
     uncommonAttributeRules.shrinkToFit();
-    for (auto& rules : tagRules.values())
-        rules->shrinkToFit();
     for (auto& rules : idRules.values())
         rules->shrinkToFit();
     for (auto& rules : classRules.values())
@@ -440,6 +446,8 @@
         rules->shrinkToFit();
     for (auto& rules : pseudoClassRules.values())
         rules->shrinkToFit();
+    for (auto& rules : hasPseudoClassRules.values())
+        rules->shrinkToFit();
 }
 
 } // namespace Style

Modified: trunk/Source/WebCore/style/RuleFeature.h (287972 => 287973)


--- trunk/Source/WebCore/style/RuleFeature.h	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/RuleFeature.h	2022-01-13 07:31:50 UTC (rev 287973)
@@ -105,11 +105,12 @@
     Vector<RuleAndSelector> siblingRules;
     Vector<RuleAndSelector> uncommonAttributeRules;
 
-    HashMap<AtomString, std::unique_ptr<RuleFeatureVector>> tagRules;
     HashMap<AtomString, std::unique_ptr<RuleFeatureVector>> idRules;
     HashMap<AtomString, std::unique_ptr<RuleFeatureVector>> classRules;
     HashMap<AtomString, std::unique_ptr<Vector<RuleFeatureWithInvalidationSelector>>> attributeRules;
     HashMap<PseudoClassInvalidationKey, std::unique_ptr<RuleFeatureVector>> pseudoClassRules;
+    HashMap<PseudoClassInvalidationKey, std::unique_ptr<Vector<RuleFeatureWithInvalidationSelector>>> hasPseudoClassRules;
+
     HashSet<AtomString> classesAffectingHost;
     HashSet<AtomString> attributesAffectingHost;
     HashSet<CSSSelector::PseudoClassType, IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> pseudoClassesAffectingHost;
@@ -124,13 +125,15 @@
     struct SelectorFeatures {
         bool hasSiblingSelector { false };
 
-        Vector<std::tuple<AtomString, MatchElement, IsNegation>, 32> tags;
-        Vector<std::tuple<AtomString, MatchElement, IsNegation>, 32> ids;
-        Vector<std::tuple<AtomString, MatchElement, IsNegation>, 32> classes;
-        Vector<std::tuple<const CSSSelector*, MatchElement, IsNegation>, 32> attributes;
-        Vector<std::tuple<const CSSSelector*, MatchElement, IsNegation>, 32> pseudoClasses;
+        using InvalidationFeature = std::tuple<const CSSSelector*, MatchElement, IsNegation>;
+
+        Vector<InvalidationFeature> ids;
+        Vector<InvalidationFeature> classes;
+        Vector<InvalidationFeature> attributes;
+        Vector<InvalidationFeature> pseudoClasses;
+        Vector<InvalidationFeature> hasPseudoClasses;
     };
-    void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject, IsNegation =  IsNegation::No);
+    void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject, IsNegation = IsNegation::No);
 };
 
 bool isHasPseudoClassMatchElement(MatchElement);

Modified: trunk/Source/WebCore/style/StyleScopeRuleSets.cpp (287972 => 287973)


--- trunk/Source/WebCore/style/StyleScopeRuleSets.cpp	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/StyleScopeRuleSets.cpp	2022-01-13 07:31:50 UTC (rev 287973)
@@ -221,11 +221,11 @@
     m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
     m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
 
-    m_tagInvalidationRuleSets.clear();
     m_idInvalidationRuleSets.clear();
     m_classInvalidationRuleSets.clear();
     m_attributeInvalidationRuleSets.clear();
     m_pseudoClassInvalidationRuleSets.clear();
+    m_hasPseudoClassInvalidationRuleSets.clear();
 
     m_cachedHasComplexSelectorsForStyleAttribute = std::nullopt;
 
@@ -272,11 +272,6 @@
     }).iterator->value.get();
 }
 
-const Vector<InvalidationRuleSet>* ScopeRuleSets::tagInvalidationRuleSets(const AtomString& tagName) const
-{
-    return ensureInvalidationRuleSets(tagName, m_tagInvalidationRuleSets, m_features.tagRules);
-}
-
 const Vector<InvalidationRuleSet>* ScopeRuleSets::idInvalidationRuleSets(const AtomString& id) const
 {
     return ensureInvalidationRuleSets(id, m_idInvalidationRuleSets, m_features.idRules);
@@ -297,6 +292,11 @@
     return ensureInvalidationRuleSets(pseudoClassKey, m_pseudoClassInvalidationRuleSets, m_features.pseudoClassRules);
 }
 
+const Vector<InvalidationRuleSet>* ScopeRuleSets::hasPseudoClassInvalidationRuleSets(const PseudoClassInvalidationKey& key) const
+{
+    return ensureInvalidationRuleSets(key, m_hasPseudoClassInvalidationRuleSets, m_features.hasPseudoClassRules);
+}
+
 bool ScopeRuleSets::hasComplexSelectorsForStyleAttribute() const
 {
     auto compute = [&] {

Modified: trunk/Source/WebCore/style/StyleScopeRuleSets.h (287972 => 287973)


--- trunk/Source/WebCore/style/StyleScopeRuleSets.h	2022-01-13 07:10:04 UTC (rev 287972)
+++ trunk/Source/WebCore/style/StyleScopeRuleSets.h	2022-01-13 07:31:50 UTC (rev 287973)
@@ -62,14 +62,12 @@
     RuleSet* sibling() const { return m_siblingRuleSet.get(); }
     RuleSet* uncommonAttribute() const { return m_uncommonAttributeRuleSet.get(); }
 
-    const Vector<InvalidationRuleSet>* tagInvalidationRuleSets(const AtomString&) const;
     const Vector<InvalidationRuleSet>* idInvalidationRuleSets(const AtomString&) const;
     const Vector<InvalidationRuleSet>* classInvalidationRuleSets(const AtomString&) const;
     const Vector<InvalidationRuleSet>* attributeInvalidationRuleSets(const AtomString&) const;
     const Vector<InvalidationRuleSet>* pseudoClassInvalidationRuleSets(const PseudoClassInvalidationKey&) const;
+    const Vector<InvalidationRuleSet>* hasPseudoClassInvalidationRuleSets(const PseudoClassInvalidationKey&) const;
 
-    const Vector<InvalidationRuleSet>* invalidationRuleSetsForChildChange(const Element&);
-
     bool hasComplexSelectorsForStyleAttribute() const;
 
     void setUsesSharedUserStyle(bool b) { m_usesSharedUserStyle = b; }
@@ -101,11 +99,11 @@
     mutable RuleFeatureSet m_features;
     mutable RefPtr<RuleSet> m_siblingRuleSet;
     mutable RefPtr<RuleSet> m_uncommonAttributeRuleSet;
-    mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_tagInvalidationRuleSets;
     mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_idInvalidationRuleSets;
     mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_classInvalidationRuleSets;
     mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_attributeInvalidationRuleSets;
     mutable HashMap<PseudoClassInvalidationKey, std::unique_ptr<Vector<InvalidationRuleSet>>> m_pseudoClassInvalidationRuleSets;
+    mutable HashMap<PseudoClassInvalidationKey, std::unique_ptr<Vector<InvalidationRuleSet>>> m_hasPseudoClassInvalidationRuleSets;
 
     mutable std::optional<bool> m_cachedHasComplexSelectorsForStyleAttribute;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to