Branch: refs/heads/main Home: https://github.com/WebKit/WebKit Commit: 3724105055b3d155fee1da5604623c6200cf1f28 https://github.com/WebKit/WebKit/commit/3724105055b3d155fee1da5604623c6200cf1f28 Author: Cameron McCormack <hey...@apple.com> Date: 2023-09-15 (Fri, 15 Sep 2023)
Changed paths: M LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/is-pseudo-containing-complex-in-has-expected.txt M LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/not-pseudo-containing-complex-in-has-expected.txt M Source/WebCore/style/ChildChangeInvalidation.cpp M Source/WebCore/style/ChildChangeInvalidation.h M Source/WebCore/style/ClassChangeInvalidation.cpp M Source/WebCore/style/RuleFeature.cpp M Source/WebCore/style/RuleFeature.h M Source/WebCore/style/StyleInvalidator.cpp M Source/WebCore/style/StyleInvalidator.h M Source/WebCore/style/StyleScopeRuleSets.cpp M Source/WebCore/style/StyleScopeRuleSets.h Log Message: ----------- Invalidate scope-breaking :has(:is(...)) selectors more thoroughly https://bugs.webkit.org/show_bug.cgi?id=253944 rdar://106768250 Reviewed by Antti Koivisto. It's possible to write :has() selectors with arguments that can match elements outside of the :has scope, such as :has(:is(.x .y)) which could match the .x against an ancestor of the :has scope, and :has(~ :is(.x .y)) which could match the .x against an ancestor of a later sibling of the :has scope. We currently handle scope breaking :has() selectors by generating RuleFeatures based on the nested selectors' features and storing them with MatchElement::HasNonSubjectOrScopeBreaking, which causes invalidation to match the inner scope-breaking selector (the :is()) against all elements in the document. Because we store these in InvalidationRuleSets keyed off the nested selectors' features, it means that for the above examples, we will process these document-wide invalidations whenever a class name changes to or from x or y. But this is not sufficient to invalidate for selectors like :has(:is(.x + .y .z)) where if the .x and .y elements are outside the :has scope, an element insertion or removal between them will not find any relevant invalidation rule sets, and :has(~ :is(.x ~ .y)) for similar reasons. This PR changes how we collect scope breaking :has() rules, so that in addition to generating entries in m_hasPseudoClassInvalidationRuleSets on Style::ScopeRuleSet, we also record them in a new m_scopeBreakingHasPseudoClassInvalidationRuleSet, which we look up for every element insertion or removal. For simplicity, we do this more drastic invalidation for both of the above cases. MatchElement::HasNonSubjectOrScopeBreaking is split into two separate values -- HasNonSubject and HasScopeBreaking -- where only the latter causes an entry to be added to m_scopeBreakingHasPseudoClassInvalidationRuleSet. This change does not regress the performance of invalidation of :has() selectors that do not contain logical combination pseudo-classes like :is() and :not(), or which have do have one but do not have any selector combinators inside them. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/is-pseudo-containing-complex-in-has-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/not-pseudo-containing-complex-in-has-expected.txt: * Source/WebCore/style/ChildChangeInvalidation.cpp: (WebCore::Style::ChildChangeInvalidation::invalidateForChangedElement): (WebCore::Style::ChildChangeInvalidation::invalidateForChangeOutsideHasScope): (WebCore::Style::ChildChangeInvalidation::invalidateForHasBeforeMutation): (WebCore::Style::ChildChangeInvalidation::invalidateForHasAfterMutation): (WebCore::Style::needsDescendantTraversal): * Source/WebCore/style/ChildChangeInvalidation.h: * Source/WebCore/style/ClassChangeInvalidation.cpp: (WebCore::Style::ClassChangeInvalidation::computeInvalidation): * Source/WebCore/style/RuleFeature.cpp: (WebCore::Style::isSiblingOrSubject): (WebCore::Style::isHasPseudoClassMatchElement): (WebCore::Style::isScopeBreaking): (WebCore::Style::computeNextHasPseudoClassMatchElement): (WebCore::Style::computeHasPseudoClassMatchElement): (WebCore::Style::computeSubSelectorMatchElement): (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector): (WebCore::Style::RuleFeatureSet::collectFeatures): (WebCore::Style::RuleFeatureSet::add): (WebCore::Style::RuleFeatureSet::clear): (WebCore::Style::RuleFeatureSet::shrinkToFit): * Source/WebCore/style/RuleFeature.h: (WebCore::Style::RuleFeatureSet::usesMatchElement const): (WebCore::Style::RuleFeatureSet::usesHasPseudoClass const): * Source/WebCore/style/StyleInvalidator.cpp: (WebCore::Style::Invalidator::invalidateStyleWithMatchElement): (WebCore::Style::Invalidator::invalidateWithScopeBreakingHasPseudoClassRuleSet): * Source/WebCore/style/StyleInvalidator.h: * Source/WebCore/style/StyleScopeRuleSets.cpp: (WebCore::Style::ScopeRuleSets::collectFeatures const): * Source/WebCore/style/StyleScopeRuleSets.h: (WebCore::Style::ScopeRuleSets::scopeBreakingHasPseudoClassInvalidationRuleSet const): Canonical link: https://commits.webkit.org/268038@main _______________________________________________ webkit-changes mailing list webkit-changes@lists.webkit.org https://lists.webkit.org/mailman/listinfo/webkit-changes