style: Update layer ordering to follow the spec

The bitfield approach worked when the layer order was in pre-order, but
the spec was changed to make it work like post-order and I don't think
there's a way to keep it working like that, so keep the layer order in a
separate data structure that we look up when going from Rule to
ApplicableDeclarationBlock.

This is just a vector index operation so hopefully shouldn't be too bad.

This patch intentionally regresses @keyframe handling to some extent,
since we need a bit more complicated approach and it seemed worth
implementing in a separate patch.

Depends on D129380

Differential Revision: https://phabricator.services.mozilla.com/D129381
This commit is contained in:
Emilio Cobos Álvarez 2023-05-27 17:36:01 +02:00 committed by Oriol Brufau
parent 5f2a29659f
commit 1b2ef21c8c
6 changed files with 190 additions and 164 deletions

View file

@ -25,7 +25,7 @@ use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind};
use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher};
use crate::stylesheets::keyframes_rule::KeyframesAnimation;
use crate::stylesheets::layer_rule::{LayerName, LayerOrder};
use crate::stylesheets::layer_rule::{LayerName, LayerId, LayerOrder};
use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
use crate::stylesheets::{StyleRule, StylesheetInDocument, StylesheetContents};
#[cfg(feature = "gecko")]
@ -293,6 +293,8 @@ impl CascadeDataCacheEntry for UserAgentCascadeData {
)?;
}
new_data.cascade_data.compute_layer_order();
Ok(Arc::new(new_data))
}
@ -1867,12 +1869,21 @@ impl PartElementAndPseudoRules {
}
}
#[derive(Debug, Clone, MallocSizeOf)]
struct LayerOrderState {
/// The order for this layer.
#[derive(Clone, Debug, MallocSizeOf)]
struct CascadeLayer {
id: LayerId,
order: LayerOrder,
/// The order for the next registered child layer.
next_child: LayerOrder,
children: Vec<LayerId>,
}
impl CascadeLayer {
const fn root() -> Self {
Self {
id: LayerId::root(),
order: LayerOrder::root(),
children: vec![],
}
}
}
/// Data resulting from performing the CSS cascade that is specific to a given
@ -1941,10 +1952,10 @@ pub struct CascadeData {
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
/// A map from cascade layer name to layer order.
layer_order: FxHashMap<LayerName, LayerOrderState>,
layer_id: FxHashMap<LayerName, LayerId>,
/// The next layer order for the top level cascade data.
next_layer_order: LayerOrder,
/// The list of cascade layers, indexed by their layer id.
layers: SmallVec<[CascadeLayer; 1]>,
/// Effective media query results cached from the last rebuild.
effective_media_query_results: EffectiveMediaQueryResults,
@ -1986,8 +1997,8 @@ impl CascadeData {
// somewhat gnarly.
selectors_for_cache_revalidation: SelectorMap::new_without_attribute_bucketing(),
animations: Default::default(),
layer_order: Default::default(),
next_layer_order: LayerOrder::first(),
layer_id: Default::default(),
layers: smallvec::smallvec![CascadeLayer::root()],
extra_data: ExtraStyleData::default(),
effective_media_query_results: EffectiveMediaQueryResults::new(),
rules_source_order: 0,
@ -2034,6 +2045,8 @@ impl CascadeData {
result.is_ok()
});
self.compute_layer_order();
result
}
@ -2095,6 +2108,43 @@ impl CascadeData {
self.part_rules.is_some()
}
#[inline]
fn layer_order_for(&self, id: LayerId) -> LayerOrder {
self.layers[id.0 as usize].order
}
fn compute_layer_order(&mut self) {
debug_assert_ne!(self.layers.len(), 0, "There should be at least the root layer!");
if self.layers.len() == 1 {
return; // Nothing to do
}
let (first, remaining) = self.layers.split_at_mut(1);
let root = &mut first[0];
let mut order = LayerOrder::first();
compute_layer_order_for_subtree(root, remaining, &mut order);
// NOTE(emilio): This is a bit trickier than it should to avoid having
// to clone() around layer indices.
fn compute_layer_order_for_subtree(
parent: &mut CascadeLayer,
remaining_layers: &mut [CascadeLayer],
order: &mut LayerOrder,
) {
for child in parent.children.iter() {
debug_assert!(parent.id < *child, "Children are always registered after parents");
let child_index = (child.0 - parent.id.0 - 1) as usize;
let (first, remaining) = remaining_layers.split_at_mut(child_index + 1);
let child = &mut first[child_index];
compute_layer_order_for_subtree(child, remaining, order);
}
if parent.id != LayerId::root() {
parent.order = *order;
order.inc();
}
}
}
/// Collects all the applicable media query results into `results`.
///
/// This duplicates part of the logic in `add_stylesheet`, which is
@ -2151,7 +2201,7 @@ impl CascadeData {
guard: &SharedRwLockReadGuard,
rebuild_kind: SheetRebuildKind,
mut current_layer: &mut LayerName,
current_layer_order: LayerOrder,
current_layer_id: LayerId,
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
) -> Result<(), FailedAllocationError>
where
@ -2174,6 +2224,7 @@ impl CascadeData {
if pseudo.is_precomputed() {
debug_assert!(selector.is_universal());
debug_assert_eq!(stylesheet.contents().origin, Origin::UserAgent);
debug_assert_eq!(current_layer_id, LayerId::root());
precomputed_pseudo_element_decls
.as_mut()
@ -2184,7 +2235,7 @@ impl CascadeData {
self.rules_source_order,
CascadeLevel::UANormal,
selector.specificity(),
current_layer_order,
LayerOrder::root(),
));
continue;
}
@ -2200,7 +2251,7 @@ impl CascadeData {
hashes,
locked.clone(),
self.rules_source_order,
current_layer_order,
current_layer_id,
);
if rebuild_kind.should_rebuild_invalidation() {
@ -2277,22 +2328,24 @@ impl CascadeData {
e.insert(KeyframesAnimation::from_keyframes(
&keyframes_rule.keyframes,
keyframes_rule.vendor_prefix.clone(),
current_layer_order,
current_layer_id,
guard,
));
},
Entry::Occupied(mut e) => {
// Don't let a prefixed keyframes animation override
// a non-prefixed one on the same layer.
// a non-prefixed one.
//
// TODO(emilio): This will need to be harder for
// layers.
let needs_insert =
current_layer_order > e.get().layer_order ||
(current_layer_order == e.get().layer_order &&
(keyframes_rule.vendor_prefix.is_none() || e.get().vendor_prefix.is_some()));
keyframes_rule.vendor_prefix.is_none() ||
e.get().vendor_prefix.is_some();
if needs_insert {
e.insert(KeyframesAnimation::from_keyframes(
&keyframes_rule.keyframes,
keyframes_rule.vendor_prefix.clone(),
current_layer_order,
current_layer_id,
guard,
));
}
@ -2360,32 +2413,38 @@ impl CascadeData {
continue;
}
fn maybe_register_layer(data: &mut CascadeData, layer: &LayerName) -> LayerOrder {
fn maybe_register_layer(data: &mut CascadeData, layer: &LayerName) -> LayerId {
// TODO: Measure what's more common / expensive, if
// layer.clone() or the double hash lookup in the insert
// case.
if let Some(ref mut state) = data.layer_order.get(layer) {
return state.order;
if let Some(id) = data.layer_id.get(layer) {
return *id;
}
// If the layer is not top-level, find the relevant parent.
let order = if layer.layer_names().len() > 1 {
let id = LayerId(data.layers.len() as u32);
let parent_layer_id = if layer.layer_names().len() > 1 {
let mut parent = layer.clone();
parent.0.pop();
let mut parent_state = data.layer_order.get_mut(&parent).expect("Parent layers should be registered before child layers");
let order = parent_state.next_child;
parent_state.next_child = order.for_next_sibling();
order
*data.layer_id
.get_mut(&parent)
.expect("Parent layers should be registered before child layers")
} else {
let order = data.next_layer_order;
data.next_layer_order = order.for_next_sibling();
order
LayerId::root()
};
data.layer_order.insert(layer.clone(), LayerOrderState {
order,
next_child: order.for_child(),
data.layers[parent_layer_id.0 as usize].children.push(id);
data.layers.push(CascadeLayer {
id,
// NOTE(emilio): Order is evaluated after rebuild in
// compute_layer_order.
order: LayerOrder::first(),
children: vec![],
});
order
data.layer_id.insert(layer.clone(), id);
id
}
fn maybe_register_layers(
@ -2393,7 +2452,7 @@ impl CascadeData {
name: Option<&LayerName>,
current_layer: &mut LayerName,
pushed_layers: &mut usize,
) -> LayerOrder {
) -> LayerId {
let anon_name;
let name = match name {
Some(name) => name,
@ -2403,18 +2462,18 @@ impl CascadeData {
},
};
let mut order = LayerOrder::top_level();
let mut id = LayerId::root();
for name in name.layer_names() {
current_layer.0.push(name.clone());
order = maybe_register_layer(data, &current_layer);
id = maybe_register_layer(data, &current_layer);
*pushed_layers += 1;
}
debug_assert_ne!(order, LayerOrder::top_level());
order
debug_assert_ne!(id, LayerId::root());
id
}
let mut layer_names_to_pop = 0;
let mut children_layer_order = current_layer_order;
let mut children_layer_id = current_layer_id;
match *rule {
CssRule::Import(ref lock) => {
let import_rule = lock.read_with(guard);
@ -2423,7 +2482,7 @@ impl CascadeData {
.saw_effective(import_rule);
}
if let Some(ref layer) = import_rule.layer {
children_layer_order = maybe_register_layers(
children_layer_id = maybe_register_layers(
self,
layer.name.as_ref(),
&mut current_layer,
@ -2444,7 +2503,7 @@ impl CascadeData {
let layer_rule = lock.read_with(guard);
match layer_rule.kind {
LayerRuleKind::Block { ref name, .. } => {
children_layer_order = maybe_register_layers(
children_layer_id = maybe_register_layers(
self,
name.as_ref(),
&mut current_layer,
@ -2482,7 +2541,7 @@ impl CascadeData {
guard,
rebuild_kind,
current_layer,
children_layer_order,
children_layer_id,
precomputed_pseudo_element_decls.as_deref_mut(),
)?;
}
@ -2527,7 +2586,7 @@ impl CascadeData {
guard,
rebuild_kind,
&mut current_layer,
LayerOrder::top_level(),
LayerId::root(),
precomputed_pseudo_element_decls.as_deref_mut(),
)?;
@ -2646,8 +2705,9 @@ impl CascadeData {
host_rules.clear();
}
self.animations.clear();
self.layer_order.clear();
self.next_layer_order = LayerOrder::first();
self.layer_id.clear();
self.layers.clear();
self.layers.push(CascadeLayer::root());
self.extra_data.clear();
self.rules_source_order = 0;
self.num_selectors = 0;
@ -2736,8 +2796,8 @@ pub struct Rule {
/// we could repurpose that storage here if we needed to.
pub source_order: u32,
/// The current layer order of this style rule.
pub layer_order: LayerOrder,
/// The current layer id of this style rule.
pub layer_id: LayerId,
/// The actual style rule.
#[cfg_attr(
@ -2765,9 +2825,16 @@ impl Rule {
pub fn to_applicable_declaration_block(
&self,
level: CascadeLevel,
cascade_data: &CascadeData,
) -> ApplicableDeclarationBlock {
let source = StyleSource::from_rule(self.style_rule.clone());
ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), self.layer_order)
ApplicableDeclarationBlock::new(
source,
self.source_order,
level,
self.specificity(),
cascade_data.layer_order_for(self.layer_id),
)
}
/// Creates a new Rule.
@ -2776,14 +2843,14 @@ impl Rule {
hashes: AncestorHashes,
style_rule: Arc<Locked<StyleRule>>,
source_order: u32,
layer_order: LayerOrder,
layer_id: LayerId,
) -> Self {
Rule {
selector,
hashes,
style_rule,
source_order,
layer_order,
layer_id,
}
}
}