Changeset 286135 in webkit


Ignore:
Timestamp:
Nov 23, 2021 7:47:54 AM (8 months ago)
Author:
Antti Koivisto
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.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r286094 r286135  
     12021-11-23  Antti Koivisto  <antti@apple.com>
     2
     3        [:has() pseudo-class] Basic invalidation support
     4        https://bugs.webkit.org/show_bug.cgi?id=233443
     5
     6        Reviewed by Alan Bujtas.
     7
     8        * web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt:
     9
    1102021-11-20  Carlos Garcia Campos  <cgarcia@igalia.com>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/attribute-or-elemental-selectors-in-has-expected.txt

    r285921 r286135  
    33PASS initial_color: div#div_child.color
    44PASS initial_color: div#div_grandchild.color
    5 FAIL add .child to #div_child: div#div_subject.color assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)"
     5PASS add .child to #div_child: div#div_subject.color
    66PASS remove .child from #div_child: div#div_subject.color
    77PASS add .child to #div_grandchild: div#div_subject.color
    88PASS remove .child from #div_grandchild: div#div_subject.color
    9 FAIL add .descendant to #div_child: div#div_subject.color assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)"
     9PASS add .descendant to #div_child: div#div_subject.color
    1010PASS remove .descendant from #div_child: div#div_subject.color
    11 FAIL add .descendant to #div_grandchild: div#div_subject.color assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)"
     11PASS add .descendant to #div_grandchild: div#div_subject.color
    1212PASS remove .descendant from #div_grandchild: div#div_subject.color
    13 FAIL set descendant to #div_grandchild[attrname]: div#div_subject.color assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)"
     13PASS set descendant to #div_grandchild[attrname]: div#div_subject.color
    1414PASS clear #div_grandchild[attrname]: div#div_subject.color
    1515FAIL change #div_grandchild to #div_descendant: div#div_subject.color assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)"
  • trunk/Source/WebCore/ChangeLog

    r286134 r286135  
     12021-11-23  Antti Koivisto  <antti@apple.com>
     2
     3        [:has() pseudo-class] Basic invalidation support
     4        https://bugs.webkit.org/show_bug.cgi?id=233443
     5
     6        Reviewed by Alan Bujtas.
     7
     8        Adde RuleSet based invalidation for :has(). This covers class/attribute/pseudo-class cases.
     9
     10        There is also a basic optimization that limits the invalidation scope based on :has() selector
     11        matching child/descedant/sibling.
     12
     13        * style/RuleFeature.cpp:
     14        (WebCore::Style::isSiblingOrSubject):
     15        (WebCore::Style::isHasPseudoClassMatchElement):
     16        (WebCore::Style::RuleFeatureSet::computeNextMatchElement):
     17        (WebCore::Style::RuleFeatureSet::computeSubSelectorMatchElement):
     18
     19        Add new MatchElement types for :has and compute the value. This enables automatic
     20        creation of the required invalidation rule sets.
     21
     22        (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
     23        * style/RuleFeature.h:
     24        * style/StyleInvalidator.cpp:
     25        (WebCore::Style::Invalidator::invalidateStyleWithMatchElement):
     26
     27        Traverse appropriate parent/ancestors/siblings to invalidate.
     28
    1292021-11-23  Antti Koivisto  <antti@apple.com>
    230
  • trunk/Source/WebCore/style/RuleFeature.cpp

    r284973 r286135  
    4444    case MatchElement::DirectSibling:
    4545    case MatchElement::AnySibling:
     46    case MatchElement::HasSibling:
    4647    case MatchElement::Host:
    4748        return true;
     
    5051    case MatchElement::ParentSibling:
    5152    case MatchElement::AncestorSibling:
     53    case MatchElement::HasChild:
     54    case MatchElement::HasDescendant:
    5255        return false;
    5356    }
    5457    ASSERT_NOT_REACHED();
    5558    return false;
     59}
     60
     61static bool isHasPseudoClassMatchElement(MatchElement matchElement)
     62{
     63    switch (matchElement) {
     64    case MatchElement::HasSibling:
     65    case MatchElement::HasChild:
     66    case MatchElement::HasDescendant:
     67        return true;
     68    default:
     69        return false;
     70    }
    5671}
    5772
     
    6883MatchElement RuleFeatureSet::computeNextMatchElement(MatchElement matchElement, CSSSelector::RelationType relation)
    6984{
     85    if (isHasPseudoClassMatchElement(matchElement))
     86        return matchElement;
     87
    7088    if (isSiblingOrSubject(matchElement)) {
    7189        switch (relation) {
     
    112130};
    113131
    114 MatchElement RuleFeatureSet::computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector)
    115 {
    116     ASSERT(selector.selectorList());
    117 
     132MatchElement RuleFeatureSet::computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector, const CSSSelector& childSelector)
     133{
    118134    if (selector.match() == CSSSelector::PseudoClass) {
    119135        auto type = selector.pseudoClassType();
     
    125141        if (type == CSSSelector::PseudoClassHost)
    126142            return MatchElement::Host;
     143
     144        if (type == CSSSelector::PseudoClassHas) {
     145            auto hasMatchElement = MatchElement::Subject;
     146            for (auto* simpleSelector = &childSelector; simpleSelector->tagHistory(); simpleSelector = simpleSelector->tagHistory())
     147                hasMatchElement = computeNextMatchElement(hasMatchElement, simpleSelector->relation());
     148
     149            if (hasMatchElement == MatchElement::Parent)
     150                return MatchElement::HasChild;
     151            if (isSiblingOrSubject(hasMatchElement))
     152                return MatchElement::HasSibling;
     153            return MatchElement::HasDescendant;
     154        }
    127155    }
    128156    if (selector.match() == CSSSelector::PseudoElement) {
     
    169197
    170198        if (const CSSSelectorList* selectorList = selector->selectorList()) {
    171             auto subSelectorMatchElement = computeSubSelectorMatchElement(matchElement, *selector);
    172 
    173199            for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
     200                auto subSelectorMatchElement = computeSubSelectorMatchElement(matchElement, *selector, *subSelector);
    174201                if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector())
    175202                    selectorFeatures.hasSiblingSelector = true;
  • trunk/Source/WebCore/style/RuleFeature.h

    r284857 r286135  
    3737class RuleData;
    3838
    39 enum class MatchElement : uint8_t { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, AnySibling, ParentSibling, AncestorSibling, Host };
     39enum class MatchElement : uint8_t { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, AnySibling, ParentSibling, AncestorSibling, HasChild, HasDescendant, HasSibling, Host };
    4040constexpr unsigned matchElementCount = static_cast<unsigned>(MatchElement::Host) + 1;
    4141
     
    8888private:
    8989    static MatchElement computeNextMatchElement(MatchElement, CSSSelector::RelationType);
    90     static MatchElement computeSubSelectorMatchElement(MatchElement, const CSSSelector&);
     90    static MatchElement computeSubSelectorMatchElement(MatchElement, const CSSSelector&, const CSSSelector& childSelector);
    9191
    9292    struct SelectorFeatures {
  • trunk/Source/WebCore/style/StyleInvalidator.cpp

    r285630 r286135  
    305305        break;
    306306    }
     307    case MatchElement::HasChild: {
     308        if (auto* parent = element.parentElement())
     309            invalidateIfNeeded(*parent, nullptr);
     310        break;
     311    }
     312    case MatchElement::HasDescendant: {
     313        Vector<Element*, 16> ancestors;
     314        for (auto* parent = element.parentElement(); parent; parent = parent->parentElement())
     315            ancestors.append(parent);
     316
     317        SelectorMatchingState selectorMatchingState;
     318        for (auto* ancestor : makeReversedRange(ancestors)) {
     319            invalidateIfNeeded(*ancestor, &selectorMatchingState);
     320            selectorMatchingState.selectorFilter.pushParent(ancestor);
     321        }
     322        break;
     323    }
     324    case MatchElement::HasSibling: {
     325        SelectorMatchingState selectorMatchingState;
     326        for (auto* sibling = element.previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
     327            selectorMatchingState.selectorFilter.popParentsUntil(element.parentElement());
     328            invalidateStyleForDescendants(*sibling, &selectorMatchingState);
     329        }
     330        break;
     331    }
    307332    case MatchElement::Host:
    308333        invalidateInShadowTreeIfNeeded(element);
Note: See TracChangeset for help on using the changeset viewer.