Bug 1904228: Don't consider :scope selectors to be featureless outside of @scope. r=emilio, a=dmeehan

Differential Revision: https://phabricator.services.mozilla.com/D214678
This commit is contained in:
David Shin 2024-06-24 18:15:27 +00:00
parent 4b1e713247
commit 07c77d3ecd
3 changed files with 74 additions and 5 deletions

View file

@ -596,6 +596,43 @@ impl From<StyleRuleInclusion> for RuleInclusion {
}
}
/// `:scope` selector, depending on the use case, can match a shadow host.
/// If used outside of `@scope`, it cannot possibly match the host.
/// Even when inside of `@scope`, it's conditional if the selector will
/// match the shadow host.
#[derive(Clone, Copy, Eq, PartialEq)]
enum ScopeMatchesShadowHost {
NotApplicable,
No,
Yes,
}
impl Default for ScopeMatchesShadowHost {
fn default() -> Self {
Self::NotApplicable
}
}
impl ScopeMatchesShadowHost {
fn nest_for_scope(&mut self, matches_shadow_host: bool) {
match *self {
Self::NotApplicable => {
// We're at the outermost `@scope`.
*self = if matches_shadow_host {
Self::Yes
} else {
Self::No
};
},
Self::Yes if !matches_shadow_host => {
// Inner `@scope` will not be able to match the shadow host.
*self = Self::No;
},
_ => (),
}
}
}
/// A struct containing state from ancestor rules like @layer / @import /
/// @container / nesting / @scope.
struct ContainingRuleState {
@ -604,7 +641,7 @@ struct ContainingRuleState {
container_condition_id: ContainerConditionId,
in_starting_style: bool,
scope_condition_id: ScopeConditionId,
scope_matches_shadow_host: bool,
scope_matches_shadow_host: ScopeMatchesShadowHost,
ancestor_selector_lists: SmallVec<[SelectorList<SelectorImpl>; 2]>,
}
@ -617,7 +654,7 @@ impl Default for ContainingRuleState {
in_starting_style: false,
ancestor_selector_lists: Default::default(),
scope_condition_id: ScopeConditionId::none(),
scope_matches_shadow_host: true,
scope_matches_shadow_host: Default::default(),
}
}
}
@ -629,7 +666,7 @@ struct SavedContainingRuleState {
container_condition_id: ContainerConditionId,
in_starting_style: bool,
scope_condition_id: ScopeConditionId,
scope_matches_shadow_host: bool,
scope_matches_shadow_host: ScopeMatchesShadowHost,
}
impl ContainingRuleState {
@ -3204,7 +3241,8 @@ impl CascadeData {
} else if potentially_matches_featureless_host
.intersects(FeaturelessHostMatches::FOR_SCOPE)
{
containing_rule_state.scope_matches_shadow_host
containing_rule_state.scope_matches_shadow_host ==
ScopeMatchesShadowHost::Yes
} else {
false
};
@ -3484,7 +3522,9 @@ impl CascadeData {
condition: Some(replaced),
implicit_scope_root,
});
containing_rule_state.scope_matches_shadow_host &= matches_shadow_host;
containing_rule_state
.scope_matches_shadow_host
.nest_for_scope(matches_shadow_host);
containing_rule_state.scope_condition_id = id;
},
// We don't care about any other rule.

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<title>Reference - :scope Selector Cannot be Featureless Outside of @scope</title>
<style>
:root {
background: white;
color: black;
}
</style>
<div id="dut">Test</div>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<title>:scope Selector Cannot be Featureless Outside of @scope</title>
<link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scoped-styles">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1904228">
<link rel="match" href="scope-featureless-ref.html">
<style>
:root {
background: white;
color: white;
}
:scope {
--font-color: black;
}
#dut {
color: var(--font-color);
}
</style>
<div id="dut">Test</div>