Skip to content

Commit

Permalink
Bug 1931416 [wpt PR 49178] - [@scope] Support '@import scope(...)' be…
Browse files Browse the repository at this point in the history
…hind a flag, a=testonly

Automatic update from web-platform-tests
[@scope] Support '@import scope(...)' behind a flag

This CL implements the ability to scope an entire stylesheet on import,
via the new scope() function. The CSSWG has resolved to add the scope()
function, but there is no spec yet. The WPTs are therefore marked as
tentative for now.

Note that this CL intentionally does not have parse-validity tests,
such as scope() combined with other features of the @import prelude
(e.g. layer(), media queries). This is because scope()'s "position"
in the prelude grammar has not been defined, and the WG instead resolved
allow full reordering of the conditions. This opens a new problem,
tracked by Issue 10972 [1]. In other words, parsing tests are
deferred until that issue is resolved. The WPTs in this only use
@import scope(...)", which is assumed to be valid regardless of the
outcome.

Since regular top-level selectors are not relative selectors,
they are not guaranteed to contain either '&' or ':scope'
like selector parsing nested under CSSNestingType::kNesting
or CSSNestingType::kScope (respectively). This means that selectors
at the top-level of an imported stylesheet are not guaranteed to
be scope-containing, so we need another way of enforcing
the in-scope [2] requirement of scoped selectors. This is effectively
done by always treating the last selector in a complex selector
as scope-containing.

Due to the same absence of '&' and ':scope' in the imported stylesheet,
rules can also be incorrectly handled as "easy" or
"covered by bucketing" even though they match in the context of a scope.
Addressed this by disabling the optimization when context.style_scope
is set.

[1] w3c/csswg-drafts#10972
[2] https://drafts.csswg.org/css-cascade-6/#in-scope

Bug: 369876911
Change-Id: I75bc3514d959c6762232bc769f844682ed4a50fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6012179
Commit-Queue: Anders Hartvoll Ruud <[email protected]>
Reviewed-by: Rune Lillesveen <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1383152}

--

wpt-commits: 8c083dd5f5cf5801b2ae298bec62fc55e9226d74
wpt-pr: 49178
  • Loading branch information
andruud authored and moz-wptsync-bot committed Nov 16, 2024
1 parent 0da53a7 commit b73e753
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.x {
--x: 1;
}

:scope > .y {
--y: 1;
}

@scope (.inner-scope) {
.z {
--z: 1;
}
}

& > .w {
--w: 1;
}

& > & > .u {
--u: 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>@import scope(), implicit scope</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7348">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<main id=main>
<div class=scope>
<style>
@import url("resources/scope-imported.css") scope();
</style>
<div class=x>Inside</div>
</div>
<div class=x>Outside</div>
</main>
<script>
test(() => {
let e = main.querySelector('.scope > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '1');
}, 'Scope-imported rule applies within implicit scope');

test(() => {
let e = main.querySelector('main > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '');
}, 'Scope-imported rule does not apply outside of implicit scope');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<title>@import scope(), :scope rules in imported stylesheet</title>
<link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@import url("resources/scope-imported.css") scope((.scope));
</style>
<main id=main>
<div class=scope>
<div class=inner-scope>
<div class=z>Inside</div>
</div>
</div>
<div class=inner-scope>
<div class=z>Outside</div>
</div>
</main>
<script>
test(() => {
let e = main.querySelector('.scope > .inner-scope > .z');
assert_equals(getComputedStyle(e).getPropertyValue('--z'), '1');
}, '@scope within scope-imported stylesheet matches');

test(() => {
let e = main.querySelector('#main > .inner-scope > .z');
assert_equals(getComputedStyle(e).getPropertyValue('--z'), '');
}, '@scope within scope-imported does not ignore import scope');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<title>@import scope(), same stylesheet imported multiple times</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7348">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@import url("resources/scope-imported.css") scope((.scope1));
@import url("resources/scope-imported.css") scope((.scope2));
</style>
<main id=main>
<div class=scope1>
<div class=x>Inside</div>
</div>
<div class=scope2>
<div class=x>Inside</div>
</div>
<div class=x>Outside</div>
</main>
<script>
test(() => {
let e1 = main.querySelector('.scope1 > .x');
let e2 = main.querySelector('.scope2 > .x');
assert_equals(getComputedStyle(e1).getPropertyValue('--x'), '1');
assert_equals(getComputedStyle(e2).getPropertyValue('--x'), '1');
}, 'A stylesheet may be imported multiple times, and scoped differently');

test(() => {
let e = main.querySelector('main > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '');
}, 'Scope-imported rule does not apply outside of scope');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<title>@import scope(), '&' selectors</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7348">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@import url("resources/scope-imported.css") scope((.scope));
</style>
<main id=main>
<div class=scope>
<div class=w>Inside</div>
<div class=scope>
<div class=w>Inner (W)</div>
<div class=u>Inner (U)</div>
</div>
</div>
</main>
<script>
test(() => {
let e = main.querySelector('#main > .scope > .w');
assert_equals(getComputedStyle(e).getPropertyValue('--w'), '1');
}, 'The & selector matches the scoping root');

test(() => {
let w = main.querySelector('#main > .scope > .scope > .w');
assert_equals(getComputedStyle(w).getPropertyValue('--w'), '1');
// The '& > & > .u' selector should behave like ':scope > :scope > .u'
// and therefore never match.
let u = main.querySelector('#main > .scope > .scope > .u');
assert_equals(getComputedStyle(u).getPropertyValue('--u'), '');
}, 'The & selector behaves like :scope');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<title>@import scope() with &lt;scope-end&gt;</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7348">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@import url("resources/scope-imported.css") scope((.scope) to (.limit));
</style>
<main id=main>
<div class=scope>
<div class=x>Inside</div>
<div class=limit>
<div class=x>Below limit</div>
</div>
</div>
</main>
<script>
test(() => {
let e = main.querySelector('.scope > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '1');
}, 'Scope-imported rule applies within scope, above limit');

test(() => {
let e = main.querySelector('.limit > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '');
}, 'Scope-imported rule does not apply below limit');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<title>@import scope(), :scope rules in imported stylesheet</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7348">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@import url("resources/scope-imported.css") scope((.scope));
</style>
<main id=main>
<div class=scope>
<div class=y>Inside</div>
<div>
<div class=y>Inside, but should not match</div>
</div>
</div>
<div class=y>Outside</div>
</main>
<script>
test(() => {
let inside = main.querySelector('.scope > .y');
assert_equals(getComputedStyle(inside).getPropertyValue('--y'), '1');

let inside_no_match = main.querySelector('.scope > div > .y');
assert_equals(getComputedStyle(inside_no_match).getPropertyValue('--y'), '');

let outside = main.querySelector('#main > .y');
assert_equals(getComputedStyle(outside).getPropertyValue('--y'), '');
}, 'The :scope pseudo-class works in imported stylesheets');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<title>@import scope(), &lt;scope-start&gt;</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7348">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@import url("resources/scope-imported.css") scope((.scope));
</style>
<main id=main>
<div class=scope>
<div class=x>Inside</div>
</div>
<div class=x>Outside</div>
</main>
<script>
test(() => {
let e = main.querySelector('.scope > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '1');
}, 'Scope-imported rule applies within scope');

test(() => {
let e = main.querySelector('main > .x');
assert_equals(getComputedStyle(e).getPropertyValue('--x'), '');
}, 'Scope-imported rule does not apply outside of scope');
</script>

0 comments on commit b73e753

Please sign in to comment.