Files
Anders Hartvoll Ruud d4aa767b6a Bug 1849167 [wpt PR 41511] - [@scope] Save MatchFlags in StyleScopeActivations, a=testonly
Automatic update from web-platform-tests
[@scope] Save MatchFlags in StyleScopeActivations

ComputedStyles that match pseudo-state-dependent selectors get
a flag set for invalidation purposes. For example:

  p:hover { ... }

When matching this selector against 'p', the MatchResults will
contain MatchFlags with the kAffectedByHover flag set, regardless
of whether or not 'p' is currently hovered or not. (The flag
ultimately ends up on the ComputedStyle of 'p').

Now consider this @scope rule which selects the same element:

  @scope (p:hover) {
    :scope { ... }
  }

Now we may or may not have a scoping root, depending on whether 'p'
is hovered or not. When matching this selector (:scope) against 'p',
we need to make sure that the kAffectedByHover is set in the returned
MatchFlags, even if 'p' is not currently hovered (in which case
we don't technically have a scoping root at 'p').

This means that we have to store the MatchFlags that was produced for
for the scopes that were attempted activated.

This is done in this CL by storing MatchFlags alongside the
activation vector, and propagating these flags during handling
of kScopeActivation. This may over-invalidate a little, since
we're propagating the flags at the start of the compound that
contains :scope (before actually evaluating :scope), but this is
probably OK.

Fixed: 1451091
Change-Id: Ia48664381766ef44e6ade11457e905f068b6103e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4790441
Commit-Queue: Anders Hartvoll Ruud <[email protected]>
Reviewed-by: Rune Lillesveen <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1185140}

--

wpt-commits: 04ab260e0d49869aa16c178d20e5222f2fbe8cd5
wpt-pr: 41511
2023-09-13 11:36:36 +00:00

114 lines
3.0 KiB
HTML

<!DOCTYPE html>
<title>@scope and :hover</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>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<main id=main></main>
<script>
async function hover(element) {
let actions = new test_driver.Actions().pointerMove(0, 0, {origin: element});
await actions.send();
}
</script>
<template id=test_subject>
<div>
<style>
@scope (.a:hover) {
:scope { z-index: 1; }
}
</style>
<div class=a>1</div>
</template>
<script>
promise_test(async (t) => {
t.add_cleanup(() => main.replaceChildren());
main.append(test_subject.content.cloneNode(true));
let a = main.querySelector('.a');
assert_equals(getComputedStyle(a).zIndex, 'auto');
await hover(a);
assert_equals(getComputedStyle(a).zIndex, '1');
}, ':hover via :scope in subject');
</script>
<template id=test_non_subject>
<div>
<style>
@scope (.a:hover) {
:scope .b { z-index: 1; }
}
</style>
<div class=a>
<div class=b>2</div>
</div>
</template>
<script>
promise_test(async (t) => {
t.add_cleanup(() => main.replaceChildren());
main.append(test_non_subject.content.cloneNode(true));
let a = main.querySelector('.a');
let b = main.querySelector('.b');
assert_equals(getComputedStyle(b).zIndex, 'auto');
await hover(a);
assert_equals(getComputedStyle(b).zIndex, '1');
}, ':hover via :scope in non-subject');
</script>
<template id=test_subject_limit>
<div>
<style>
@scope (.a) to (:scope:hover) {
:scope { z-index: 1; }
}
</style>
<div class=a tabindex=0>3</div>
</template>
<script>
promise_test(async (t) => {
t.add_cleanup(() => main.replaceChildren());
main.append(test_subject_limit.content.cloneNode(true));
let a = main.querySelector('.a');
assert_equals(getComputedStyle(a).zIndex, '1');
await hover(a);
// After hover, we're no longer in scope because the limit (to-selector)
// kicks in.
assert_equals(getComputedStyle(a).zIndex, 'auto');
}, ':hover in limit, :scope in subject');
</script>
<template id=test_non_subject_limit>
<div>
<style>
@scope (.a) to (.b:hover) {
.b { z-index: 1; }
}
</style>
<div class=a tabindex=0>
<div class=b tabindex=1>4</div>
</div>
</template>
<script>
promise_test(async (t) => {
t.add_cleanup(() => main.replaceChildren());
main.append(test_non_subject_limit.content.cloneNode(true));
let a = main.querySelector('.a');
let b = main.querySelector('.b');
assert_equals(getComputedStyle(b).zIndex, '1');
await hover(b);
// After hover, we're no longer in scope because the limit (to-selector)
// kicks in.
assert_equals(getComputedStyle(b).zIndex, 'auto');
}, ':hover in intermediate limit, :scope in subject');
</script>