summaryrefslogtreecommitdiffstats
path: root/servo/components/style/applicable_declarations.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/applicable_declarations.rs')
-rw-r--r--servo/components/style/applicable_declarations.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/servo/components/style/applicable_declarations.rs b/servo/components/style/applicable_declarations.rs
new file mode 100644
index 0000000000..6353fb4c5e
--- /dev/null
+++ b/servo/components/style/applicable_declarations.rs
@@ -0,0 +1,120 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! Applicable declarations management.
+
+use crate::properties::PropertyDeclarationBlock;
+use crate::rule_tree::{CascadeLevel, StyleSource};
+use crate::shared_lock::Locked;
+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.
+pub type 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.
+///
+/// [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_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
+const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
+
+/// We pack the cascade level in a single byte, see CascadeLevel::to_byte_lossy
+/// for the different trade-offs there.
+const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS;
+
+/// 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, Debug, Eq, MallocSizeOf, PartialEq)]
+struct ApplicableDeclarationBits(u32);
+
+impl ApplicableDeclarationBits {
+ fn new(source_order: u32, cascade_level: CascadeLevel) -> Self {
+ Self(
+ (source_order & SOURCE_ORDER_MASK) |
+ ((cascade_level.to_byte_lossy() as u32) << CASCADE_LEVEL_SHIFT),
+ )
+ }
+
+ fn source_order(&self) -> u32 {
+ self.0 & SOURCE_ORDER_MASK
+ }
+
+ fn level(&self) -> CascadeLevel {
+ CascadeLevel::from_byte((self.0 >> CASCADE_LEVEL_SHIFT) as u8)
+ }
+}
+
+/// 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)]
+pub struct ApplicableDeclarationBlock {
+ /// The style source, either a style rule, or a property declaration block.
+ #[ignore_malloc_size_of = "Arc"]
+ pub source: StyleSource,
+ /// 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,
+}
+
+impl ApplicableDeclarationBlock {
+ /// Constructs an applicable declaration block from a given property
+ /// declaration block and importance.
+ #[inline]
+ pub fn from_declarations(
+ declarations: Arc<Locked<PropertyDeclarationBlock>>,
+ level: CascadeLevel,
+ ) -> Self {
+ ApplicableDeclarationBlock {
+ source: StyleSource::from_declarations(declarations),
+ bits: ApplicableDeclarationBits::new(0, level),
+ specificity: 0,
+ }
+ }
+
+ /// Constructs an applicable declaration block from the given components
+ #[inline]
+ pub fn new(source: StyleSource, order: u32, level: CascadeLevel, specificity: u32) -> Self {
+ ApplicableDeclarationBlock {
+ source,
+ bits: ApplicableDeclarationBits::new(order, level),
+ specificity,
+ }
+ }
+
+ /// Returns the source order of the block.
+ #[inline]
+ pub fn source_order(&self) -> u32 {
+ self.bits.source_order()
+ }
+
+ /// Returns the cascade level of the block.
+ #[inline]
+ pub fn level(&self) -> CascadeLevel {
+ self.bits.level()
+ }
+
+ /// Convenience method to consume self and return the right thing for the
+ /// rule tree to iterate over.
+ #[inline]
+ pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel) {
+ let level = self.level();
+ (self.source, level)
+ }
+}