commit 81bf0dcc280fd98be38adea720a648cd6c7cf8f4
parent ae22c1270ad56534454c8eb82ed9667fe6e92f38
Author: Anders Hartvoll Ruud <andruud@chromium.org>
Date: Wed, 15 Oct 2025 08:21:22 +0000
Bug 1993475 [wpt PR 55297] - Include child rules when adding rules to RuleSetDiff, a=testonly
Automatic update from web-platform-tests
Include child rules when adding rules to RuleSetDiff
When some style rule changes (e.g. its selector text), any inner
style rules may also effectively change due to the &/:scope selector.
We already accounted for this during RuleSet::AddFilteredRulesFrom-
OtherBucket by traversing the chain of parent rules to see if any
were marked for inclusion. However, we did this by searching for
the '&' selector specifically, which means :scope cases did not
invalidate properly.
Unlike '&', :scope does not capture its parent style rule during
parsing, and a StyleRule has no general way of reaching its parent
(we don't store that pointer). Therefore, this CL traverses the child
rules top-down instead, during RuleSetDiff::AddDiff. The end result
should be the same, except that we now also include child rules
of @scope rules.
Note: There is little point in checking if inner style rules actually
contain &/:scope in their selector or not; if omitted by the author,
we insert them implicitly.
Bug: 449542602
Change-Id: I9a42e61ede422f41e83200064f74bff6c164047a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7013292
Reviewed-by: Steinar H Gunderson <sesse@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1526740}
--
wpt-commits: 2bba74c15b2b421eee0de9c55f8777db39439848
wpt-pr: 55297
Diffstat:
1 file changed, 73 insertions(+), 0 deletions(-)
diff --git a/testing/web-platform/tests/css/css-cascade/scope-nesting.html b/testing/web-platform/tests/css/css-cascade/scope-nesting.html
@@ -693,3 +693,76 @@ test((t) => {
assert_equals(getComputedStyle(child).getPropertyValue('--x'), '1'); // Changed.
}, 'Mutating selectorText on outer style rule causes correct inner specificity');
</script>
+
+<template id=test_set_selector_text>
+ <style id=style>
+ :where(.x) {
+ background-color: black;
+ }
+ .a {
+ @scope (&) {
+ :scope .x { background-color: green; }
+ }
+ }
+ </style>
+ <div class=a>
+ <div class=x>
+ </div>
+ </div>
+ <div class=b>
+ <div class=x>
+ </div>
+ </div>
+</template>
+<script>
+test((t) => {
+ t.add_cleanup(() => main.replaceChildren());
+ main.append(test_set_selector_text.content.cloneNode(true));
+ let ax = main.querySelector('.a > .x');
+ let bx = main.querySelector('.b > .x');
+ assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 128, 0)');
+ assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 0, 0)');
+ style.sheet.cssRules[1].selectorText = '.b'; // .a -> .
+ assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 0, 0)');
+ assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 128, 0)');
+}, 'Modifying selectorText invalidates inner scoped rules');
+</script>
+
+<template id=test_set_selector_text_nested_declarations>
+ <style id=style>
+ :where(.x) {
+ background-color: black;
+ }
+ .a {
+ @scope (&) {
+ :scope .x {
+ .unused {}
+ /* CSSNestedDeclarations { */
+ background-color: green;
+ /* } { */
+ }
+ }
+ }
+ </style>
+ <div class=a>
+ <div class=x>
+ </div>
+ </div>
+ <div class=b>
+ <div class=x>
+ </div>
+ </div>
+</template>
+<script>
+test((t) => {
+ t.add_cleanup(() => main.replaceChildren());
+ main.append(test_set_selector_text_nested_declarations.content.cloneNode(true));
+ let ax = main.querySelector('.a > .x');
+ let bx = main.querySelector('.b > .x');
+ assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 128, 0)');
+ assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 0, 0)');
+ style.sheet.cssRules[1].selectorText = '.b'; // .a -> .
+ assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 0, 0)');
+ assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 128, 0)');
+}, 'Modifying selectorText invalidates inner scoped rules (nested declarations)');
+</script>