mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +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),
|
source: StyleSource::from_declarations(declarations),
|
||||||
bits: ApplicableDeclarationBits::new(0, level),
|
bits: ApplicableDeclarationBits::new(0, level),
|
||||||
specificity: 0,
|
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]
|
#[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 {
|
ApplicableDeclarationBlock {
|
||||||
source,
|
source,
|
||||||
bits: ApplicableDeclarationBits::new(source_order, level),
|
bits: ApplicableDeclarationBits::new(source_order, level),
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::selector_map::SelectorMap;
|
||||||
use crate::selector_parser::PseudoElement;
|
use crate::selector_parser::PseudoElement;
|
||||||
use crate::shared_lock::Locked;
|
use crate::shared_lock::Locked;
|
||||||
use crate::stylesheets::Origin;
|
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 selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||||
use servo_arc::ArcBorrow;
|
use servo_arc::ArcBorrow;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -173,7 +173,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
self.in_tree(None, |collector| {
|
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]
|
#[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");
|
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||||
SelectorMap::get_matching_rules(
|
SelectorMap::get_matching_rules(
|
||||||
self.element,
|
self.element,
|
||||||
|
@ -223,11 +223,12 @@ where
|
||||||
&mut self.context,
|
&mut self.context,
|
||||||
&mut self.flags_setter,
|
&mut self.flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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");
|
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||||
map.get_all_matching_rules(
|
map.get_all_matching_rules(
|
||||||
self.element,
|
self.element,
|
||||||
|
@ -236,6 +237,7 @@ where
|
||||||
&mut self.context,
|
&mut self.context,
|
||||||
&mut self.flags_setter,
|
&mut self.flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +279,7 @@ where
|
||||||
let cascade_level = CascadeLevel::AuthorNormal {
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
shadow_cascade_order,
|
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();
|
let cascade_level = CascadeLevel::same_tree_author_normal();
|
||||||
self.in_shadow_tree(containing_shadow.host(), |collector| {
|
self.in_shadow_tree(containing_shadow.host(), |collector| {
|
||||||
if let Some(map) = cascade_data.normal_rules(collector.pseudo_element) {
|
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
|
// Collect rules from :host::part() and such
|
||||||
|
@ -319,7 +321,7 @@ where
|
||||||
|
|
||||||
hash_target.each_part(|part| {
|
hash_target.each_part(|part| {
|
||||||
if let Some(part_rules) = part_rules.get(&part.0) {
|
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 {
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
shadow_cascade_order,
|
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 inner_shadow_host = inner_shadow.host();
|
||||||
let outer_shadow = inner_shadow_host.containing_shadow();
|
let outer_shadow = inner_shadow_host.containing_shadow();
|
||||||
let part_rules = match outer_shadow {
|
let cascade_data = match outer_shadow {
|
||||||
Some(shadow) => shadow
|
Some(shadow) => shadow.style_data(),
|
||||||
.style_data()
|
None => Some(self
|
||||||
.and_then(|data| data.part_rules(self.pseudo_element)),
|
|
||||||
None => self
|
|
||||||
.stylist
|
.stylist
|
||||||
.cascade_data()
|
.cascade_data()
|
||||||
.borrow_for_origin(Origin::Author)
|
.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 containing_host = outer_shadow.map(|s| s.host());
|
||||||
let cascade_level = CascadeLevel::AuthorNormal {
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
shadow_cascade_order,
|
shadow_cascade_order,
|
||||||
|
@ -405,12 +406,13 @@ where
|
||||||
self.in_tree(containing_host, |collector| {
|
self.in_tree(containing_host, |collector| {
|
||||||
for p in &parts {
|
for p in &parts {
|
||||||
if let Some(part_rules) = part_rules.get(&p.0) {
|
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();
|
shadow_cascade_order.inc();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inner_shadow = match outer_shadow {
|
inner_shadow = match outer_shadow {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::hash::map as hash_map;
|
||||||
use crate::hash::{HashMap, HashSet};
|
use crate::hash::{HashMap, HashSet};
|
||||||
use crate::rule_tree::CascadeLevel;
|
use crate::rule_tree::CascadeLevel;
|
||||||
use crate::selector_parser::SelectorImpl;
|
use crate::selector_parser::SelectorImpl;
|
||||||
use crate::stylist::Rule;
|
use crate::stylist::{Rule, CascadeData};
|
||||||
use crate::{Atom, LocalName, Namespace, WeakAtom};
|
use crate::{Atom, LocalName, Namespace, WeakAtom};
|
||||||
use fallible::FallibleVec;
|
use fallible::FallibleVec;
|
||||||
use hashglobe::FailedAllocationError;
|
use hashglobe::FailedAllocationError;
|
||||||
|
@ -189,6 +189,7 @@ impl SelectorMap<Rule> {
|
||||||
context: &mut MatchingContext<E::Impl>,
|
context: &mut MatchingContext<E::Impl>,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
cascade_level: CascadeLevel,
|
cascade_level: CascadeLevel,
|
||||||
|
cascade_data: &CascadeData,
|
||||||
) where
|
) where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
|
@ -207,6 +208,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +221,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +235,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -246,6 +250,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -259,6 +264,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +276,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +287,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
|
cascade_data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,6 +299,7 @@ impl SelectorMap<Rule> {
|
||||||
context: &mut MatchingContext<E::Impl>,
|
context: &mut MatchingContext<E::Impl>,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
cascade_level: CascadeLevel,
|
cascade_level: CascadeLevel,
|
||||||
|
cascade_data: &CascadeData,
|
||||||
) where
|
) where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
|
@ -304,7 +313,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
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::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard};
|
||||||
use crate::shared_lock::{Locked, ToCssWithGuard};
|
use crate::shared_lock::{Locked, ToCssWithGuard};
|
||||||
use crate::str::CssStringWriter;
|
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::rule_parser::VendorPrefix;
|
||||||
use crate::stylesheets::{CssRuleType, StylesheetContents};
|
use crate::stylesheets::{CssRuleType, StylesheetContents};
|
||||||
use crate::values::{serialize_percentage, KeyframesName};
|
use crate::values::{serialize_percentage, KeyframesName};
|
||||||
|
@ -358,8 +358,8 @@ pub struct KeyframesAnimation {
|
||||||
pub properties_changed: LonghandIdSet,
|
pub properties_changed: LonghandIdSet,
|
||||||
/// Vendor prefix type the @keyframes has.
|
/// Vendor prefix type the @keyframes has.
|
||||||
pub vendor_prefix: Option<VendorPrefix>,
|
pub vendor_prefix: Option<VendorPrefix>,
|
||||||
/// The order of the cascade layer the keyframe rule was in.
|
/// The id of the cascade layer the keyframe rule was in.
|
||||||
pub layer_order: LayerOrder,
|
pub layer_id: LayerId,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all the animated properties in a keyframes animation.
|
/// Get all the animated properties in a keyframes animation.
|
||||||
|
@ -412,14 +412,14 @@ impl KeyframesAnimation {
|
||||||
pub fn from_keyframes(
|
pub fn from_keyframes(
|
||||||
keyframes: &[Arc<Locked<Keyframe>>],
|
keyframes: &[Arc<Locked<Keyframe>>],
|
||||||
vendor_prefix: Option<VendorPrefix>,
|
vendor_prefix: Option<VendorPrefix>,
|
||||||
layer_order: LayerOrder,
|
layer_id: LayerId,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut result = KeyframesAnimation {
|
let mut result = KeyframesAnimation {
|
||||||
steps: vec![],
|
steps: vec![],
|
||||||
properties_changed: LonghandIdSet::new(),
|
properties_changed: LonghandIdSet::new(),
|
||||||
vendor_prefix,
|
vendor_prefix,
|
||||||
layer_order,
|
layer_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
if keyframes.is_empty() {
|
if keyframes.is_empty() {
|
||||||
|
|
|
@ -19,94 +19,36 @@ use smallvec::SmallVec;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ParseError, ToCss};
|
use style_traits::{CssWriter, ParseError, ToCss};
|
||||||
|
|
||||||
/// The order of a given layer. We encode in a 32-bit integer as follows:
|
/// The order of a given layer.
|
||||||
///
|
|
||||||
/// * 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.
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct LayerOrder(u32);
|
pub struct LayerOrder(u32);
|
||||||
|
|
||||||
impl LayerOrder {
|
impl LayerOrder {
|
||||||
const FIRST_LEVEL_BITS: usize = 7;
|
/// The order of the root layer.
|
||||||
const CHILD_BITS: usize = 5;
|
pub const fn root() -> Self {
|
||||||
const FIRST_LEVEL_MASK: u32 = 0b11111110_00000000_00000000_00000000;
|
Self(std::u32::MAX)
|
||||||
const CHILD_MASK: u32 = 0b00011111;
|
|
||||||
|
|
||||||
/// Get the raw value.
|
|
||||||
pub fn raw(self) -> u32 {
|
|
||||||
self.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The top level layer (implicit) is zero.
|
/// The first cascade layer order.
|
||||||
#[inline]
|
pub const fn first() -> Self {
|
||||||
pub const fn top_level() -> Self {
|
|
||||||
Self(0)
|
Self(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The first layer order.
|
/// Increment the cascade layer order.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn first() -> Self {
|
pub fn inc(&mut self) {
|
||||||
Self(1 << (32 - Self::FIRST_LEVEL_BITS))
|
self.0 += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn child_bit_offset(self) -> usize {
|
/// The id of a given layer, a sequentially-increasing identifier.
|
||||||
if self.0 & (Self::CHILD_MASK << 5) != 0 {
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
|
||||||
return 0; // We're at the last or next-to-last level.
|
pub struct LayerId(pub u32);
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sibling_bit_mask_max_and_offset(self) -> (u32, u32, u32) {
|
impl LayerId {
|
||||||
debug_assert_ne!(self.0, 0, "Top layer should have no siblings");
|
/// The id of the root layer.
|
||||||
for offset in &[0, 5, 10, 15, 20] {
|
pub const fn root() -> Self {
|
||||||
let mask = Self::CHILD_MASK << *offset;
|
Self(0)
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,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::{LayerName, LayerOrder};
|
use crate::stylesheets::layer_rule::{LayerName, LayerId, LayerOrder};
|
||||||
use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
|
use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
|
||||||
use crate::stylesheets::{StyleRule, StylesheetInDocument, StylesheetContents};
|
use crate::stylesheets::{StyleRule, StylesheetInDocument, StylesheetContents};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -293,6 +293,8 @@ impl CascadeDataCacheEntry for UserAgentCascadeData {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_data.cascade_data.compute_layer_order();
|
||||||
|
|
||||||
Ok(Arc::new(new_data))
|
Ok(Arc::new(new_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1867,12 +1869,21 @@ impl PartElementAndPseudoRules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
struct LayerOrderState {
|
struct CascadeLayer {
|
||||||
/// The order for this layer.
|
id: LayerId,
|
||||||
order: LayerOrder,
|
order: LayerOrder,
|
||||||
/// The order for the next registered child layer.
|
children: Vec<LayerId>,
|
||||||
next_child: LayerOrder,
|
}
|
||||||
|
|
||||||
|
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
|
/// Data resulting from performing the CSS cascade that is specific to a given
|
||||||
|
@ -1941,10 +1952,10 @@ pub struct CascadeData {
|
||||||
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
|
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
|
||||||
|
|
||||||
/// A map from cascade layer name to layer order.
|
/// 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.
|
/// The list of cascade layers, indexed by their layer id.
|
||||||
next_layer_order: LayerOrder,
|
layers: SmallVec<[CascadeLayer; 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,
|
||||||
|
@ -1986,8 +1997,8 @@ impl CascadeData {
|
||||||
// somewhat gnarly.
|
// somewhat gnarly.
|
||||||
selectors_for_cache_revalidation: SelectorMap::new_without_attribute_bucketing(),
|
selectors_for_cache_revalidation: SelectorMap::new_without_attribute_bucketing(),
|
||||||
animations: Default::default(),
|
animations: Default::default(),
|
||||||
layer_order: Default::default(),
|
layer_id: Default::default(),
|
||||||
next_layer_order: LayerOrder::first(),
|
layers: smallvec::smallvec![CascadeLayer::root()],
|
||||||
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,
|
||||||
|
@ -2034,6 +2045,8 @@ impl CascadeData {
|
||||||
result.is_ok()
|
result.is_ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.compute_layer_order();
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2095,6 +2108,43 @@ impl CascadeData {
|
||||||
self.part_rules.is_some()
|
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`.
|
/// Collects all the applicable media query results into `results`.
|
||||||
///
|
///
|
||||||
/// This duplicates part of the logic in `add_stylesheet`, which is
|
/// This duplicates part of the logic in `add_stylesheet`, which is
|
||||||
|
@ -2151,7 +2201,7 @@ impl CascadeData {
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
rebuild_kind: SheetRebuildKind,
|
rebuild_kind: SheetRebuildKind,
|
||||||
mut current_layer: &mut LayerName,
|
mut current_layer: &mut LayerName,
|
||||||
current_layer_order: LayerOrder,
|
current_layer_id: LayerId,
|
||||||
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
|
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
|
||||||
) -> Result<(), FailedAllocationError>
|
) -> Result<(), FailedAllocationError>
|
||||||
where
|
where
|
||||||
|
@ -2174,6 +2224,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());
|
||||||
|
|
||||||
precomputed_pseudo_element_decls
|
precomputed_pseudo_element_decls
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -2184,7 +2235,7 @@ impl CascadeData {
|
||||||
self.rules_source_order,
|
self.rules_source_order,
|
||||||
CascadeLevel::UANormal,
|
CascadeLevel::UANormal,
|
||||||
selector.specificity(),
|
selector.specificity(),
|
||||||
current_layer_order,
|
LayerOrder::root(),
|
||||||
));
|
));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2200,7 +2251,7 @@ impl CascadeData {
|
||||||
hashes,
|
hashes,
|
||||||
locked.clone(),
|
locked.clone(),
|
||||||
self.rules_source_order,
|
self.rules_source_order,
|
||||||
current_layer_order,
|
current_layer_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
if rebuild_kind.should_rebuild_invalidation() {
|
if rebuild_kind.should_rebuild_invalidation() {
|
||||||
|
@ -2277,22 +2328,24 @@ impl CascadeData {
|
||||||
e.insert(KeyframesAnimation::from_keyframes(
|
e.insert(KeyframesAnimation::from_keyframes(
|
||||||
&keyframes_rule.keyframes,
|
&keyframes_rule.keyframes,
|
||||||
keyframes_rule.vendor_prefix.clone(),
|
keyframes_rule.vendor_prefix.clone(),
|
||||||
current_layer_order,
|
current_layer_id,
|
||||||
guard,
|
guard,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
Entry::Occupied(mut e) => {
|
Entry::Occupied(mut e) => {
|
||||||
// Don't let a prefixed keyframes animation override
|
// 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 =
|
let needs_insert =
|
||||||
current_layer_order > e.get().layer_order ||
|
keyframes_rule.vendor_prefix.is_none() ||
|
||||||
(current_layer_order == e.get().layer_order &&
|
e.get().vendor_prefix.is_some();
|
||||||
(keyframes_rule.vendor_prefix.is_none() || e.get().vendor_prefix.is_some()));
|
|
||||||
if needs_insert {
|
if needs_insert {
|
||||||
e.insert(KeyframesAnimation::from_keyframes(
|
e.insert(KeyframesAnimation::from_keyframes(
|
||||||
&keyframes_rule.keyframes,
|
&keyframes_rule.keyframes,
|
||||||
keyframes_rule.vendor_prefix.clone(),
|
keyframes_rule.vendor_prefix.clone(),
|
||||||
current_layer_order,
|
current_layer_id,
|
||||||
guard,
|
guard,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -2360,32 +2413,38 @@ impl CascadeData {
|
||||||
continue;
|
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
|
// TODO: Measure what's more common / expensive, if
|
||||||
// layer.clone() or the double hash lookup in the insert
|
// layer.clone() or the double hash lookup in the insert
|
||||||
// case.
|
// case.
|
||||||
if let Some(ref mut state) = data.layer_order.get(layer) {
|
if let Some(id) = data.layer_id.get(layer) {
|
||||||
return state.order;
|
return *id;
|
||||||
}
|
}
|
||||||
// If the layer is not top-level, find the relevant parent.
|
let id = LayerId(data.layers.len() as u32);
|
||||||
let order = 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();
|
||||||
parent.0.pop();
|
parent.0.pop();
|
||||||
|
|
||||||
let mut parent_state = data.layer_order.get_mut(&parent).expect("Parent layers should be registered before child layers");
|
*data.layer_id
|
||||||
let order = parent_state.next_child;
|
.get_mut(&parent)
|
||||||
parent_state.next_child = order.for_next_sibling();
|
.expect("Parent layers should be registered before child layers")
|
||||||
order
|
|
||||||
} else {
|
} else {
|
||||||
let order = data.next_layer_order;
|
LayerId::root()
|
||||||
data.next_layer_order = order.for_next_sibling();
|
|
||||||
order
|
|
||||||
};
|
};
|
||||||
data.layer_order.insert(layer.clone(), LayerOrderState {
|
|
||||||
order,
|
data.layers[parent_layer_id.0 as usize].children.push(id);
|
||||||
next_child: order.for_child(),
|
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(
|
fn maybe_register_layers(
|
||||||
|
@ -2393,7 +2452,7 @@ impl CascadeData {
|
||||||
name: Option<&LayerName>,
|
name: Option<&LayerName>,
|
||||||
current_layer: &mut LayerName,
|
current_layer: &mut LayerName,
|
||||||
pushed_layers: &mut usize,
|
pushed_layers: &mut usize,
|
||||||
) -> LayerOrder {
|
) -> LayerId {
|
||||||
let anon_name;
|
let anon_name;
|
||||||
let name = match name {
|
let name = match name {
|
||||||
Some(name) => 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() {
|
for name in name.layer_names() {
|
||||||
current_layer.0.push(name.clone());
|
current_layer.0.push(name.clone());
|
||||||
order = maybe_register_layer(data, ¤t_layer);
|
id = maybe_register_layer(data, ¤t_layer);
|
||||||
*pushed_layers += 1;
|
*pushed_layers += 1;
|
||||||
}
|
}
|
||||||
debug_assert_ne!(order, LayerOrder::top_level());
|
debug_assert_ne!(id, LayerId::root());
|
||||||
order
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut layer_names_to_pop = 0;
|
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 {
|
match *rule {
|
||||||
CssRule::Import(ref lock) => {
|
CssRule::Import(ref lock) => {
|
||||||
let import_rule = lock.read_with(guard);
|
let import_rule = lock.read_with(guard);
|
||||||
|
@ -2423,7 +2482,7 @@ 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_order = maybe_register_layers(
|
children_layer_id = maybe_register_layers(
|
||||||
self,
|
self,
|
||||||
layer.name.as_ref(),
|
layer.name.as_ref(),
|
||||||
&mut current_layer,
|
&mut current_layer,
|
||||||
|
@ -2444,7 +2503,7 @@ impl CascadeData {
|
||||||
let layer_rule = lock.read_with(guard);
|
let layer_rule = lock.read_with(guard);
|
||||||
match layer_rule.kind {
|
match layer_rule.kind {
|
||||||
LayerRuleKind::Block { ref name, .. } => {
|
LayerRuleKind::Block { ref name, .. } => {
|
||||||
children_layer_order = maybe_register_layers(
|
children_layer_id = maybe_register_layers(
|
||||||
self,
|
self,
|
||||||
name.as_ref(),
|
name.as_ref(),
|
||||||
&mut current_layer,
|
&mut current_layer,
|
||||||
|
@ -2482,7 +2541,7 @@ impl CascadeData {
|
||||||
guard,
|
guard,
|
||||||
rebuild_kind,
|
rebuild_kind,
|
||||||
current_layer,
|
current_layer,
|
||||||
children_layer_order,
|
children_layer_id,
|
||||||
precomputed_pseudo_element_decls.as_deref_mut(),
|
precomputed_pseudo_element_decls.as_deref_mut(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -2527,7 +2586,7 @@ impl CascadeData {
|
||||||
guard,
|
guard,
|
||||||
rebuild_kind,
|
rebuild_kind,
|
||||||
&mut current_layer,
|
&mut current_layer,
|
||||||
LayerOrder::top_level(),
|
LayerId::root(),
|
||||||
precomputed_pseudo_element_decls.as_deref_mut(),
|
precomputed_pseudo_element_decls.as_deref_mut(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -2646,8 +2705,9 @@ impl CascadeData {
|
||||||
host_rules.clear();
|
host_rules.clear();
|
||||||
}
|
}
|
||||||
self.animations.clear();
|
self.animations.clear();
|
||||||
self.layer_order.clear();
|
self.layer_id.clear();
|
||||||
self.next_layer_order = LayerOrder::first();
|
self.layers.clear();
|
||||||
|
self.layers.push(CascadeLayer::root());
|
||||||
self.extra_data.clear();
|
self.extra_data.clear();
|
||||||
self.rules_source_order = 0;
|
self.rules_source_order = 0;
|
||||||
self.num_selectors = 0;
|
self.num_selectors = 0;
|
||||||
|
@ -2736,8 +2796,8 @@ pub struct Rule {
|
||||||
/// we could repurpose that storage here if we needed to.
|
/// we could repurpose that storage here if we needed to.
|
||||||
pub source_order: u32,
|
pub source_order: u32,
|
||||||
|
|
||||||
/// The current layer order of this style rule.
|
/// The current layer id of this style rule.
|
||||||
pub layer_order: LayerOrder,
|
pub layer_id: LayerId,
|
||||||
|
|
||||||
/// The actual style rule.
|
/// The actual style rule.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
|
@ -2765,9 +2825,16 @@ impl Rule {
|
||||||
pub fn to_applicable_declaration_block(
|
pub fn to_applicable_declaration_block(
|
||||||
&self,
|
&self,
|
||||||
level: CascadeLevel,
|
level: CascadeLevel,
|
||||||
|
cascade_data: &CascadeData,
|
||||||
) -> ApplicableDeclarationBlock {
|
) -> ApplicableDeclarationBlock {
|
||||||
let source = StyleSource::from_rule(self.style_rule.clone());
|
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.
|
/// Creates a new Rule.
|
||||||
|
@ -2776,14 +2843,14 @@ impl Rule {
|
||||||
hashes: AncestorHashes,
|
hashes: AncestorHashes,
|
||||||
style_rule: Arc<Locked<StyleRule>>,
|
style_rule: Arc<Locked<StyleRule>>,
|
||||||
source_order: u32,
|
source_order: u32,
|
||||||
layer_order: LayerOrder,
|
layer_id: LayerId,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Rule {
|
Rule {
|
||||||
selector,
|
selector,
|
||||||
hashes,
|
hashes,
|
||||||
style_rule,
|
style_rule,
|
||||||
source_order,
|
source_order,
|
||||||
layer_order,
|
layer_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue