[go: nahoru, domu]

Skip to content

Commit

Permalink
[@scope] Make scoping limit exclusive
Browse files Browse the repository at this point in the history
w3c/csswg-drafts#6577

Fixed: 1417896
Change-Id: I4c51177df78eba71cbbfacb88257bdee91b2039b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4272283
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1108286}
  • Loading branch information
andruud authored and Chromium LUCI CQ committed Feb 22, 2023
1 parent 2d22913 commit a017759
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 30 deletions.
49 changes: 25 additions & 24 deletions third_party/blink/renderer/core/css/selector_checker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2237,8 +2237,7 @@ const StyleScopeActivations& SelectorChecker::EnsureActivations(
? &EnsureActivations(context, *style_scope.Parent())
: MakeGarbageCollected<StyleScopeActivations>(
1, StyleScopeActivation{nullptr /* scope */,
std::numeric_limits<unsigned>::max(),
false});
std::numeric_limits<unsigned>::max()});
const StyleScopeActivations* activations =
CalculateActivations(context.style_scope_frame->element_, style_scope,
*outer_activations, context.style_scope_frame);
Expand Down Expand Up @@ -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.
Expand All @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions third_party/blink/renderer/core/css/selector_checker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
4 changes: 0 additions & 4 deletions third_party/blink/renderer/core/css/style_scope_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <scope-end>.
//
// https://drafts.csswg.org/css-cascade-6/#typedef-scope-end
bool limit = false;
};

using StyleScopeActivations = HeapVector<StyleScopeActivation>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
</script>

<template>
<style>
@scope (.a) to (.b > *) {
* { background-color: green; }
}
</style>
<div id=above>
<div class=a>
<div>
<div class=b>
<div id=limit></div>
</div>
</div>
</div>
<div id=adjacent></div>
</div>
</template>
<script>
test_scope(document.currentScript, () => {
assert_not_green('#above');
assert_not_green('#adjacent');
assert_green('.a');
assert_green('.a > div');
assert_green('.b');
assert_not_green('#limit');
}, 'Simulated inclusive scoping limit');
</script>

<template>
<style>
@scope (.a) to (.a) {
* { background-color: green; }
}
</style>
<div id=above>
<div class=a>
<div>
<div class=b>
<div id=inner></div>
</div>
</div>
</div>
<div id=adjacent></div>
</div>
</template>
<script>
test_scope(document.currentScript, () => {
assert_not_green('#above');
assert_not_green('#adjacent');
assert_not_green('.a');
assert_not_green('.a > div');
assert_not_green('.b');
assert_not_green('#inner');
}, 'Scope with no elements');
</script>


<template>
<style>
@scope (.a) {
Expand Down

0 comments on commit a017759

Please sign in to comment.