/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Applicable declarations management.
usecrate::properties::PropertyDeclarationBlock; usecrate::rule_tree::{CascadeLevel, StyleSource}; usecrate::shared_lock::Locked; usecrate::stylesheets::layer_rule::LayerOrder; use servo_arc::Arc; use smallvec::SmallVec;
/// List of applicable declarations. This is a transient structure that shuttles /// declarations between selector matching and inserting into the rule tree, and /// therefore we want to avoid heap-allocation where possible. /// /// In measurements on wikipedia, we pretty much never have more than 8 applicable /// declarations, so we could consider making this 8 entries instead of 16. /// However, it may depend a lot on workload, and stack space is cheap. pubtype ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
/// Blink uses 18 bits to store source order, and does not check overflow [1]. /// 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 right now this restriction could be lifted if wanted (because we /// no longer stash the cascade level in the remaining bits), but we keep it in /// place in case we come up with a use-case for them, lacking reports of the /// current limit being too small. /// /// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/ /// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3 const SOURCE_ORDER_BITS: usize = 24; const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1; const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX;
/// The cascade-level+layer order of this declaration. #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] pubstruct CascadePriority {
cascade_level: CascadeLevel,
layer_order: LayerOrder,
}
impl Ord for CascadePriority { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.cascade_level.cmp(&other.cascade_level).then_with(|| { let ordering = self.layer_order.cmp(&other.layer_order); if ordering == std::cmp::Ordering::Equal { return ordering;
} // https://drafts.csswg.org/css-cascade-5/#cascade-layering // // Cascade layers (like declarations) are ordered by order // of appearance. When comparing declarations that belong to // different layers, then for normal rules the declaration // whose cascade layer is last wins, and for important rules // the declaration whose cascade layer is first wins. // // But the style attribute layer for some reason is special. ifself.cascade_level.is_important() &&
!self.layer_order.is_style_attribute_layer() &&
!other.layer_order.is_style_attribute_layer()
{
ordering.reverse()
} else {
ordering
}
})
}
}
impl CascadePriority { /// Construct a new CascadePriority for a given (level, order) pair. pubfn new(cascade_level: CascadeLevel, layer_order: LayerOrder) -> Self { Self {
cascade_level,
layer_order,
}
}
/// Whether this declaration should be allowed if `revert` or `revert-layer` /// have been specified on a given origin. /// /// `self` is the priority at which the `revert` or `revert-layer` keyword /// have been specified. pubfn allows_when_reverted(&self, other: &Self, origin_revert: bool) -> bool { if origin_revert {
other.cascade_level.origin() < self.cascade_level.origin()
} else {
other.unimportant() < self.unimportant()
}
}
/// Convert this priority from "important" to "non-important", if needed. pubfn unimportant(&self) -> Self { Self::new(self.cascade_level().unimportant(), self.layer_order())
}
/// Convert this priority from "non-important" to "important", if needed. pubfn important(&self) -> Self { Self::new(self.cascade_level().important(), self.layer_order())
}
/// The same tree, in author origin, at the root layer. pubfn same_tree_author_normal_at_root_layer() -> Self { Self::new(CascadeLevel::same_tree_author_normal(), LayerOrder::root())
}
}
impl Ord for ScopeProximity { fn cmp(&self, other: &Self) -> std::cmp::Ordering { // Lower proximity to scope root wins
other.0.cmp(&self.0)
}
}
/// Sacrifice the largest possible value for infinity. This makes the comparison /// trivial. const PROXIMITY_INFINITY: u16 = u16::MAX;
impl ScopeProximity { /// Construct a new scope proximity. pubfn new(proximity: usize) -> Self { if cfg!(debug_assertions) && proximity >= PROXIMITY_INFINITY as usize {
warn!("Proximity out of bounds");
} Self(proximity.clamp(0, (PROXIMITY_INFINITY - 1) as usize) as u16)
}
/// Create a scope proximity for delcarations outside of any scope root. pubfn infinity() -> Self { Self(PROXIMITY_INFINITY)
}
}
/// A property declaration together with its precedence among rules of equal /// specificity so that we can sort them. /// /// This represents the declarations in a given declaration block for a given /// importance. #[derive(Clone, Debug, MallocSizeOf, PartialEq)] pubstruct ApplicableDeclarationBlock { /// The style source, either a style rule, or a property declaration block. #[ignore_malloc_size_of = "Arc"] pub source: StyleSource, /// Order of appearance in which this rule appears - Set to 0 if not relevant /// (e.g. Declaration from `style="/*...*/"`, presentation hints, animations /// - See `CascadePriority` instead).
source_order: u32, /// The specificity of the selector. pub specificity: u32, /// The proximity to the scope root. pub scope_proximity: ScopeProximity, /// The cascade priority of the rule. pub cascade_priority: CascadePriority,
}
impl ApplicableDeclarationBlock { /// Constructs an applicable declaration block from a given property /// declaration block and importance. #[inline] pubfn from_declarations(
declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel,
layer_order: LayerOrder,
) -> Self {
ApplicableDeclarationBlock {
source: StyleSource::from_declarations(declarations),
source_order: 0,
specificity: 0,
scope_proximity: ScopeProximity::infinity(),
cascade_priority: CascadePriority::new(level, layer_order),
}
}
/// Returns the source order of the block. #[inline] pubfn source_order(&self) -> u32 { self.source_order
}
/// Returns the cascade level of the block. #[inline] pubfn level(&self) -> CascadeLevel { self.cascade_priority.cascade_level()
}
/// Returns the cascade level of the block. #[inline] pubfn layer_order(&self) -> LayerOrder { self.cascade_priority.layer_order()
}
/// Returns the scope proximity of the block. #[inline] pubfn scope_proximity(&self) -> ScopeProximity { self.scope_proximity
}
/// Convenience method to consume self and return the right thing for the /// rule tree to iterate over. #[inline] pubfn for_rule_tree(self) -> (StyleSource, CascadePriority) {
(self.source, self.cascade_priority)
}
/// Return the key used to sort applicable declarations. #[inline] pubfn sort_key(&self) -> (LayerOrder, u32, ScopeProximity, u32) {
( self.layer_order(), self.specificity, self.scope_proximity(), self.source_order(),
)
}
}
// Size of this struct determines sorting and selector-matching performance.
size_of_test!(ApplicableDeclarationBlock, 24);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.