mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
style: Allow propagating computed style bits from the selector-matching process
This allows us to propagate flags from the container query styles all the way to the computed style of the element. The flag for viewport units in container queries has to be different because it requires rematching, see comments. Depends on D159851 Differential Revision: https://phabricator.services.mozilla.com/D159852
This commit is contained in:
parent
bfa293c5c5
commit
5ded58a2b1
10 changed files with 92 additions and 14 deletions
|
@ -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)
|
||||
|
|
|
@ -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<StrongRuleNode>,
|
||||
|
||||
/// 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -59,6 +59,7 @@ pub fn cascade<E>(
|
|||
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<E>(
|
|||
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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -359,6 +359,7 @@ impl SelectorMap<Rule> {
|
|||
rule.container_condition_id,
|
||||
stylist,
|
||||
element,
|
||||
matching_context,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -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<ResolvedStyle> {
|
||||
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<StrongRuleNode> {
|
||||
) -> Option<MatchingResults> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,12 @@ impl ContainerCondition {
|
|||
}
|
||||
|
||||
/// Tries to match a container query condition for a given element.
|
||||
pub(crate) fn matches<E>(&self, device: &Device, element: E) -> bool
|
||||
pub(crate) fn matches<E>(
|
||||
&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
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<E::Impl>,
|
||||
) -> 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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue