Changeset 286365 in webkit


Ignore:
Timestamp:
Dec 1, 2021 9:04:27 AM (8 months ago)
Author:
Antti Koivisto
Message:

[:has() pseudo-class] Sibling combinator invalidation
https://bugs.webkit.org/show_bug.cgi?id=233696

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

  • web-platform-tests/css/selectors/invalidation/has-sibling-expected.txt: Added.
  • web-platform-tests/css/selectors/invalidation/has-sibling.html: Added.

Source/WebCore:

Invalidate style correctly for sibling combinators in :has() arguments.

Also add new MatchElement::HasSiblingDescendant value used for :has() arguments that
match the subject elements siblings descendants, like ':has(~ div .descendant)'.
Use it to avoid unnecessary big tree traversals in simple cases.

Test: imported/w3c/web-platform-tests/css/selectors/invalidation/has-sibling.html

  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::matchHasPseudoClass const):

Minimal traversals for HasSibling and HasSiblingDescendant.

  • style/ChildChangeInvalidation.cpp:

(WebCore::Style::needsTraversal):
(WebCore::Style::needsDescendantTraversal):

  • style/RuleFeature.cpp:

(WebCore::Style::isSiblingOrSubject):
(WebCore::Style::isHasPseudoClassMatchElement):
(WebCore::Style::computeHasPseudoClassMatchElement):

  • style/RuleFeature.h:
  • style/StyleInvalidator.cpp:

(WebCore::Style::Invalidator::invalidateStyleWithMatchElement):

Invalidation traversal.

Location:
trunk
Files:
2 added
7 edited

Legend:

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

    r286363 r286365  
     12021-12-01  Antti Koivisto  <antti@apple.com>
     2
     3        [:has() pseudo-class] Sibling combinator invalidation
     4        https://bugs.webkit.org/show_bug.cgi?id=233696
     5
     6        Reviewed by Simon Fraser.
     7
     8        * web-platform-tests/css/selectors/invalidation/has-sibling-expected.txt: Added.
     9        * web-platform-tests/css/selectors/invalidation/has-sibling.html: Added.
     10
    1112021-12-01  Patrick Griffis  <pgriffis@igalia.com>
    212
  • trunk/Source/WebCore/ChangeLog

    r286364 r286365  
     12021-12-01  Antti Koivisto  <antti@apple.com>
     2
     3        [:has() pseudo-class] Sibling combinator invalidation
     4        https://bugs.webkit.org/show_bug.cgi?id=233696
     5
     6        Reviewed by Simon Fraser.
     7
     8        Invalidate style correctly for sibling combinators in :has() arguments.
     9
     10        Also add new MatchElement::HasSiblingDescendant value used for :has() arguments that
     11        match the subject elements siblings descendants, like ':has(~ div .descendant)'.
     12        Use it to avoid unnecessary big tree traversals in simple cases.
     13
     14        Test: imported/w3c/web-platform-tests/css/selectors/invalidation/has-sibling.html
     15
     16        * css/SelectorChecker.cpp:
     17        (WebCore::SelectorChecker::matchHasPseudoClass const):
     18
     19        Minimal traversals for HasSibling and HasSiblingDescendant.
     20
     21        * style/ChildChangeInvalidation.cpp:
     22        (WebCore::Style::needsTraversal):
     23        (WebCore::Style::needsDescendantTraversal):
     24        * style/RuleFeature.cpp:
     25        (WebCore::Style::isSiblingOrSubject):
     26        (WebCore::Style::isHasPseudoClassMatchElement):
     27        (WebCore::Style::computeHasPseudoClassMatchElement):
     28        * style/RuleFeature.h:
     29        * style/StyleInvalidator.cpp:
     30        (WebCore::Style::Invalidator::invalidateStyleWithMatchElement):
     31
     32        Invalidation traversal.
     33
    1342021-12-01  Youenn Fablet  <youenn@apple.com>
    235
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r286302 r286365  
    13161316            if (checkRelative(*sibling))
    13171317                return true;
     1318        }
     1319        break;
     1320    case Style::MatchElement::HasSiblingDescendant:
     1321        for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
    13181322            if (checkDescendants(*sibling))
    13191323                return true;
    13201324        }
    13211325        break;
     1326
    13221327    default:
    13231328        ASSERT_NOT_REACHED();
  • trunk/Source/WebCore/style/ChildChangeInvalidation.cpp

    r286226 r286365  
    112112    if (features.usesMatchElement(MatchElement::HasDescendant))
    113113        return true;
     114    if (features.usesMatchElement(MatchElement::HasSiblingDescendant))
     115        return true;
    114116    return features.usesMatchElement(MatchElement::HasSibling) && childChange.previousSiblingElement;
    115117};
     
    117119static bool needsDescendantTraversal(const RuleFeatureSet& features)
    118120{
    119     return features.usesMatchElement(MatchElement::HasDescendant);
     121    return features.usesMatchElement(MatchElement::HasDescendant) || features.usesMatchElement(MatchElement::HasSiblingDescendant);
    120122};
    121123
  • trunk/Source/WebCore/style/RuleFeature.cpp

    r286292 r286365  
    5353    case MatchElement::HasChild:
    5454    case MatchElement::HasDescendant:
     55    case MatchElement::HasSiblingDescendant:
    5556        return false;
    5657    }
     
    6263{
    6364    switch (matchElement) {
    64     case MatchElement::HasSibling:
    6565    case MatchElement::HasChild:
    6666    case MatchElement::HasDescendant:
     67    case MatchElement::HasSibling:
     68    case MatchElement::HasSiblingDescendant:
    6769        return true;
    6870    default:
     
    147149    case MatchElement::IndirectSibling:
    148150    case MatchElement::DirectSibling:
     151    case MatchElement::AnySibling:
     152        return MatchElement::HasSibling;
    149153    case MatchElement::ParentSibling:
    150154    case MatchElement::AncestorSibling:
    151     case MatchElement::AnySibling:
    152         return MatchElement::HasSibling;
     155        return MatchElement::HasSiblingDescendant;
    153156    case MatchElement::HasChild:
    154157    case MatchElement::HasDescendant:
    155158    case MatchElement::HasSibling:
     159    case MatchElement::HasSiblingDescendant:
    156160    case MatchElement::Host:
    157161        ASSERT_NOT_REACHED();
  • trunk/Source/WebCore/style/RuleFeature.h

    r286226 r286365  
    3737class RuleData;
    3838
    39 enum class MatchElement : uint8_t { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, AnySibling, ParentSibling, AncestorSibling, HasChild, HasDescendant, HasSibling, Host };
     39enum class MatchElement : uint8_t {
     40    Subject,
     41    Parent,
     42    Ancestor,
     43    DirectSibling,
     44    IndirectSibling,
     45    AnySibling,
     46    ParentSibling,
     47    AncestorSibling,
     48    HasChild,
     49    HasDescendant,
     50    HasSibling,
     51    HasSiblingDescendant,
     52    Host
     53};
    4054constexpr unsigned matchElementCount = static_cast<unsigned>(MatchElement::Host) + 1;
    4155
  • trunk/Source/WebCore/style/StyleInvalidator.cpp

    r286135 r286365  
    323323    }
    324324    case MatchElement::HasSibling: {
     325        if (auto* sibling = element.previousElementSibling()) {
     326            SelectorMatchingState selectorMatchingState;
     327            selectorMatchingState.selectorFilter.pushParentInitializingIfNeeded(*element.parentElement());
     328
     329            for (; sibling; sibling = sibling->previousElementSibling())
     330                invalidateIfNeeded(*sibling, &selectorMatchingState);
     331        }
     332        break;
     333    }
     334    case MatchElement::HasSiblingDescendant: {
     335        Vector<Element*, 16> elementAndAncestors;
     336        elementAndAncestors.append(&element);
     337        for (auto* parent = element.parentElement(); parent; parent = parent->parentElement())
     338            elementAndAncestors.append(parent);
     339
    325340        SelectorMatchingState selectorMatchingState;
    326         for (auto* sibling = element.previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
    327             selectorMatchingState.selectorFilter.popParentsUntil(element.parentElement());
    328             invalidateStyleForDescendants(*sibling, &selectorMatchingState);
     341        for (auto* elementOrAncestor : makeReversedRange(elementAndAncestors)) {
     342            for (auto* sibling = elementOrAncestor->previousElementSibling(); sibling; sibling = sibling->previousElementSibling())
     343                invalidateIfNeeded(*sibling, &selectorMatchingState);
     344
     345            selectorMatchingState.selectorFilter.pushParent(elementOrAncestor);
    329346        }
    330347        break;
Note: See TracChangeset for help on using the changeset viewer.