mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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:
parent
5f2a29659f
commit
1b2ef21c8c
6 changed files with 190 additions and 164 deletions
|
@ -88,13 +88,19 @@ impl ApplicableDeclarationBlock {
|
|||
source: StyleSource::from_declarations(declarations),
|
||||
bits: ApplicableDeclarationBits::new(0, level),
|
||||
specificity: 0,
|
||||
layer_order: LayerOrder::first(),
|
||||
layer_order: LayerOrder::root(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an applicable declaration block from the given components
|
||||
/// Constructs an applicable declaration block from the given components.
|
||||
#[inline]
|
||||
pub fn new(source: StyleSource, source_order: u32, level: CascadeLevel, specificity: u32, layer_order: LayerOrder) -> Self {
|
||||
pub fn new(
|
||||
source: StyleSource,
|
||||
source_order: u32,
|
||||
level: CascadeLevel,
|
||||
specificity: u32,
|
||||
layer_order: LayerOrder,
|
||||
) -> Self {
|
||||
ApplicableDeclarationBlock {
|
||||
source,
|
||||
bits: ApplicableDeclarationBits::new(source_order, level),
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::selector_map::SelectorMap;
|
|||
use crate::selector_parser::PseudoElement;
|
||||
use crate::shared_lock::Locked;
|
||||
use crate::stylesheets::Origin;
|
||||
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
|
||||
use crate::stylist::{AuthorStylesEnabled, CascadeData, Rule, RuleInclusion, Stylist};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||
use servo_arc::ArcBorrow;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -173,7 +173,7 @@ where
|
|||
};
|
||||
|
||||
self.in_tree(None, |collector| {
|
||||
collector.collect_rules_in_map(map, cascade_level);
|
||||
collector.collect_rules_in_map(map, cascade_level, cascade_data);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_rules_in_list(&mut self, part_rules: &[Rule], cascade_level: CascadeLevel) {
|
||||
fn collect_rules_in_list(&mut self, part_rules: &[Rule], cascade_level: CascadeLevel, cascade_data: &CascadeData) {
|
||||
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||
SelectorMap::get_matching_rules(
|
||||
self.element,
|
||||
|
@ -223,11 +223,12 @@ where
|
|||
&mut self.context,
|
||||
&mut self.flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_rules_in_map(&mut self, map: &SelectorMap<Rule>, cascade_level: CascadeLevel) {
|
||||
fn collect_rules_in_map(&mut self, map: &SelectorMap<Rule>, cascade_level: CascadeLevel, cascade_data: &CascadeData) {
|
||||
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||
map.get_all_matching_rules(
|
||||
self.element,
|
||||
|
@ -236,6 +237,7 @@ where
|
|||
&mut self.context,
|
||||
&mut self.flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -277,7 +279,7 @@ where
|
|||
let cascade_level = CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
};
|
||||
collector.collect_rules_in_map(slotted_rules, cascade_level);
|
||||
collector.collect_rules_in_map(slotted_rules, cascade_level, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +305,7 @@ where
|
|||
let cascade_level = CascadeLevel::same_tree_author_normal();
|
||||
self.in_shadow_tree(containing_shadow.host(), |collector| {
|
||||
if let Some(map) = cascade_data.normal_rules(collector.pseudo_element) {
|
||||
collector.collect_rules_in_map(map, cascade_level);
|
||||
collector.collect_rules_in_map(map, cascade_level, cascade_data);
|
||||
}
|
||||
|
||||
// Collect rules from :host::part() and such
|
||||
|
@ -319,7 +321,7 @@ where
|
|||
|
||||
hash_target.each_part(|part| {
|
||||
if let Some(part_rules) = part_rules.get(&part.0) {
|
||||
collector.collect_rules_in_list(part_rules, cascade_level);
|
||||
collector.collect_rules_in_list(part_rules, cascade_level, cascade_data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -352,7 +354,7 @@ where
|
|||
let cascade_level = CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
};
|
||||
collector.collect_rules_in_map(host_rules, cascade_level);
|
||||
collector.collect_rules_in_map(host_rules, cascade_level, style_data);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -386,18 +388,17 @@ where
|
|||
|
||||
let inner_shadow_host = inner_shadow.host();
|
||||
let outer_shadow = inner_shadow_host.containing_shadow();
|
||||
let part_rules = match outer_shadow {
|
||||
Some(shadow) => shadow
|
||||
.style_data()
|
||||
.and_then(|data| data.part_rules(self.pseudo_element)),
|
||||
None => self
|
||||
let cascade_data = match outer_shadow {
|
||||
Some(shadow) => shadow.style_data(),
|
||||
None => Some(self
|
||||
.stylist
|
||||
.cascade_data()
|
||||
.borrow_for_origin(Origin::Author)
|
||||
.part_rules(self.pseudo_element),
|
||||
),
|
||||
};
|
||||
|
||||
if let Some(part_rules) = part_rules {
|
||||
if let Some(cascade_data) = cascade_data {
|
||||
if let Some(part_rules) = cascade_data.part_rules(self.pseudo_element) {
|
||||
let containing_host = outer_shadow.map(|s| s.host());
|
||||
let cascade_level = CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
|
@ -405,12 +406,13 @@ where
|
|||
self.in_tree(containing_host, |collector| {
|
||||
for p in &parts {
|
||||
if let Some(part_rules) = part_rules.get(&p.0) {
|
||||
collector.collect_rules_in_list(part_rules, cascade_level);
|
||||
collector.collect_rules_in_list(part_rules, cascade_level, cascade_data);
|
||||
}
|
||||
}
|
||||
});
|
||||
shadow_cascade_order.inc();
|
||||
}
|
||||
}
|
||||
|
||||
inner_shadow = match outer_shadow {
|
||||
Some(s) => s,
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::hash::map as hash_map;
|
|||
use crate::hash::{HashMap, HashSet};
|
||||
use crate::rule_tree::CascadeLevel;
|
||||
use crate::selector_parser::SelectorImpl;
|
||||
use crate::stylist::Rule;
|
||||
use crate::stylist::{Rule, CascadeData};
|
||||
use crate::{Atom, LocalName, Namespace, WeakAtom};
|
||||
use fallible::FallibleVec;
|
||||
use hashglobe::FailedAllocationError;
|
||||
|
@ -189,6 +189,7 @@ impl SelectorMap<Rule> {
|
|||
context: &mut MatchingContext<E::Impl>,
|
||||
flags_setter: &mut F,
|
||||
cascade_level: CascadeLevel,
|
||||
cascade_data: &CascadeData,
|
||||
) where
|
||||
E: TElement,
|
||||
F: FnMut(&E, ElementSelectorFlags),
|
||||
|
@ -207,6 +208,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -219,6 +221,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -232,6 +235,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
)
|
||||
}
|
||||
});
|
||||
|
@ -246,6 +250,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
)
|
||||
}
|
||||
});
|
||||
|
@ -259,6 +264,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -270,6 +276,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -280,6 +287,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
cascade_data,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -291,6 +299,7 @@ impl SelectorMap<Rule> {
|
|||
context: &mut MatchingContext<E::Impl>,
|
||||
flags_setter: &mut F,
|
||||
cascade_level: CascadeLevel,
|
||||
cascade_data: &CascadeData,
|
||||
) where
|
||||
E: TElement,
|
||||
F: FnMut(&E, ElementSelectorFlags),
|
||||
|
@ -304,7 +313,7 @@ impl SelectorMap<Rule> {
|
|||
context,
|
||||
flags_setter,
|
||||
) {
|
||||
matching_rules.push(rule.to_applicable_declaration_block(cascade_level));
|
||||
matching_rules.push(rule.to_applicable_declaration_block(cascade_level, cascade_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::properties::{PropertyDeclarationId, SourcePropertyDeclaration};
|
|||
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard};
|
||||
use crate::shared_lock::{Locked, ToCssWithGuard};
|
||||
use crate::str::CssStringWriter;
|
||||
use crate::stylesheets::layer_rule::LayerOrder;
|
||||
use crate::stylesheets::layer_rule::LayerId;
|
||||
use crate::stylesheets::rule_parser::VendorPrefix;
|
||||
use crate::stylesheets::{CssRuleType, StylesheetContents};
|
||||
use crate::values::{serialize_percentage, KeyframesName};
|
||||
|
@ -358,8 +358,8 @@ pub struct KeyframesAnimation {
|
|||
pub properties_changed: LonghandIdSet,
|
||||
/// Vendor prefix type the @keyframes has.
|
||||
pub vendor_prefix: Option<VendorPrefix>,
|
||||
/// The order of the cascade layer the keyframe rule was in.
|
||||
pub layer_order: LayerOrder,
|
||||
/// The id of the cascade layer the keyframe rule was in.
|
||||
pub layer_id: LayerId,
|
||||
}
|
||||
|
||||
/// Get all the animated properties in a keyframes animation.
|
||||
|
@ -412,14 +412,14 @@ impl KeyframesAnimation {
|
|||
pub fn from_keyframes(
|
||||
keyframes: &[Arc<Locked<Keyframe>>],
|
||||
vendor_prefix: Option<VendorPrefix>,
|
||||
layer_order: LayerOrder,
|
||||
layer_id: LayerId,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
) -> Self {
|
||||
let mut result = KeyframesAnimation {
|
||||
steps: vec![],
|
||||
properties_changed: LonghandIdSet::new(),
|
||||
vendor_prefix,
|
||||
layer_order,
|
||||
layer_id,
|
||||
};
|
||||
|
||||
if keyframes.is_empty() {
|
||||
|
|
|
@ -19,94 +19,36 @@ use smallvec::SmallVec;
|
|||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ParseError, ToCss};
|
||||
|
||||
/// The order of a given layer. We encode in a 32-bit integer as follows:
|
||||
///
|
||||
/// * 0 is reserved for the initial (top-level) layer.
|
||||
/// * Top 7 bits are for top level layer order.
|
||||
/// * The 25 remaining bits are split in 5 chunks of 5 bits each, for each
|
||||
/// nesting level.
|
||||
///
|
||||
/// This scheme this gives up to 127 layers in the top level, and up to 31
|
||||
/// children layers in nested levels, with a max of 6 nesting levels over all.
|
||||
///
|
||||
/// This seemingly complicated scheme is to avoid fixing up layer orders after
|
||||
/// the cascade data rebuild.
|
||||
///
|
||||
/// An alternative approach that would allow improving those limits would be to
|
||||
/// make layers have a sequential identifier, and sort layer order after the
|
||||
/// fact. But that complicates incremental cascade data rebuild.
|
||||
/// The order of a given layer.
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
|
||||
pub struct LayerOrder(u32);
|
||||
|
||||
impl LayerOrder {
|
||||
const FIRST_LEVEL_BITS: usize = 7;
|
||||
const CHILD_BITS: usize = 5;
|
||||
const FIRST_LEVEL_MASK: u32 = 0b11111110_00000000_00000000_00000000;
|
||||
const CHILD_MASK: u32 = 0b00011111;
|
||||
|
||||
/// Get the raw value.
|
||||
pub fn raw(self) -> u32 {
|
||||
self.0
|
||||
/// The order of the root layer.
|
||||
pub const fn root() -> Self {
|
||||
Self(std::u32::MAX)
|
||||
}
|
||||
|
||||
/// The top level layer (implicit) is zero.
|
||||
#[inline]
|
||||
pub const fn top_level() -> Self {
|
||||
/// The first cascade layer order.
|
||||
pub const fn first() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
/// The first layer order.
|
||||
/// Increment the cascade layer order.
|
||||
#[inline]
|
||||
pub const fn first() -> Self {
|
||||
Self(1 << (32 - Self::FIRST_LEVEL_BITS))
|
||||
pub fn inc(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn child_bit_offset(self) -> usize {
|
||||
if self.0 & (Self::CHILD_MASK << 5) != 0 {
|
||||
return 0; // We're at the last or next-to-last level.
|
||||
}
|
||||
if self.0 & (Self::CHILD_MASK << 10) != 0 {
|
||||
return 5;
|
||||
}
|
||||
if self.0 & (Self::CHILD_MASK << 15) != 0 {
|
||||
return 10;
|
||||
}
|
||||
if self.0 & (Self::CHILD_MASK << 20) != 0 {
|
||||
return 15;
|
||||
}
|
||||
if self.0 != 0 {
|
||||
return 20;
|
||||
}
|
||||
return 25;
|
||||
}
|
||||
/// The id of a given layer, a sequentially-increasing identifier.
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
|
||||
pub struct LayerId(pub u32);
|
||||
|
||||
fn sibling_bit_mask_max_and_offset(self) -> (u32, u32, u32) {
|
||||
debug_assert_ne!(self.0, 0, "Top layer should have no siblings");
|
||||
for offset in &[0, 5, 10, 15, 20] {
|
||||
let mask = Self::CHILD_MASK << *offset;
|
||||
if self.0 & mask != 0 {
|
||||
return (mask, (1 << Self::CHILD_BITS) - 1, *offset);
|
||||
}
|
||||
}
|
||||
return (Self::FIRST_LEVEL_MASK, (1 << Self::FIRST_LEVEL_BITS) - 1, 25);
|
||||
}
|
||||
|
||||
/// Generate the layer order for our first child.
|
||||
pub fn for_child(self) -> Self {
|
||||
Self(self.0 | (1 << self.child_bit_offset()))
|
||||
}
|
||||
|
||||
/// Generate the layer order for our next sibling. Might return the same
|
||||
/// order when our limits overflow.
|
||||
pub fn for_next_sibling(self) -> Self {
|
||||
let (mask, max_index, offset) = self.sibling_bit_mask_max_and_offset();
|
||||
let self_index = (self.0 & mask) >> offset;
|
||||
let next_index = if self_index == max_index {
|
||||
self_index
|
||||
} else {
|
||||
self_index + 1
|
||||
};
|
||||
Self((self.0 & !mask) | (next_index << offset))
|
||||
impl LayerId {
|
||||
/// The id of the root layer.
|
||||
pub const fn root() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ¤t_layer);
|
||||
id = maybe_register_layer(data, ¤t_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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue