Title: [226703] trunk
Revision
226703
Author
[email protected]
Date
2018-01-10 01:01:53 -0800 (Wed, 10 Jan 2018)

Log Message

Invalidate current element style on class change accurately
https://bugs.webkit.org/show_bug.cgi?id=181210

Reviewed by Zalan Bujtas.

Source/WebCore:

* css/DocumentRuleSets.cpp:
(WebCore::DocumentRuleSets::collectFeatures const):
(WebCore::DocumentRuleSets::subjectClassRules const):

    New rule set containing class rules affecting the subject element.

(WebCore::DocumentRuleSets::ancestorClassRules const):
* css/DocumentRuleSets.h:
* css/RuleFeature.cpp:
(WebCore::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):

    Classify selector components into various buckets based on the elements they match relative to
    the subject element. There are more categories than this patch strictly needs, for future use.

(WebCore::RuleFeatureSet::collectFeatures):
(WebCore::RuleFeatureSet::add):
(WebCore::RuleFeatureSet::clear):
(WebCore::RuleFeatureSet::shrinkToFit):
* css/RuleFeature.h:
* css/StyleResolver.h:
(WebCore::StyleResolver::hasSelectorForClass const): Deleted.
* style/ClassChangeInvalidation.cpp:
(WebCore::Style::elementNeedsInvalidation):
(WebCore::Style::ClassChangeInvalidation::computeInvalidation):

    Don't invalidate current element unconditionally on class change. Instead find the subject rulesets
    that might affect it use them to perform invalidation.

(WebCore::Style::ClassChangeInvalidation::invalidateStyleWithRuleSets):
(WebCore::Style::ClassChangeInvalidation::invalidateStyle): Deleted.
(WebCore::Style::ClassChangeInvalidation::invalidateDescendantStyle): Deleted.
* style/ClassChangeInvalidation.h:
(WebCore::Style::ClassChangeInvalidation::ClassChangeInvalidation):
(WebCore::Style::ClassChangeInvalidation::~ClassChangeInvalidation):
* style/StyleSharingResolver.cpp:
(WebCore::Style::SharingResolver::classNamesAffectedByRules const):

LayoutTests:

* fast/css/set-inline-style-recalc-expected.txt:
* fast/css/set-inline-style-recalc.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (226702 => 226703)


--- trunk/LayoutTests/ChangeLog	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/LayoutTests/ChangeLog	2018-01-10 09:01:53 UTC (rev 226703)
@@ -1,3 +1,13 @@
+2018-01-10  Antti Koivisto  <[email protected]>
+
+        Invalidate current element style on class change accurately
+        https://bugs.webkit.org/show_bug.cgi?id=181210
+
+        Reviewed by Zalan Bujtas.
+
+        * fast/css/set-inline-style-recalc-expected.txt:
+        * fast/css/set-inline-style-recalc.html:
+
 2018-01-09  Antoine Quint  <[email protected]>
 
         [Web Animations] Expose the id property on Animation

Modified: trunk/LayoutTests/fast/css/set-inline-style-recalc-expected.txt (226702 => 226703)


--- trunk/LayoutTests/fast/css/set-inline-style-recalc-expected.txt	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/LayoutTests/fast/css/set-inline-style-recalc-expected.txt	2018-01-10 09:01:53 UTC (rev 226703)
@@ -14,7 +14,7 @@
 PASS numStyleRecalcs is 0
 PASS numStyleRecalcs is 1
 PASS numStyleRecalcs is 0
-PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 0
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/fast/css/set-inline-style-recalc.html (226702 => 226703)


--- trunk/LayoutTests/fast/css/set-inline-style-recalc.html	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/LayoutTests/fast/css/set-inline-style-recalc.html	2018-01-10 09:01:53 UTC (rev 226703)
@@ -69,7 +69,7 @@
 numStyleRecalcs = setStyleAndForceLayout(function() { testContainer.classList.add('foo'); });
 shouldBe("numStyleRecalcs", "0");
 numStyleRecalcs = setStyleAndForceLayout(function() { testContainer.classList.add('bar'); });
-shouldBe("numStyleRecalcs", "1");
+shouldBe("numStyleRecalcs", "0");
 
 document.body.removeChild(testContainer);
 </script>

Modified: trunk/Source/WebCore/ChangeLog (226702 => 226703)


--- trunk/Source/WebCore/ChangeLog	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/ChangeLog	2018-01-10 09:01:53 UTC (rev 226703)
@@ -1,3 +1,47 @@
+2018-01-10  Antti Koivisto  <[email protected]>
+
+        Invalidate current element style on class change accurately
+        https://bugs.webkit.org/show_bug.cgi?id=181210
+
+        Reviewed by Zalan Bujtas.
+
+        * css/DocumentRuleSets.cpp:
+        (WebCore::DocumentRuleSets::collectFeatures const):
+        (WebCore::DocumentRuleSets::subjectClassRules const):
+
+            New rule set containing class rules affecting the subject element.
+
+        (WebCore::DocumentRuleSets::ancestorClassRules const):
+        * css/DocumentRuleSets.h:
+        * css/RuleFeature.cpp:
+        (WebCore::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
+
+            Classify selector components into various buckets based on the elements they match relative to
+            the subject element. There are more categories than this patch strictly needs, for future use.
+
+        (WebCore::RuleFeatureSet::collectFeatures):
+        (WebCore::RuleFeatureSet::add):
+        (WebCore::RuleFeatureSet::clear):
+        (WebCore::RuleFeatureSet::shrinkToFit):
+        * css/RuleFeature.h:
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::hasSelectorForClass const): Deleted.
+        * style/ClassChangeInvalidation.cpp:
+        (WebCore::Style::elementNeedsInvalidation):
+        (WebCore::Style::ClassChangeInvalidation::computeInvalidation):
+
+            Don't invalidate current element unconditionally on class change. Instead find the subject rulesets
+            that might affect it use them to perform invalidation.
+
+        (WebCore::Style::ClassChangeInvalidation::invalidateStyleWithRuleSets):
+        (WebCore::Style::ClassChangeInvalidation::invalidateStyle): Deleted.
+        (WebCore::Style::ClassChangeInvalidation::invalidateDescendantStyle): Deleted.
+        * style/ClassChangeInvalidation.h:
+        (WebCore::Style::ClassChangeInvalidation::ClassChangeInvalidation):
+        (WebCore::Style::ClassChangeInvalidation::~ClassChangeInvalidation):
+        * style/StyleSharingResolver.cpp:
+        (WebCore::Style::SharingResolver::classNamesAffectedByRules const):
+
 2018-01-09  Antoine Quint  <[email protected]>
 
         [Web Animations] Expose the id property on Animation

Modified: trunk/Source/WebCore/css/DocumentRuleSets.cpp (226702 => 226703)


--- trunk/Source/WebCore/css/DocumentRuleSets.cpp	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/css/DocumentRuleSets.cpp	2018-01-10 09:01:53 UTC (rev 226703)
@@ -167,6 +167,7 @@
     m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
     m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
 
+    m_subjectClassRuleSets.clear();
     m_ancestorClassRuleSets.clear();
     m_ancestorAttributeRuleSetsForHTML.clear();
 
@@ -173,14 +174,20 @@
     m_features.shrinkToFit();
 }
 
+RuleSet* DocumentRuleSets::subjectClassRules(const AtomicString& className) const
+{
+    return m_subjectClassRuleSets.ensure(className, [&] {
+        auto* rules = m_features.subjectClassRules.get(className);
+        return rules ? makeRuleSet(*rules) : nullptr;
+    }).iterator->value.get();
+}
+
 RuleSet* DocumentRuleSets::ancestorClassRules(const AtomicString& className) const
 {
-    auto addResult = m_ancestorClassRuleSets.add(className, nullptr);
-    if (addResult.isNewEntry) {
-        if (auto* rules = m_features.ancestorClassRules.get(className))
-            addResult.iterator->value = makeRuleSet(*rules);
-    }
-    return addResult.iterator->value.get();
+    return m_ancestorClassRuleSets.ensure(className, [&] {
+        auto* rules = m_features.ancestorClassRules.get(className);
+        return rules ? makeRuleSet(*rules) : nullptr;
+    }).iterator->value.get();
 }
 
 const DocumentRuleSets::AttributeRules* DocumentRuleSets::ancestorAttributeRulesForHTML(const AtomicString& attributeName) const

Modified: trunk/Source/WebCore/css/DocumentRuleSets.h (226702 => 226703)


--- trunk/Source/WebCore/css/DocumentRuleSets.h	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/css/DocumentRuleSets.h	2018-01-10 09:01:53 UTC (rev 226703)
@@ -50,6 +50,7 @@
     const RuleFeatureSet& features() const;
     RuleSet* sibling() const { return m_siblingRuleSet.get(); }
     RuleSet* uncommonAttribute() const { return m_uncommonAttributeRuleSet.get(); }
+    RuleSet* subjectClassRules(const AtomicString& className) const;
     RuleSet* ancestorClassRules(const AtomicString& className) const;
 
     struct AttributeRules {
@@ -90,6 +91,7 @@
     mutable unsigned m_userAgentMediaQueryRuleCountOnUpdate { 0 };
     mutable std::unique_ptr<RuleSet> m_siblingRuleSet;
     mutable std::unique_ptr<RuleSet> m_uncommonAttributeRuleSet;
+    mutable HashMap<AtomicString, std::unique_ptr<RuleSet>> m_subjectClassRuleSets;
     mutable HashMap<AtomicString, std::unique_ptr<RuleSet>> m_ancestorClassRuleSets;
     mutable HashMap<AtomicString, std::unique_ptr<AttributeRules>> m_ancestorAttributeRuleSetsForHTML;
 };

Modified: trunk/Source/WebCore/css/RuleFeature.cpp (226702 => 226703)


--- trunk/Source/WebCore/css/RuleFeature.cpp	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/css/RuleFeature.cpp	2018-01-10 09:01:53 UTC (rev 226703)
@@ -35,24 +35,78 @@
 
 namespace WebCore {
 
-void RuleFeatureSet::recursivelyCollectFeaturesFromSelector(SelectorFeatures& selectorFeatures, const CSSSelector& firstSelector, bool matchesAncestor)
+RuleFeatureSet::MatchElement RuleFeatureSet::computeNextMatchElement(MatchElement matchElement, CSSSelector::RelationType relation)
 {
+    if (matchElement == MatchElement::Subject || matchElement == MatchElement::IndirectSibling || matchElement == MatchElement::DirectSibling) {
+        switch (relation) {
+        case CSSSelector::Subselector:
+            return matchElement;
+        case CSSSelector::DescendantSpace:
+            return MatchElement::Ancestor;
+        case CSSSelector::Child:
+            return MatchElement::Parent;
+        case CSSSelector::IndirectAdjacent:
+            return MatchElement::IndirectSibling;
+        case CSSSelector::DirectAdjacent:
+            return matchElement == MatchElement::Subject ? MatchElement::DirectSibling : MatchElement::IndirectSibling;
+        case CSSSelector::ShadowDescendant:
+            return MatchElement::Host;
+        };
+    }
+    switch (relation) {
+    case CSSSelector::Subselector:
+        return matchElement;
+    case CSSSelector::DescendantSpace:
+    case CSSSelector::Child:
+        return MatchElement::Ancestor;
+    case CSSSelector::IndirectAdjacent:
+    case CSSSelector::DirectAdjacent:
+        return matchElement == MatchElement::Parent ? MatchElement::ParentSibling : MatchElement::AncestorSibling;
+    case CSSSelector::ShadowDescendant:
+        return MatchElement::Host;
+    };
+};
+
+RuleFeatureSet::MatchElement RuleFeatureSet::computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector)
+{
+    ASSERT(selector.selectorList());
+
+    if (selector.match() == CSSSelector::PseudoClass) {
+        auto type = selector.pseudoClassType();
+        // For :nth-child(n of .some-subselector) where an element change may affect other elements similar to sibling combinators.
+        // FIXME: This is not entirely accurate but good enough for current users.
+        if (type == CSSSelector::PseudoClassNthChild || type == CSSSelector::PseudoClassNthLastChild)
+            return MatchElement::IndirectSibling;
+
+        // Similarly for :host().
+        if (type == CSSSelector::PseudoClassHost)
+            return MatchElement::Host;
+    }
+    if (selector.match() == CSSSelector::PseudoElement) {
+        // Similarly for ::slotted().
+        if (selector.pseudoElementType() == CSSSelector::PseudoElementSlotted)
+            return MatchElement::Host;
+    }
+
+    return matchElement;
+};
+
+void RuleFeatureSet::recursivelyCollectFeaturesFromSelector(SelectorFeatures& selectorFeatures, const CSSSelector& firstSelector, MatchElement matchElement)
+{
     const CSSSelector* selector = &firstSelector;
     do {
         if (selector->match() == CSSSelector::Id) {
             idsInRules.add(selector->value());
-            if (matchesAncestor)
+            if (matchElement == MatchElement::Parent || matchElement == MatchElement::Ancestor)
                 idsMatchingAncestorsInRules.add(selector->value());
-        } else if (selector->match() == CSSSelector::Class) {
-            classesInRules.add(selector->value());
-            if (matchesAncestor)
-                selectorFeatures.classesMatchingAncestors.append(selector->value());
-        } else if (selector->isAttributeSelector()) {
+        } else if (selector->match() == CSSSelector::Class)
+            selectorFeatures.classes.append(std::make_pair(selector->value(), matchElement));
+        else if (selector->isAttributeSelector()) {
             auto& canonicalLocalName = selector->attributeCanonicalLocalName();
             auto& localName = selector->attribute().localName();
             attributeCanonicalLocalNamesInRules.add(canonicalLocalName);
             attributeLocalNamesInRules.add(localName);
-            if (matchesAncestor)
+            if (matchElement == MatchElement::Parent || matchElement == MatchElement::Ancestor)
                 selectorFeatures.attributeSelectorsMatchingAncestors.append(selector);
         } else if (selector->match() == CSSSelector::PseudoElement) {
             switch (selector->pseudoElementType()) {
@@ -71,15 +125,17 @@
             selectorFeatures.hasSiblingSelector = true;
 
         if (const CSSSelectorList* selectorList = selector->selectorList()) {
+            auto subSelectorMatchElement = computeSubSelectorMatchElement(matchElement, *selector);
+
             for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
                 if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector())
                     selectorFeatures.hasSiblingSelector = true;
-                recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, matchesAncestor);
+                recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, subSelectorMatchElement);
             }
         }
-        if (selector->hasDescendantOrChildRelation())
-            matchesAncestor = true;
 
+        matchElement = computeNextMatchElement(matchElement, selector->relation());
+
         selector = selector->tagHistory();
     } while (selector);
 }
@@ -99,11 +155,28 @@
         siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex()));
     if (ruleData.containsUncommonAttributeSelector())
         uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex()));
-    for (auto& className : selectorFeatures.classesMatchingAncestors) {
-        auto addResult = ancestorClassRules.ensure(className, [] {
-            return std::make_unique<Vector<RuleFeature>>();
-        });
-        addResult.iterator->value->append(RuleFeature(ruleData.rule(), ruleData.selectorIndex()));
+    for (auto& classNameAndMatchElement : selectorFeatures.classes) {
+        auto& className = classNameAndMatchElement.first;
+        switch (classNameAndMatchElement.second) {
+        case MatchElement::Subject:
+            subjectClassRules.ensure(className, [] {
+                return std::make_unique<Vector<RuleFeature>>();
+            }).iterator->value->append(RuleFeature(ruleData.rule(), ruleData.selectorIndex()));
+            break;
+        case MatchElement::Parent:
+        case MatchElement::Ancestor:
+            ancestorClassRules.ensure(className, [] {
+                return std::make_unique<Vector<RuleFeature>>();
+            }).iterator->value->append(RuleFeature(ruleData.rule(), ruleData.selectorIndex()));
+            break;
+        case MatchElement::DirectSibling:
+        case MatchElement::IndirectSibling:
+        case MatchElement::ParentSibling:
+        case MatchElement::AncestorSibling:
+        case MatchElement::Host:
+            otherClassesInRules.add(className);
+            break;
+        };
     }
     for (auto* selector : selectorFeatures.attributeSelectorsMatchingAncestors) {
         // Hashing by attributeCanonicalLocalName makes this HTML specific.
@@ -121,17 +194,22 @@
 {
     idsInRules.add(other.idsInRules.begin(), other.idsInRules.end());
     idsMatchingAncestorsInRules.add(other.idsMatchingAncestorsInRules.begin(), other.idsMatchingAncestorsInRules.end());
-    classesInRules.add(other.classesInRules.begin(), other.classesInRules.end());
+    otherClassesInRules.add(other.otherClassesInRules.begin(), other.otherClassesInRules.end());
     attributeCanonicalLocalNamesInRules.add(other.attributeCanonicalLocalNamesInRules.begin(), other.attributeCanonicalLocalNamesInRules.end());
     attributeLocalNamesInRules.add(other.attributeLocalNamesInRules.begin(), other.attributeLocalNamesInRules.end());
     siblingRules.appendVector(other.siblingRules);
     uncommonAttributeRules.appendVector(other.uncommonAttributeRules);
     for (auto& keyValuePair : other.ancestorClassRules) {
-        auto addResult = ancestorClassRules.ensure(keyValuePair.key, [] {
+        ancestorClassRules.ensure(keyValuePair.key, [] {
             return std::make_unique<Vector<RuleFeature>>();
-        });
-        addResult.iterator->value->appendVector(*keyValuePair.value);
+        }).iterator->value->appendVector(*keyValuePair.value);
     }
+    for (auto& keyValuePair : other.subjectClassRules) {
+        subjectClassRules.ensure(keyValuePair.key, [] {
+            return std::make_unique<Vector<RuleFeature>>();
+        }).iterator->value->appendVector(*keyValuePair.value);
+    }
+
     for (auto& keyValuePair : other.ancestorAttributeRulesForHTML) {
         auto addResult = ancestorAttributeRulesForHTML.ensure(keyValuePair.key, [] {
             return std::make_unique<AttributeRules>();
@@ -149,12 +227,13 @@
 {
     idsInRules.clear();
     idsMatchingAncestorsInRules.clear();
-    classesInRules.clear();
+    otherClassesInRules.clear();
     attributeCanonicalLocalNamesInRules.clear();
     attributeLocalNamesInRules.clear();
     siblingRules.clear();
     uncommonAttributeRules.clear();
     ancestorClassRules.clear();
+    subjectClassRules.clear();
     ancestorAttributeRulesForHTML.clear();
     usesFirstLineRules = false;
     usesFirstLetterRules = false;
@@ -166,6 +245,8 @@
     uncommonAttributeRules.shrinkToFit();
     for (auto& rules : ancestorClassRules.values())
         rules->shrinkToFit();
+    for (auto& rules : subjectClassRules.values())
+        rules->shrinkToFit();
     for (auto& rules : ancestorAttributeRulesForHTML.values())
         rules->features.shrinkToFit();
 }

Modified: trunk/Source/WebCore/css/RuleFeature.h (226702 => 226703)


--- trunk/Source/WebCore/css/RuleFeature.h	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/css/RuleFeature.h	2018-01-10 09:01:53 UTC (rev 226703)
@@ -51,12 +51,13 @@
 
     HashSet<AtomicString> idsInRules;
     HashSet<AtomicString> idsMatchingAncestorsInRules;
-    HashSet<AtomicString> classesInRules;
     HashSet<AtomicString> attributeCanonicalLocalNamesInRules;
     HashSet<AtomicString> attributeLocalNamesInRules;
     Vector<RuleFeature> siblingRules;
     Vector<RuleFeature> uncommonAttributeRules;
     HashMap<AtomicString, std::unique_ptr<Vector<RuleFeature>>> ancestorClassRules;
+    HashMap<AtomicString, std::unique_ptr<Vector<RuleFeature>>> subjectClassRules;
+    HashSet<AtomicString> otherClassesInRules;
 
     struct AttributeRules {
         WTF_MAKE_FAST_ALLOCATED;
@@ -70,12 +71,18 @@
     bool usesFirstLetterRules { false };
 
 private:
+    enum class MatchElement { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, ParentSibling, AncestorSibling, Host };
+
+    static MatchElement computeNextMatchElement(MatchElement, CSSSelector::RelationType);
+    static MatchElement computeSubSelectorMatchElement(MatchElement, const CSSSelector&);
+
     struct SelectorFeatures {
         bool hasSiblingSelector { false };
-        Vector<AtomicString, 32> classesMatchingAncestors;
+
+        Vector<std::pair<AtomicString, MatchElement>, 32> classes;
         Vector<const CSSSelector*> attributeSelectorsMatchingAncestors;
     };
-    void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, bool matchesAncestor = false);
+    void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject);
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/css/StyleResolver.h (226702 => 226703)


--- trunk/Source/WebCore/css/StyleResolver.h	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/css/StyleResolver.h	2018-01-10 09:01:53 UTC (rev 226703)
@@ -192,7 +192,6 @@
     Color colorFromPrimitiveValue(const CSSPrimitiveValue&, bool forVisitedLink = false) const;
 
     bool hasSelectorForId(const AtomicString&) const;
-    bool hasSelectorForClass(const AtomicString&) const;
     bool hasSelectorForAttribute(const Element&, const AtomicString&) const;
 
 #if ENABLE(CSS_DEVICE_ADAPTATION)
@@ -521,12 +520,6 @@
     return m_ruleSets.features().attributeLocalNamesInRules.contains(attributeName);
 }
 
-inline bool StyleResolver::hasSelectorForClass(const AtomicString& classValue) const
-{
-    ASSERT(!classValue.isEmpty());
-    return m_ruleSets.features().classesInRules.contains(classValue);
-}
-
 inline bool StyleResolver::hasSelectorForId(const AtomicString& idValue) const
 {
     ASSERT(!idValue.isEmpty());

Modified: trunk/Source/WebCore/style/ClassChangeInvalidation.cpp (226702 => 226703)


--- trunk/Source/WebCore/style/ClassChangeInvalidation.cpp	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/style/ClassChangeInvalidation.cpp	2018-01-10 09:01:53 UTC (rev 226703)
@@ -83,26 +83,35 @@
     return changedClasses;
 }
 
-void ClassChangeInvalidation::invalidateStyle(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
+void ClassChangeInvalidation::computeInvalidation(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
 {
     auto changedClasses = computeClassChange(oldClasses, newClasses);
 
-    ClassChangeVector changedClassesAffectingStyle;
+    bool shouldInvalidateCurrent = false;
     bool mayAffectStyleInShadowTree = false;
+    ClassChangeVector classesAffectingDescendant;
+    ClassChangeVector classesAffectingCurrent;
 
     traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) {
         for (auto* changedClass : changedClasses) {
-            if (!features.classesInRules.contains(changedClass))
-                continue;
-            changedClassesAffectingStyle.append(changedClass);
-            if (mayAffectShadowTree)
+            bool mayAffectStyle = false;
+            if (features.otherClassesInRules.contains(changedClass)) {
+                shouldInvalidateCurrent = true;
+                mayAffectStyle = true;
+            }
+            if (features.ancestorClassRules.contains(changedClass)) {
+                classesAffectingDescendant.append(changedClass);
+                mayAffectStyle = true;
+            }
+            if (features.subjectClassRules.contains(changedClass)) {
+                classesAffectingCurrent.append(changedClass);
+                mayAffectStyle = true;
+            }
+            if (mayAffectStyle && mayAffectShadowTree)
                 mayAffectStyleInShadowTree = true;
         }
     });
 
-    if (changedClassesAffectingStyle.isEmpty())
-        return;
-
     if (mayAffectStyleInShadowTree) {
         // FIXME: We should do fine-grained invalidation for shadow tree.
         m_element.invalidateStyleForSubtree();
@@ -109,24 +118,30 @@
         return;
     }
 
-    m_element.invalidateStyle();
+    auto& ruleSets = m_element.styleResolver().ruleSets();
 
-    if (!childrenOfType<Element>(m_element).first())
+    if (childrenOfType<Element>(m_element).first()) {
+        for (auto* changedClass : classesAffectingDescendant) {
+            if (auto* rules = ruleSets.ancestorClassRules(changedClass))
+                m_invalidationRuleSets.append(rules);
+        }
+    }
+
+    if (shouldInvalidateCurrent) {
+        m_element.invalidateStyle();
         return;
+    }
 
-    auto& ruleSets = m_element.styleResolver().ruleSets();
-    for (auto* changedClass : changedClassesAffectingStyle) {
-        auto* ancestorClassRules = ruleSets.ancestorClassRules(changedClass);
-        if (!ancestorClassRules)
-            continue;
-        m_descendantInvalidationRuleSets.append(ancestorClassRules);
+    for (auto* changedClass : classesAffectingCurrent) {
+        if (auto* rules = ruleSets.subjectClassRules(changedClass))
+            m_invalidationRuleSets.append(rules);
     }
 }
 
-void ClassChangeInvalidation::invalidateDescendantStyle()
+void ClassChangeInvalidation::invalidateStyleWithRuleSets()
 {
-    for (auto* ancestorClassRules : m_descendantInvalidationRuleSets) {
-        Invalidator invalidator(*ancestorClassRules);
+    for (auto* rules : m_invalidationRuleSets) {
+        Invalidator invalidator(*rules);
         invalidator.invalidateStyle(m_element);
     }
 }

Modified: trunk/Source/WebCore/style/ClassChangeInvalidation.h (226702 => 226703)


--- trunk/Source/WebCore/style/ClassChangeInvalidation.h	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/style/ClassChangeInvalidation.h	2018-01-10 09:01:53 UTC (rev 226703)
@@ -42,13 +42,13 @@
     ~ClassChangeInvalidation();
 
 private:
-    void invalidateStyle(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses);
-    void invalidateDescendantStyle();
+    void computeInvalidation(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses);
+    void invalidateStyleWithRuleSets();
 
     const bool m_isEnabled;
     Element& m_element;
 
-    Vector<const RuleSet*, 4> m_descendantInvalidationRuleSets;
+    Vector<const RuleSet*, 4> m_invalidationRuleSets;
 };
 
 inline ClassChangeInvalidation::ClassChangeInvalidation(Element& element, const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
@@ -58,8 +58,8 @@
 {
     if (!m_isEnabled)
         return;
-    invalidateStyle(oldClasses, newClasses);
-    invalidateDescendantStyle();
+    computeInvalidation(oldClasses, newClasses);
+    invalidateStyleWithRuleSets();
 }
 
 inline ClassChangeInvalidation::~ClassChangeInvalidation()
@@ -66,7 +66,7 @@
 {
     if (!m_isEnabled)
         return;
-    invalidateDescendantStyle();
+    invalidateStyleWithRuleSets();
 }
 
 }

Modified: trunk/Source/WebCore/style/StyleSharingResolver.cpp (226702 => 226703)


--- trunk/Source/WebCore/style/StyleSharingResolver.cpp	2018-01-10 08:56:43 UTC (rev 226702)
+++ trunk/Source/WebCore/style/StyleSharingResolver.cpp	2018-01-10 09:01:53 UTC (rev 226703)
@@ -340,8 +340,13 @@
 bool SharingResolver::classNamesAffectedByRules(const SpaceSplitString& classNames) const
 {
     for (unsigned i = 0; i < classNames.size(); ++i) {
-        if (m_ruleSets.features().classesInRules.contains(classNames[i]))
+        if (m_ruleSets.features().otherClassesInRules.contains(classNames[i]))
             return true;
+        if (m_ruleSets.features().ancestorClassRules.contains(classNames[i]))
+            return true;
+        if (m_ruleSets.features().subjectClassRules.contains(classNames[i]))
+            return true;
+
     }
     return false;
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to