style: Track @container condition id in style rules

Much like we track layer rules. Consolidate that "containing rule state
we pass down while building the cascade data" in a single struct that we
can easily restore.

For now, do nothing with it. I want to land this patch separately
because it touches the Rule struct and CascadeData rebuilds, which both
are performance sensitive.

Its layout shouldn't change because I also changed LayerId to be a u16
(this shouldn't matter in practice, since LayerOrder is already a u16).

Differential Revision: https://phabricator.services.mozilla.com/D145243
This commit is contained in:
Emilio Cobos Álvarez 2023-08-12 00:28:54 +02:00 committed by Martin Robinson
parent b05552369f
commit 82c5be08c8
2 changed files with 135 additions and 54 deletions

View file

@ -61,17 +61,6 @@ impl LayerOrder {
} }
} }
/// The id of a given layer, a sequentially-increasing identifier.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
pub struct LayerId(pub u32);
impl LayerId {
/// The id of the root layer.
pub const fn root() -> Self {
Self(0)
}
}
/// A `<layer-name>`: https://drafts.csswg.org/css-cascade-5/#typedef-layer-name /// A `<layer-name>`: https://drafts.csswg.org/css-cascade-5/#typedef-layer-name
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
pub struct LayerName(pub SmallVec<[AtomIdent; 1]>); pub struct LayerName(pub SmallVec<[AtomIdent; 1]>);

View file

@ -29,7 +29,7 @@ use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind}; use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind};
use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher}; use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher};
use crate::stylesheets::keyframes_rule::KeyframesAnimation; use crate::stylesheets::keyframes_rule::KeyframesAnimation;
use crate::stylesheets::layer_rule::{LayerId, LayerName, LayerOrder}; use crate::stylesheets::layer_rule::{LayerName, LayerOrder};
use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule}; use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::stylesheets::{ use crate::stylesheets::{
@ -548,6 +548,47 @@ impl From<StyleRuleInclusion> for RuleInclusion {
} }
} }
/// A struct containing state from ancestor rules like @layer / @import /
/// @container.
struct ContainingRuleState {
layer_name: LayerName,
layer_id: LayerId,
container_condition_id: ContainerConditionId,
}
impl Default for ContainingRuleState {
fn default() -> Self {
Self {
layer_name: LayerName::new_empty(),
layer_id: LayerId::root(),
container_condition_id: ContainerConditionId::none(),
}
}
}
struct SavedContainingRuleState {
layer_name_len: usize,
layer_id: LayerId,
container_condition_id: ContainerConditionId,
}
impl ContainingRuleState {
fn save(&self) -> SavedContainingRuleState {
SavedContainingRuleState {
layer_name_len: self.layer_name.0.len(),
layer_id: self.layer_id,
container_condition_id: self.container_condition_id,
}
}
fn restore(&mut self, saved: &SavedContainingRuleState) {
debug_assert!(self.layer_name.0.len() >= saved.layer_name_len);
self.layer_name.0.truncate(saved.layer_name_len);
self.layer_id = saved.layer_id;
self.container_condition_id = saved.container_condition_id;
}
}
impl Stylist { impl Stylist {
/// Construct a new `Stylist`, using given `Device` and `QuirksMode`. /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
/// If more members are added here, think about whether they should /// If more members are added here, think about whether they should
@ -2029,6 +2070,17 @@ impl PartElementAndPseudoRules {
} }
} }
/// The id of a given layer, a sequentially-increasing identifier.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
pub struct LayerId(u16);
impl LayerId {
/// The id of the root layer.
pub const fn root() -> Self {
Self(0)
}
}
#[derive(Clone, Debug, MallocSizeOf)] #[derive(Clone, Debug, MallocSizeOf)]
struct CascadeLayer { struct CascadeLayer {
id: LayerId, id: LayerId,
@ -2046,6 +2098,33 @@ impl CascadeLayer {
} }
} }
/// The id of a given container condition, a sequentially-increasing identifier
/// for a given style set.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
pub struct ContainerConditionId(u16);
impl ContainerConditionId {
/// A special id that represents no container rule all.
pub const fn none() -> Self {
Self(0)
}
}
#[derive(Clone, Debug, MallocSizeOf)]
struct ContainerCondition {
parent: ContainerConditionId,
// TODO: condition: Option<Arc<ContainerCondition>> (or so).
}
impl ContainerCondition {
const fn none() -> Self {
Self {
parent: ContainerConditionId::none(),
}
}
}
/// Data resulting from performing the CSS cascade that is specific to a given /// Data resulting from performing the CSS cascade that is specific to a given
/// origin. /// origin.
/// ///
@ -2117,6 +2196,9 @@ pub struct CascadeData {
/// The list of cascade layers, indexed by their layer id. /// The list of cascade layers, indexed by their layer id.
layers: SmallVec<[CascadeLayer; 1]>, layers: SmallVec<[CascadeLayer; 1]>,
/// The list of container conditions, indexed by their id.
container_conditions: SmallVec<[ContainerCondition; 1]>,
/// Effective media query results cached from the last rebuild. /// Effective media query results cached from the last rebuild.
effective_media_query_results: EffectiveMediaQueryResults, effective_media_query_results: EffectiveMediaQueryResults,
@ -2159,6 +2241,7 @@ impl CascadeData {
animations: Default::default(), animations: Default::default(),
layer_id: Default::default(), layer_id: Default::default(),
layers: smallvec::smallvec![CascadeLayer::root()], layers: smallvec::smallvec![CascadeLayer::root()],
container_conditions: smallvec::smallvec![ContainerCondition::none()],
extra_data: ExtraStyleData::default(), extra_data: ExtraStyleData::default(),
effective_media_query_results: EffectiveMediaQueryResults::new(), effective_media_query_results: EffectiveMediaQueryResults::new(),
rules_source_order: 0, rules_source_order: 0,
@ -2394,8 +2477,7 @@ impl CascadeData {
stylesheet: &S, stylesheet: &S,
guard: &SharedRwLockReadGuard, guard: &SharedRwLockReadGuard,
rebuild_kind: SheetRebuildKind, rebuild_kind: SheetRebuildKind,
mut current_layer: &mut LayerName, containing_rule_state: &mut ContainingRuleState,
current_layer_id: LayerId,
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>, mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
) -> Result<(), AllocErr> ) -> Result<(), AllocErr>
where where
@ -2418,7 +2500,7 @@ impl CascadeData {
if pseudo.is_precomputed() { if pseudo.is_precomputed() {
debug_assert!(selector.is_universal()); debug_assert!(selector.is_universal());
debug_assert_eq!(stylesheet.contents().origin, Origin::UserAgent); debug_assert_eq!(stylesheet.contents().origin, Origin::UserAgent);
debug_assert_eq!(current_layer_id, LayerId::root()); debug_assert_eq!(containing_rule_state.layer_id, LayerId::root());
precomputed_pseudo_element_decls precomputed_pseudo_element_decls
.as_mut() .as_mut()
@ -2445,7 +2527,8 @@ impl CascadeData {
hashes, hashes,
locked.clone(), locked.clone(),
self.rules_source_order, self.rules_source_order,
current_layer_id, containing_rule_state.layer_id,
containing_rule_state.container_condition_id,
); );
if rebuild_kind.should_rebuild_invalidation() { if rebuild_kind.should_rebuild_invalidation() {
@ -2523,7 +2606,7 @@ impl CascadeData {
self.animations.try_insert_with( self.animations.try_insert_with(
name, name,
animation, animation,
current_layer_id, containing_rule_state.layer_id,
compare_keyframes_in_same_layer, compare_keyframes_in_same_layer,
)?; )?;
}, },
@ -2532,25 +2615,35 @@ impl CascadeData {
// Note: Bug 1733260: we may drop @scroll-timeline rule once this spec issue // Note: Bug 1733260: we may drop @scroll-timeline rule once this spec issue
// https://github.com/w3c/csswg-drafts/issues/6674 gets landed. // https://github.com/w3c/csswg-drafts/issues/6674 gets landed.
self.extra_data self.extra_data
.add_scroll_timeline(guard, rule, current_layer_id)?; .add_scroll_timeline(guard, rule, containing_rule_state.layer_id)?;
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
CssRule::FontFace(ref rule) => { CssRule::FontFace(ref rule) => {
self.extra_data.add_font_face(rule, current_layer_id); // NOTE(emilio): We don't care about container_condition_id
// because:
//
// Global, name-defining at-rules such as @keyframes or
// @font-face or @layer that are defined inside container
// queries are not constrained by the container query
// conditions.
//
// https://drafts.csswg.org/css-contain-3/#container-rule
// (Same elsewhere)
self.extra_data.add_font_face(rule, containing_rule_state.layer_id);
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
CssRule::FontFeatureValues(ref rule) => { CssRule::FontFeatureValues(ref rule) => {
self.extra_data self.extra_data
.add_font_feature_values(rule, current_layer_id); .add_font_feature_values(rule, containing_rule_state.layer_id);
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
CssRule::CounterStyle(ref rule) => { CssRule::CounterStyle(ref rule) => {
self.extra_data self.extra_data
.add_counter_style(guard, rule, current_layer_id)?; .add_counter_style(guard, rule, containing_rule_state.layer_id)?;
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
CssRule::Page(ref rule) => { CssRule::Page(ref rule) => {
self.extra_data.add_page(guard, rule, current_layer_id)?; self.extra_data.add_page(guard, rule, containing_rule_state.layer_id)?;
}, },
CssRule::Viewport(..) => {}, CssRule::Viewport(..) => {},
_ => { _ => {
@ -2591,7 +2684,7 @@ impl CascadeData {
if let Some(id) = data.layer_id.get(layer) { if let Some(id) = data.layer_id.get(layer) {
return *id; return *id;
} }
let id = LayerId(data.layers.len() as u32); let id = LayerId(data.layers.len() as u16);
let parent_layer_id = if layer.layer_names().len() > 1 { let parent_layer_id = if layer.layer_names().len() > 1 {
let mut parent = layer.clone(); let mut parent = layer.clone();
@ -2622,9 +2715,8 @@ impl CascadeData {
fn maybe_register_layers( fn maybe_register_layers(
data: &mut CascadeData, data: &mut CascadeData,
name: Option<&LayerName>, name: Option<&LayerName>,
current_layer: &mut LayerName, containing_rule_state: &mut ContainingRuleState,
pushed_layers: &mut usize, ) {
) -> LayerId {
let anon_name; let anon_name;
let name = match name { let name = match name {
Some(name) => name, Some(name) => name,
@ -2633,19 +2725,14 @@ impl CascadeData {
&anon_name &anon_name
}, },
}; };
let mut id = LayerId::root();
for name in name.layer_names() { for name in name.layer_names() {
current_layer.0.push(name.clone()); containing_rule_state.layer_name.0.push(name.clone());
id = maybe_register_layer(data, &current_layer); containing_rule_state.layer_id = maybe_register_layer(data, &containing_rule_state.layer_name);
*pushed_layers += 1;
} }
debug_assert_ne!(id, LayerId::root()); debug_assert_ne!(containing_rule_state.layer_id, LayerId::root());
id
} }
let mut layer_names_to_pop = 0; let saved_containing_rule_state = containing_rule_state.save();
let mut children_layer_id = current_layer_id;
match *rule { match *rule {
CssRule::Import(ref lock) => { CssRule::Import(ref lock) => {
let import_rule = lock.read_with(guard); let import_rule = lock.read_with(guard);
@ -2654,11 +2741,10 @@ impl CascadeData {
.saw_effective(import_rule); .saw_effective(import_rule);
} }
if let Some(ref layer) = import_rule.layer { if let Some(ref layer) = import_rule.layer {
children_layer_id = maybe_register_layers( maybe_register_layers(
self, self,
layer.name.as_ref(), layer.name.as_ref(),
&mut current_layer, containing_rule_state
&mut layer_names_to_pop,
); );
} }
}, },
@ -2670,25 +2756,28 @@ impl CascadeData {
}, },
CssRule::LayerBlock(ref lock) => { CssRule::LayerBlock(ref lock) => {
let layer_rule = lock.read_with(guard); let layer_rule = lock.read_with(guard);
children_layer_id = maybe_register_layers( maybe_register_layers(
self, self,
layer_rule.name.as_ref(), layer_rule.name.as_ref(),
&mut current_layer, containing_rule_state,
&mut layer_names_to_pop,
); );
}, },
CssRule::LayerStatement(ref lock) => { CssRule::LayerStatement(ref lock) => {
let layer_rule = lock.read_with(guard); let layer_rule = lock.read_with(guard);
for name in &*layer_rule.names { for name in &*layer_rule.names {
let mut pushed = 0;
// There are no children, so we can ignore the // There are no children, so we can ignore the
// return value. // return value.
maybe_register_layers(self, Some(name), &mut current_layer, &mut pushed); maybe_register_layers(self, Some(name), containing_rule_state);
for _ in 0..pushed {
current_layer.0.pop();
}
} }
}, },
CssRule::Container(ref lock) => {
let _container_rule = lock.read_with(guard);
let id = ContainerConditionId(self.container_conditions.len() as u16);
self.container_conditions.push(ContainerCondition {
parent: containing_rule_state.container_condition_id,
});
containing_rule_state.container_condition_id = id;
},
// We don't care about any other rule. // We don't care about any other rule.
_ => {}, _ => {},
} }
@ -2701,15 +2790,12 @@ impl CascadeData {
stylesheet, stylesheet,
guard, guard,
rebuild_kind, rebuild_kind,
current_layer, containing_rule_state,
children_layer_id,
precomputed_pseudo_element_decls.as_deref_mut(), precomputed_pseudo_element_decls.as_deref_mut(),
)?; )?;
} }
for _ in 0..layer_names_to_pop { containing_rule_state.restore(&saved_containing_rule_state);
current_layer.0.pop();
}
} }
Ok(()) Ok(())
@ -2738,7 +2824,7 @@ impl CascadeData {
self.effective_media_query_results.saw_effective(contents); self.effective_media_query_results.saw_effective(contents);
} }
let mut current_layer = LayerName::new_empty(); let mut state = ContainingRuleState::default();
self.add_rule_list( self.add_rule_list(
contents.rules(guard).iter(), contents.rules(guard).iter(),
device, device,
@ -2746,8 +2832,7 @@ impl CascadeData {
stylesheet, stylesheet,
guard, guard,
rebuild_kind, rebuild_kind,
&mut current_layer, &mut state,
LayerId::root(),
precomputed_pseudo_element_decls.as_deref_mut(), precomputed_pseudo_element_decls.as_deref_mut(),
)?; )?;
@ -2873,6 +2958,8 @@ impl CascadeData {
self.layer_id.clear(); self.layer_id.clear();
self.layers.clear(); self.layers.clear();
self.layers.push(CascadeLayer::root()); self.layers.push(CascadeLayer::root());
self.container_conditions.clear();
self.container_conditions.push(ContainerCondition::none());
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
{ {
self.extra_data.clear(); self.extra_data.clear();
@ -2967,6 +3054,9 @@ pub struct Rule {
/// The current layer id of this style rule. /// The current layer id of this style rule.
pub layer_id: LayerId, pub layer_id: LayerId,
/// The current @container rule id.
pub container_condition_id: ContainerConditionId,
/// The actual style rule. /// The actual style rule.
#[cfg_attr( #[cfg_attr(
feature = "gecko", feature = "gecko",
@ -3012,6 +3102,7 @@ impl Rule {
style_rule: Arc<Locked<StyleRule>>, style_rule: Arc<Locked<StyleRule>>,
source_order: u32, source_order: u32,
layer_id: LayerId, layer_id: LayerId,
container_condition_id: ContainerConditionId,
) -> Self { ) -> Self {
Rule { Rule {
selector, selector,
@ -3019,6 +3110,7 @@ impl Rule {
style_rule, style_rule,
source_order, source_order,
layer_id, layer_id,
container_condition_id,
} }
} }
} }