Title: [286135] trunk
Revision
286135
Author
[email protected]
Date
2021-11-23 07:47:54 -0800 (Tue, 23 Nov 2021)

Log Message

[:has() pseudo-class] Basic invalidation support
https://bugs.webkit.org/show_bug.cgi?id=233443

Reviewed by Alan Bujtas.

LayoutTests/imported/w3c:

* web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt:

Source/WebCore:

Adde RuleSet based invalidation for :has(). This covers class/attribute/pseudo-class cases.

There is also a basic optimization that limits the invalidation scope based on :has() selector
matching child/descedant/sibling.

* style/RuleFeature.cpp:
(WebCore::Style::isSiblingOrSubject):
(WebCore::Style::isHasPseudoClassMatchElement):
(WebCore::Style::RuleFeatureSet::computeNextMatchElement):
(WebCore::Style::RuleFeatureSet::computeSubSelectorMatchElement):

Add new MatchElement types for :has and compute the value. This enables automatic
creation of the required invalidation rule sets.

(WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
* style/RuleFeature.h:
* style/StyleInvalidator.cpp:
(WebCore::Style::Invalidator::invalidateStyleWithMatchElement):

Traverse appropriate parent/ancestors/siblings to invalidate.

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (286134 => 286135)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-11-23 15:47:14 UTC (rev 286134)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-11-23 15:47:54 UTC (rev 286135)
@@ -1,3 +1,12 @@
+2021-11-23  Antti Koivisto  <[email protected]>
+
+        [:has() pseudo-class] Basic invalidation support
+        https://bugs.webkit.org/show_bug.cgi?id=233443
+
+        Reviewed by Alan Bujtas.
+
+        * web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt:
+
 2021-11-20  Carlos Garcia Campos  <[email protected]>
 
         Report the initiating url instead of the redirected one

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt (286134 => 286135)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt	2021-11-23 15:47:14 UTC (rev 286134)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt	2021-11-23 15:47:54 UTC (rev 286135)
@@ -2,15 +2,15 @@
 PASS initial_color: div#div_subject.color
 PASS initial_color: div#div_child.color
 PASS initial_color: div#div_grandchild.color
-FAIL add .child to #div_child: div#div_subject.color assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)"
+PASS add .child to #div_child: div#div_subject.color
 PASS remove .child from #div_child: div#div_subject.color
 PASS add .child to #div_grandchild: div#div_subject.color
 PASS remove .child from #div_grandchild: div#div_subject.color
-FAIL add .descendant to #div_child: div#div_subject.color assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)"
+PASS add .descendant to #div_child: div#div_subject.color
 PASS remove .descendant from #div_child: div#div_subject.color
-FAIL add .descendant to #div_grandchild: div#div_subject.color assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)"
+PASS add .descendant to #div_grandchild: div#div_subject.color
 PASS remove .descendant from #div_grandchild: div#div_subject.color
-FAIL set descendant to #div_grandchild[attrname]: div#div_subject.color assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)"
+PASS set descendant to #div_grandchild[attrname]: div#div_subject.color
 PASS clear #div_grandchild[attrname]: div#div_subject.color
 FAIL change #div_grandchild to #div_descendant: div#div_subject.color assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)"
 PASS change #div_descendant to #div_grandchild: div#div_subject.color

Modified: trunk/Source/WebCore/ChangeLog (286134 => 286135)


--- trunk/Source/WebCore/ChangeLog	2021-11-23 15:47:14 UTC (rev 286134)
+++ trunk/Source/WebCore/ChangeLog	2021-11-23 15:47:54 UTC (rev 286135)
@@ -1,5 +1,33 @@
 2021-11-23  Antti Koivisto  <[email protected]>
 
+        [:has() pseudo-class] Basic invalidation support
+        https://bugs.webkit.org/show_bug.cgi?id=233443
+
+        Reviewed by Alan Bujtas.
+
+        Adde RuleSet based invalidation for :has(). This covers class/attribute/pseudo-class cases.
+
+        There is also a basic optimization that limits the invalidation scope based on :has() selector
+        matching child/descedant/sibling.
+
+        * style/RuleFeature.cpp:
+        (WebCore::Style::isSiblingOrSubject):
+        (WebCore::Style::isHasPseudoClassMatchElement):
+        (WebCore::Style::RuleFeatureSet::computeNextMatchElement):
+        (WebCore::Style::RuleFeatureSet::computeSubSelectorMatchElement):
+
+        Add new MatchElement types for :has and compute the value. This enables automatic
+        creation of the required invalidation rule sets.
+
+        (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
+        * style/RuleFeature.h:
+        * style/StyleInvalidator.cpp:
+        (WebCore::Style::Invalidator::invalidateStyleWithMatchElement):
+
+        Traverse appropriate parent/ancestors/siblings to invalidate.
+
+2021-11-23  Antti Koivisto  <[email protected]>
+
         Add :focus-visible to focus bucket in RuleSet
         https://bugs.webkit.org/show_bug.cgi?id=233178
 

Modified: trunk/Source/WebCore/style/RuleFeature.cpp (286134 => 286135)


--- trunk/Source/WebCore/style/RuleFeature.cpp	2021-11-23 15:47:14 UTC (rev 286134)
+++ trunk/Source/WebCore/style/RuleFeature.cpp	2021-11-23 15:47:54 UTC (rev 286135)
@@ -43,6 +43,7 @@
     case MatchElement::IndirectSibling:
     case MatchElement::DirectSibling:
     case MatchElement::AnySibling:
+    case MatchElement::HasSibling:
     case MatchElement::Host:
         return true;
     case MatchElement::Parent:
@@ -49,6 +50,8 @@
     case MatchElement::Ancestor:
     case MatchElement::ParentSibling:
     case MatchElement::AncestorSibling:
+    case MatchElement::HasChild:
+    case MatchElement::HasDescendant:
         return false;
     }
     ASSERT_NOT_REACHED();
@@ -55,6 +58,18 @@
     return false;
 }
 
+static bool isHasPseudoClassMatchElement(MatchElement matchElement)
+{
+    switch (matchElement) {
+    case MatchElement::HasSibling:
+    case MatchElement::HasChild:
+    case MatchElement::HasDescendant:
+        return true;
+    default:
+        return false;
+    }
+}
+
 RuleFeature::RuleFeature(const RuleData& ruleData, std::optional<MatchElement> matchElement)
     : styleRule(&ruleData.styleRule())
     , selectorIndex(ruleData.selectorIndex())
@@ -67,6 +82,9 @@
 
 MatchElement RuleFeatureSet::computeNextMatchElement(MatchElement matchElement, CSSSelector::RelationType relation)
 {
+    if (isHasPseudoClassMatchElement(matchElement))
+        return matchElement;
+
     if (isSiblingOrSubject(matchElement)) {
         switch (relation) {
         case CSSSelector::Subselector:
@@ -111,10 +129,8 @@
     return matchElement;
 };
 
-MatchElement RuleFeatureSet::computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector)
+MatchElement RuleFeatureSet::computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector, const CSSSelector& childSelector)
 {
-    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.
@@ -124,6 +140,18 @@
         // Similarly for :host().
         if (type == CSSSelector::PseudoClassHost)
             return MatchElement::Host;
+
+        if (type == CSSSelector::PseudoClassHas) {
+            auto hasMatchElement = MatchElement::Subject;
+            for (auto* simpleSelector = &childSelector; simpleSelector->tagHistory(); simpleSelector = simpleSelector->tagHistory())
+                hasMatchElement = computeNextMatchElement(hasMatchElement, simpleSelector->relation());
+
+            if (hasMatchElement == MatchElement::Parent)
+                return MatchElement::HasChild;
+            if (isSiblingOrSubject(hasMatchElement))
+                return MatchElement::HasSibling;
+            return MatchElement::HasDescendant;
+        }
     }
     if (selector.match() == CSSSelector::PseudoElement) {
         // Similarly for ::slotted().
@@ -168,9 +196,8 @@
             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)) {
+                auto subSelectorMatchElement = computeSubSelectorMatchElement(matchElement, *selector, *subSelector);
                 if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector())
                     selectorFeatures.hasSiblingSelector = true;
                 recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, subSelectorMatchElement);

Modified: trunk/Source/WebCore/style/RuleFeature.h (286134 => 286135)


--- trunk/Source/WebCore/style/RuleFeature.h	2021-11-23 15:47:14 UTC (rev 286134)
+++ trunk/Source/WebCore/style/RuleFeature.h	2021-11-23 15:47:54 UTC (rev 286135)
@@ -36,7 +36,7 @@
 
 class RuleData;
 
-enum class MatchElement : uint8_t { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, AnySibling, ParentSibling, AncestorSibling, Host };
+enum class MatchElement : uint8_t { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, AnySibling, ParentSibling, AncestorSibling, HasChild, HasDescendant, HasSibling, Host };
 constexpr unsigned matchElementCount = static_cast<unsigned>(MatchElement::Host) + 1;
 
 struct RuleFeature {
@@ -87,7 +87,7 @@
 
 private:
     static MatchElement computeNextMatchElement(MatchElement, CSSSelector::RelationType);
-    static MatchElement computeSubSelectorMatchElement(MatchElement, const CSSSelector&);
+    static MatchElement computeSubSelectorMatchElement(MatchElement, const CSSSelector&, const CSSSelector& childSelector);
 
     struct SelectorFeatures {
         bool hasSiblingSelector { false };

Modified: trunk/Source/WebCore/style/StyleInvalidator.cpp (286134 => 286135)


--- trunk/Source/WebCore/style/StyleInvalidator.cpp	2021-11-23 15:47:14 UTC (rev 286134)
+++ trunk/Source/WebCore/style/StyleInvalidator.cpp	2021-11-23 15:47:54 UTC (rev 286135)
@@ -304,6 +304,31 @@
         }
         break;
     }
+    case MatchElement::HasChild: {
+        if (auto* parent = element.parentElement())
+            invalidateIfNeeded(*parent, nullptr);
+        break;
+    }
+    case MatchElement::HasDescendant: {
+        Vector<Element*, 16> ancestors;
+        for (auto* parent = element.parentElement(); parent; parent = parent->parentElement())
+            ancestors.append(parent);
+
+        SelectorMatchingState selectorMatchingState;
+        for (auto* ancestor : makeReversedRange(ancestors)) {
+            invalidateIfNeeded(*ancestor, &selectorMatchingState);
+            selectorMatchingState.selectorFilter.pushParent(ancestor);
+        }
+        break;
+    }
+    case MatchElement::HasSibling: {
+        SelectorMatchingState selectorMatchingState;
+        for (auto* sibling = element.previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
+            selectorMatchingState.selectorFilter.popParentsUntil(element.parentElement());
+            invalidateStyleForDescendants(*sibling, &selectorMatchingState);
+        }
+        break;
+    }
     case MatchElement::Host:
         invalidateInShadowTreeIfNeeded(element);
         break;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to