From a01775938b37cd5725f52a201852a75dee41c788 Mon Sep 17 00:00:00 2001 From: Anders Hartvoll Ruud Date: Wed, 22 Feb 2023 13:12:52 +0000 Subject: [PATCH] [@scope] Make scoping limit exclusive https://github.com/w3c/csswg-drafts/issues/6577 Fixed: 1417896 Change-Id: I4c51177df78eba71cbbfacb88257bdee91b2039b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4272283 Reviewed-by: Rune Lillesveen Commit-Queue: Anders Hartvoll Ruud Cr-Commit-Position: refs/heads/main@{#1108286} --- .../renderer/core/css/selector_checker.cc | 49 +++++++-------- .../renderer/core/css/selector_checker.h | 4 ++ .../renderer/core/css/style_scope_frame.h | 4 -- .../wpt/css/css-cascade/scope-evaluation.html | 61 ++++++++++++++++++- 4 files changed, 88 insertions(+), 30 deletions(-) diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc index 71fe817f466bab..bd279fb7bc932d 100644 --- a/third_party/blink/renderer/core/css/selector_checker.cc +++ b/third_party/blink/renderer/core/css/selector_checker.cc @@ -2237,8 +2237,7 @@ const StyleScopeActivations& SelectorChecker::EnsureActivations( ? &EnsureActivations(context, *style_scope.Parent()) : MakeGarbageCollected( 1, StyleScopeActivation{nullptr /* scope */, - std::numeric_limits::max(), - false}); + std::numeric_limits::max()}); const StyleScopeActivations* activations = CalculateActivations(context.style_scope_frame->element_, style_scope, *outer_activations, context.style_scope_frame); @@ -2291,39 +2290,31 @@ const StyleScopeActivations* SelectorChecker::CalculateActivations( } // The activations of the parent element are still active for this element, - // unless the activation was limited. + // unless this element is a scoping limit. if (parent_activations) { for (const StyleScopeActivation& activation : *parent_activations) { - if (!activation.limit) { - activations->push_back(StyleScopeActivation{ - activation.root, activation.proximity + 1, false}); + if (!ElementIsScopingLimit(style_scope, activation, element)) { + activations->push_back( + StyleScopeActivation{activation.root, activation.proximity + 1}); } } } // Check if we need to add a new activation for this element. - for (const StyleScopeActivation& activation : outer_activations) { - if (style_scope.From() - ? MatchesWithScope(element, *style_scope.From(), activation.root) - : style_scope.HasImplicitRoot(&element)) { - activations->push_back(StyleScopeActivation{&element, 0, false}); + for (const StyleScopeActivation& outer_activation : outer_activations) { + if (style_scope.From() ? MatchesWithScope(element, *style_scope.From(), + outer_activation.root) + : style_scope.HasImplicitRoot(&element)) { + StyleScopeActivation activation{&element, 0}; + // It's possible for a newly created activation to be immediately + // limited (e.g. @scope (.x) to (.x)). + if (!ElementIsScopingLimit(style_scope, activation, element)) { + activations->push_back(activation); + } break; } // TODO(crbug.com/1280240): Break if we don't depend on :scope. } - - if (style_scope.To()) { - DCHECK(style_scope.From()); - for (StyleScopeActivation& activation : *activations) { - DCHECK(!activation.limit); - if (MatchesWithScope(element, *style_scope.To(), - activation.root.Get())) { - // TODO(crbug.com/1280240): If we don't depend on :scope, just set all - // to limit=true. - activation.limit = true; - } - } - } } // Cache the result if possible. @@ -2350,6 +2341,16 @@ bool SelectorChecker::MatchesWithScope(Element& element, return false; } +bool SelectorChecker::ElementIsScopingLimit( + const StyleScope& style_scope, + const StyleScopeActivation& activation, + Element& element) const { + if (!style_scope.To()) { + return false; + } + return MatchesWithScope(element, *style_scope.To(), activation.root.Get()); +} + bool SelectorChecker::CheckInStyleScope(const SelectorCheckingContext& context, MatchResult& result) const { SelectorCheckingContext local_context(context); diff --git a/third_party/blink/renderer/core/css/selector_checker.h b/third_party/blink/renderer/core/css/selector_checker.h index 60d0ea55d60cd1..832b1f6a0851cf 100644 --- a/third_party/blink/renderer/core/css/selector_checker.h +++ b/third_party/blink/renderer/core/css/selector_checker.h @@ -302,6 +302,10 @@ class CORE_EXPORT SelectorChecker { const StyleScopeActivations& outer_activations, StyleScopeFrame*) const; bool MatchesWithScope(Element&, const CSSSelectorList&, Element* scope) const; + // https://drafts.csswg.org/css-cascade-6/#scoping-limit + bool ElementIsScopingLimit(const StyleScope&, + const StyleScopeActivation&, + Element& element) const; CustomScrollbar* scrollbar_; PartNames* part_names_; diff --git a/third_party/blink/renderer/core/css/style_scope_frame.h b/third_party/blink/renderer/core/css/style_scope_frame.h index 3f9bfd10c3bc5b..849c1e08c816d7 100644 --- a/third_party/blink/renderer/core/css/style_scope_frame.h +++ b/third_party/blink/renderer/core/css/style_scope_frame.h @@ -40,10 +40,6 @@ struct CORE_EXPORT StyleScopeActivation { // The distance to the root, in terms of number of inclusive ancestors // between some subject element and the root. unsigned proximity = 0; - // True if some subject element matches . - // - // https://drafts.csswg.org/css-cascade-6/#typedef-scope-end - bool limit = false; }; using StyleScopeActivations = HeapVector; diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-evaluation.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-evaluation.html index bd20712c7f26c6..48139d048a05e0 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-evaluation.html +++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-evaluation.html @@ -356,11 +356,68 @@ assert_not_green('#adjacent'); assert_green('.a'); assert_green('.a > div'); - assert_green('.b'); + assert_not_green('.b'); assert_not_green('#below'); -}, 'The scoping limit is in scope'); +}, 'The scoping limit is not in scope'); + + + + + + +