Commit 4bdea1b0 authored by Anders Hartvoll Ruud's avatar Anders Hartvoll Ruud Committed by Commit Bot

[:is/:where] Avoid scope-contains-last-matched-element check

As far as I can tell, this check exists to ensure that complex
Shadow DOM v0 selectors don't cross any boundaries they shouldn't
(see Issue 360679).

The problem is that for e.g. ::part(foo):is(:focus), the :focus part
is detected as an illegal boundary crossing, since the TreeScope of
context.scope and context.element are different.

This function doesn't seem entirely right to me, but at this point
I want to touch Shadow DOM v0 as little as possible, since it's very
close to being removed. Hence I'm basically just disabling the check
for :is/:where.

Bug: 568705
Change-Id: I2febcd37c9772b11f91ae93df87acb7649a8de91
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2464263Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816112}
parent c86e1636
...@@ -194,6 +194,13 @@ static bool ScopeContainsLastMatchedElement( ...@@ -194,6 +194,13 @@ static bool ScopeContainsLastMatchedElement(
if (context.scope->GetTreeScope() == context.element->GetTreeScope()) if (context.scope->GetTreeScope() == context.element->GetTreeScope())
return true; return true;
// The scope-contains-last-matched-element check is only relevant for
// ShadowDOM V0 features (::content, ::shadow, /deep/), and the selector
// parser does not allow mixing ShadowDOM V0 with nested complex
// selectors, hence we can skip the check inside a nested complex selector.
if (context.in_nested_complex_selector)
return true;
// Because Blink treats a shadow host's TreeScope as a separate one from its // Because Blink treats a shadow host's TreeScope as a separate one from its
// descendent shadow roots, if the last matched element is a shadow host, the // descendent shadow roots, if the last matched element is a shadow host, the
// condition above isn't met, even though it should be. // condition above isn't met, even though it should be.
...@@ -1102,6 +1109,7 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context, ...@@ -1102,6 +1109,7 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
case CSSSelector::kPseudoAny: { case CSSSelector::kPseudoAny: {
SelectorCheckingContext sub_context(context); SelectorCheckingContext sub_context(context);
sub_context.is_sub_selector = true; sub_context.is_sub_selector = true;
sub_context.in_nested_complex_selector = true;
if (!selector.SelectorList()) if (!selector.SelectorList())
break; break;
for (sub_context.selector = selector.SelectorList()->First(); for (sub_context.selector = selector.SelectorList()->First();
......
...@@ -126,6 +126,7 @@ class SelectorChecker { ...@@ -126,6 +126,7 @@ class SelectorChecker {
bool has_selection_pseudo = false; bool has_selection_pseudo = false;
bool treat_shadow_host_as_normal_scope = false; bool treat_shadow_host_as_normal_scope = false;
bool is_from_vtt = false; bool is_from_vtt = false;
bool in_nested_complex_selector = false;
}; };
struct MatchResult { struct MatchResult {
......
<!DOCTYPE html>
<button style="color:green">Should be green on focus</button>
<!DOCTYPE html>
<html class="reftest-wait">
<title>CSS Shadow Parts - Nested Pseudo Classes</title>
<link rel="help" href="https://drafts.csswg.org/css-shadow-parts" >
<link rel="help" href="https://drafts.csswg.org/selectors/#matches">
<link href="https://drafts.csswg.org/selectors/#matches" rel="help">
<link rel="match" href="interaction-with-nested-pseudo-class-ref.html">
<script src="/common/reftest-wait.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<style>
:root { color: red; }
::part(test):is(:focus) { color: green; }
</style>
<div id=host></div>
<script>
const root = host.attachShadow({mode: 'closed'});
root.innerHTML = '<button part=test>Should be green on focus</button>';
const button = root.querySelector('button');
button.addEventListener('focus', takeScreenshot);
test_driver.bless('focus button', () => button.focus());
</script>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment