diff --git a/components/style/animation.rs b/components/style/animation.rs index 2d2748d29e5..b8b98dcb4e4 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -259,6 +259,7 @@ impl IntermediateComputedKeyframe { let inputs = CascadeInputs { rules: new_node, visited_rules: base_style.visited_rules().cloned(), + flags: base_style.flags.for_cascade_inputs(), }; resolver .cascade_style_and_visited_with_default_parents(inputs) diff --git a/components/style/context.rs b/components/style/context.rs index 633479c5a7a..d6b4d2cc102 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -7,6 +7,7 @@ #[cfg(feature = "servo")] use crate::animation::DocumentAnimationSet; use crate::bloom::StyleBloom; +use crate::computed_value_flags::ComputedValueFlags; use crate::data::{EagerPseudoStyles, ElementData}; use crate::dom::{SendElement, TElement}; #[cfg(feature = "gecko")] @@ -189,14 +190,18 @@ pub struct CascadeInputs { /// element. A element's "relevant link" is the element being matched if it /// is a link or the nearest ancestor link. pub visited_rules: Option, + + /// The set of flags from container queries that we need for invalidation. + pub flags: ComputedValueFlags, } impl CascadeInputs { /// Construct inputs from previous cascade results, if any. pub fn new_from_style(style: &ComputedValues) -> Self { - CascadeInputs { + Self { rules: style.rules.clone(), visited_rules: style.visited_style().and_then(|v| v.rules.clone()), + flags: style.flags.for_cascade_inputs(), } } } diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index bf1cad4311d..84c2165f759 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -4,6 +4,7 @@ //! Gecko-specific bits for selector-parsing. +use crate::computed_value_flags::ComputedValueFlags; use crate::gecko_bindings::structs::RawServoSelectorList; use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use crate::invalidation::element::document_state::InvalidationMatchingData; @@ -236,6 +237,10 @@ pub struct SelectorImpl; pub struct ExtraMatchingData { /// The invalidation data to invalidate doc-state pseudo-classes correctly. pub invalidation_data: InvalidationMatchingData, + + /// The invalidation bits from matching container queries. These are here + /// just for convenience mostly. + pub cascade_input_flags: ComputedValueFlags, } impl ::selectors::SelectorImpl for SelectorImpl { diff --git a/components/style/matching.rs b/components/style/matching.rs index f62c8cbbdfb..5e433efc79e 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -238,6 +238,7 @@ trait PrivateMatchMethods: TElement { let inputs = CascadeInputs { rules: Some(without_transition_rules), visited_rules: primary_style.visited_rules().cloned(), + flags: primary_style.flags.for_cascade_inputs(), }; // Actually `PseudoElementResolution` doesn't really matter. diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs index ce928c1c692..18eff8200cc 100644 --- a/components/style/properties/cascade.rs +++ b/components/style/properties/cascade.rs @@ -59,6 +59,7 @@ pub fn cascade( parent_style_ignoring_first_line: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>, visited_rules: Option<&StrongRuleNode>, + cascade_input_flags: ComputedValueFlags, quirks_mode: QuirksMode, rule_cache: Option<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, @@ -76,6 +77,7 @@ where parent_style_ignoring_first_line, layout_parent_style, CascadeMode::Unvisited { visited_rules }, + cascade_input_flags, quirks_mode, rule_cache, rule_cache_conditions, @@ -175,6 +177,7 @@ fn cascade_rules( parent_style_ignoring_first_line: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>, cascade_mode: CascadeMode, + cascade_input_flags: ComputedValueFlags, quirks_mode: QuirksMode, rule_cache: Option<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, @@ -197,6 +200,7 @@ where parent_style_ignoring_first_line, layout_parent_style, cascade_mode, + cascade_input_flags, quirks_mode, rule_cache, rule_cache_conditions, @@ -232,6 +236,7 @@ pub fn apply_declarations<'a, E, I>( parent_style_ignoring_first_line: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>, cascade_mode: CascadeMode, + cascade_input_flags: ComputedValueFlags, quirks_mode: QuirksMode, rule_cache: Option<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, @@ -296,6 +301,8 @@ where container_size_query, ); + context.style().add_flags(cascade_input_flags); + let using_cached_reset_properties; let mut cascade = Cascade::new(&mut context, cascade_mode, &referenced_properties); let mut shorthand_cache = ShorthandsWithPropertyReferencesCache::default(); @@ -751,6 +758,9 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { visited_parent!(parent_style_ignoring_first_line), visited_parent!(layout_parent_style), CascadeMode::Visited { writing_mode }, + // Cascade input flags don't matter for the visited style, they are + // in the main (unvisited) style. + Default::default(), self.context.quirks_mode, // The rule cache doesn't care about caching :visited // styles, we cache the unvisited style instead. We still do diff --git a/components/style/properties/computed_value_flags.rs b/components/style/properties/computed_value_flags.rs index 1cfaee084df..056245f35a1 100644 --- a/components/style/properties/computed_value_flags.rs +++ b/components/style/properties/computed_value_flags.rs @@ -102,9 +102,23 @@ bitflags! { /// Whether the style depends on viewport units. const USES_VIEWPORT_UNITS = 1 << 20; + /// Whether the style depends on viewport units on container queries. + /// + /// This needs to be a separate flag from `USES_VIEWPORT_UNITS` because + /// it causes us to re-match the style (rather than re-cascascading it, + /// which is enough for other uses of viewport units). + const USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES = 1 << 21; + /// A flag used to mark styles which have `container-type` of `size` or /// `inline-size`, or under one. - const SELF_OR_ANCESTOR_HAS_SIZE_CONTAINER_TYPE = 1 << 21; + const SELF_OR_ANCESTOR_HAS_SIZE_CONTAINER_TYPE = 1 << 22; + } +} + +impl Default for ComputedValueFlags { + #[inline] + fn default() -> Self { + Self::empty() } } @@ -124,7 +138,13 @@ impl ComputedValueFlags { /// Flags that may be propagated to descendants. #[inline] fn maybe_inherited_flags() -> Self { - Self::inherited_flags() | ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK + Self::inherited_flags() | Self::SHOULD_SUPPRESS_LINEBREAK + } + + /// Flags that are an input to the cascade. + #[inline] + fn cascade_input_flags() -> Self { + Self::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES } /// Returns the flags that are always propagated to descendants. @@ -141,4 +161,10 @@ impl ComputedValueFlags { pub fn maybe_inherited(self) -> Self { self & Self::maybe_inherited_flags() } + + /// Flags that are an input to the cascade. + #[inline] + pub fn for_cascade_inputs(self) -> Self { + self & Self::cascade_input_flags() + } } diff --git a/components/style/selector_map.rs b/components/style/selector_map.rs index 6331f60cb53..3b7515292bf 100644 --- a/components/style/selector_map.rs +++ b/components/style/selector_map.rs @@ -359,6 +359,7 @@ impl SelectorMap { rule.container_condition_id, stylist, element, + matching_context, ) { continue; } diff --git a/components/style/style_resolver.rs b/components/style/style_resolver.rs index e787e19d176..b768e5ff5db 100644 --- a/components/style/style_resolver.rs +++ b/components/style/style_resolver.rs @@ -5,6 +5,7 @@ //! Style resolution for a given element or pseudo-element. use crate::applicable_declarations::ApplicableDeclarationList; +use crate::computed_value_flags::ComputedValueFlags; use crate::context::{CascadeInputs, ElementCascadeInputs, StyleContext}; use crate::data::{EagerPseudoStyles, ElementStyles}; use crate::dom::TElement; @@ -44,6 +45,7 @@ where struct MatchingResults { rule_node: StrongRuleNode, + flags: ComputedValueFlags, } /// A style returned from the resolver machinery. @@ -133,8 +135,6 @@ fn eager_pseudo_is_definitely_not_generated( pseudo: &PseudoElement, style: &ComputedValues, ) -> bool { - use crate::computed_value_flags::ComputedValueFlags; - if !pseudo.is_before_or_after() { return false; } @@ -204,6 +204,7 @@ where CascadeInputs { rules: Some(primary_results.rule_node), visited_rules, + flags: primary_results.flags, }, parent_style, layout_parent_style, @@ -418,7 +419,7 @@ where originating_element_style: &PrimaryStyle, layout_parent_style: Option<&ComputedValues>, ) -> Option { - let rules = self.match_pseudo( + let MatchingResults { rule_node, mut flags } = self.match_pseudo( originating_element_style.style(), pseudo, VisitedHandlingMode::AllLinksUnvisited, @@ -430,13 +431,17 @@ where originating_element_style.style(), pseudo, VisitedHandlingMode::RelevantLinkVisited, - ); + ).map(|results| { + flags |= results.flags; + results.rule_node + }); } Some(self.cascade_style_and_visited( CascadeInputs { - rules: Some(rules), + rules: Some(rule_node), visited_rules, + flags, }, Some(originating_element_style.style()), layout_parent_style, @@ -493,7 +498,10 @@ where } } - MatchingResults { rule_node } + MatchingResults { + rule_node, + flags: matching_context.extra_data.cascade_input_flags, + } } fn match_pseudo( @@ -501,7 +509,7 @@ where originating_element_style: &ComputedValues, pseudo_element: &PseudoElement, visited_handling: VisitedHandlingMode, - ) -> Option { + ) -> Option { debug!( "Match pseudo {:?} for {:?}, visited: {:?}", self.element, pseudo_element, visited_handling @@ -556,6 +564,9 @@ where .rule_tree() .compute_rule_node(&mut applicable_declarations, &self.context.shared.guards); - Some(rule_node) + Some(MatchingResults { + rule_node, + flags: matching_context.extra_data.cascade_input_flags, + }) } } diff --git a/components/style/stylesheets/container_rule.rs b/components/style/stylesheets/container_rule.rs index 6850fa2f853..f4d652e6e45 100644 --- a/components/style/stylesheets/container_rule.rs +++ b/components/style/stylesheets/container_rule.rs @@ -225,7 +225,12 @@ impl ContainerCondition { } /// Tries to match a container query condition for a given element. - pub(crate) fn matches(&self, device: &Device, element: E) -> bool + pub(crate) fn matches( + &self, + device: &Device, + element: E, + invalidation_flags: &mut ComputedValueFlags, + ) -> bool where E: TElement, { @@ -240,7 +245,15 @@ impl ContainerCondition { device, info, size_query_container_lookup, - |context| self.condition.matches(context), + |context| { + let matches = self.condition.matches(context); + if context.style().flags().contains(ComputedValueFlags::USES_VIEWPORT_UNITS) { + // TODO(emilio): Might need something similar to improve + // invalidation of font relative container-query lengths. + invalidation_flags.insert(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES); + } + matches + }, ) } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 8dfdc91e58b..321f879c83a 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -891,6 +891,7 @@ impl Stylist { CascadeInputs { rules: Some(rules), visited_rules: None, + flags: Default::default(), }, pseudo, guards, @@ -1088,6 +1089,7 @@ impl Stylist { parent_style_ignoring_first_line, layout_parent_style, visited_rules, + inputs.flags, self.quirks_mode, rule_cache, rule_cache_conditions, @@ -1187,6 +1189,7 @@ impl Stylist { Some(CascadeInputs { rules: Some(rules), visited_rules, + flags: matching_context.extra_data.cascade_input_flags, }) } @@ -1501,6 +1504,7 @@ impl Stylist { CascadeMode::Unvisited { visited_rules: None, }, + Default::default(), self.quirks_mode, /* rule_cache = */ None, &mut Default::default(), @@ -2365,6 +2369,7 @@ impl CascadeData { mut id: ContainerConditionId, stylist: &Stylist, element: E, + context: &mut MatchingContext, ) -> bool where E: TElement, @@ -2375,7 +2380,7 @@ impl CascadeData { None => return true, Some(ref c) => c, }; - if !condition.matches(stylist.device(), element) { + if !condition.matches(stylist.device(), element, &mut context.extra_data.cascade_input_flags) { return false; } id = condition_ref.parent;