diff options
Diffstat (limited to 'components/style/applicable_declarations.rs')
-rw-r--r-- | components/style/applicable_declarations.rs | 105 |
1 files changed, 67 insertions, 38 deletions
diff --git a/components/style/applicable_declarations.rs b/components/style/applicable_declarations.rs index ab7c47307d7..d4674fa1bc7 100644 --- a/components/style/applicable_declarations.rs +++ b/components/style/applicable_declarations.rs @@ -5,12 +5,11 @@ //! Applicable declarations management. use properties::PropertyDeclarationBlock; -use rule_tree::{CascadeLevel, StyleSource}; +use rule_tree::{CascadeLevel, ShadowCascadeOrder, StyleSource}; use servo_arc::Arc; use shared_lock::Locked; use smallvec::SmallVec; use std::fmt::{self, Debug}; -use std::mem; /// List of applicable declarations. This is a transient structure that shuttles /// declarations between selector matching and inserting into the rule tree, and @@ -25,45 +24,67 @@ pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>; /// That's a limit that could be reached in realistic webpages, so we use /// 24 bits and enforce defined behavior in the overflow case. /// -/// Note that the value of 24 is also hard-coded into the level() accessor, -/// which does a byte-aligned load of the 4th byte. If you change this value -/// you'll need to change that as well. -/// /// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/ /// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3 +const SOURCE_ORDER_SHIFT: usize = 0; const SOURCE_ORDER_BITS: usize = 24; -const SOURCE_ORDER_MASK: u32 = (1 << SOURCE_ORDER_BITS) - 1; -const SOURCE_ORDER_MAX: u32 = SOURCE_ORDER_MASK; +const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1; +const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT; + +/// We store up-to-15 shadow order levels. +/// +/// You'd need an element slotted across 16 components with ::slotted rules to +/// trigger this as of this writing, which looks... Unlikely. +const SHADOW_CASCADE_ORDER_SHIFT: usize = SOURCE_ORDER_BITS; +const SHADOW_CASCADE_ORDER_BITS: usize = 4; +const SHADOW_CASCADE_ORDER_MAX: u8 = (1 << SHADOW_CASCADE_ORDER_BITS) - 1; +const SHADOW_CASCADE_ORDER_MASK: u32 = (SHADOW_CASCADE_ORDER_MAX as u32) << SHADOW_CASCADE_ORDER_SHIFT; -/// Stores the source order of a block and the cascade level it belongs to. +const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS + SHADOW_CASCADE_ORDER_BITS; +const CASCADE_LEVEL_BITS: usize = 4; +const CASCADE_LEVEL_MAX: u8 = (1 << CASCADE_LEVEL_BITS) - 1; +const CASCADE_LEVEL_MASK: u32 = (CASCADE_LEVEL_MAX as u32) << CASCADE_LEVEL_SHIFT; + +/// Stores the source order of a block, the cascade level it belongs to, and the +/// counter needed to handle Shadow DOM cascade order properly. #[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)] -struct SourceOrderAndCascadeLevel(u32); +struct ApplicableDeclarationBits(u32); -impl SourceOrderAndCascadeLevel { - fn new(source_order: u32, cascade_level: CascadeLevel) -> SourceOrderAndCascadeLevel { +impl ApplicableDeclarationBits { + fn new( + source_order: u32, + cascade_level: CascadeLevel, + shadow_cascade_order: ShadowCascadeOrder, + ) -> Self { + debug_assert!( + cascade_level as u8 <= CASCADE_LEVEL_MAX, + "Gotta find more bits!" + ); let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX); - bits |= (cascade_level as u8 as u32) << SOURCE_ORDER_BITS; - SourceOrderAndCascadeLevel(bits) + bits |= ((shadow_cascade_order & SHADOW_CASCADE_ORDER_MAX) as u32) << SHADOW_CASCADE_ORDER_SHIFT; + bits |= (cascade_level as u8 as u32) << CASCADE_LEVEL_SHIFT; + ApplicableDeclarationBits(bits) } - fn order(&self) -> u32 { - self.0 & SOURCE_ORDER_MASK + fn source_order(&self) -> u32 { + (self.0 & SOURCE_ORDER_MASK) >> SOURCE_ORDER_SHIFT + } + + fn shadow_cascade_order(&self) -> ShadowCascadeOrder { + ((self.0 & SHADOW_CASCADE_ORDER_MASK) >> SHADOW_CASCADE_ORDER_SHIFT) as ShadowCascadeOrder } fn level(&self) -> CascadeLevel { - unsafe { - // Transmute rather than shifting so that we're sure the compiler - // emits a simple byte-aligned load. - let as_bytes: [u8; 4] = mem::transmute(self.0); - CascadeLevel::from_byte(as_bytes[3]) - } + let byte = ((self.0 & CASCADE_LEVEL_MASK) >> CASCADE_LEVEL_SHIFT) as u8; + unsafe { CascadeLevel::from_byte(byte) } } } -impl Debug for SourceOrderAndCascadeLevel { +impl Debug for ApplicableDeclarationBits { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SourceOrderAndCascadeLevel") - .field("order", &self.order()) + f.debug_struct("ApplicableDeclarationBits") + .field("source_order", &self.source_order()) + .field("shadow_cascade_order", &self.shadow_cascade_order()) .field("level", &self.level()) .finish() } @@ -79,8 +100,9 @@ pub struct ApplicableDeclarationBlock { /// The style source, either a style rule, or a property declaration block. #[ignore_malloc_size_of = "Arc"] pub source: StyleSource, - /// The source order of the block, and the cascade level it belongs to. - order_and_level: SourceOrderAndCascadeLevel, + /// The bits containing the source order, cascade level, and shadow cascade + /// order. + bits: ApplicableDeclarationBits, /// The specificity of the selector this block is represented by. pub specificity: u32, } @@ -95,38 +117,45 @@ impl ApplicableDeclarationBlock { ) -> Self { ApplicableDeclarationBlock { source: StyleSource::Declarations(declarations), - order_and_level: SourceOrderAndCascadeLevel::new(0, level), + bits: ApplicableDeclarationBits::new(0, level, 0), specificity: 0, } } /// Constructs an applicable declaration block from the given components #[inline] - pub fn new(source: StyleSource, order: u32, level: CascadeLevel, specificity: u32) -> Self { + pub fn new( + source: StyleSource, + order: u32, + level: CascadeLevel, + specificity: u32, + shadow_cascade_order: ShadowCascadeOrder, + ) -> Self { ApplicableDeclarationBlock { - source: source, - order_and_level: SourceOrderAndCascadeLevel::new(order, level), - specificity: specificity, + source, + bits: ApplicableDeclarationBits::new(order, level, shadow_cascade_order), + specificity, } } /// Returns the source order of the block. #[inline] pub fn source_order(&self) -> u32 { - self.order_and_level.order() + self.bits.source_order() } /// Returns the cascade level of the block. #[inline] pub fn level(&self) -> CascadeLevel { - self.order_and_level.level() + self.bits.level() } - /// Convenience method to consume self and return the source alongside the - /// level. + /// Convenience method to consume self and return the right thing for the + /// rule tree to iterate over. #[inline] - pub fn order_and_level(self) -> (StyleSource, CascadeLevel) { + pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) { let level = self.level(); - (self.source, level) + let cascade_order = self.bits.shadow_cascade_order(); + (self.source, level, cascade_order) } } |