mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Hoist ApplicableDeclaration{Block,List} into a separate file.
MozReview-Commit-ID: EXnAzfyoZ1e
This commit is contained in:
parent
0caad2ffdc
commit
a98fff1af8
12 changed files with 161 additions and 130 deletions
137
components/style/applicable_declarations.rs
Normal file
137
components/style/applicable_declarations.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Applicable declarations management.
|
||||
|
||||
use properties::PropertyDeclarationBlock;
|
||||
use rule_tree::{CascadeLevel, StyleSource};
|
||||
use shared_lock::Locked;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::{Debug, self};
|
||||
use std::mem;
|
||||
use stylearc::Arc;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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_BITS: usize = 24;
|
||||
const SOURCE_ORDER_MASK: u32 = (1 << SOURCE_ORDER_BITS) - 1;
|
||||
const SOURCE_ORDER_MAX: u32 = SOURCE_ORDER_MASK;
|
||||
|
||||
/// Stores the source order of a block and the cascade level it belongs to.
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
struct SourceOrderAndCascadeLevel(u32);
|
||||
|
||||
impl SourceOrderAndCascadeLevel {
|
||||
fn new(source_order: u32, cascade_level: CascadeLevel) -> SourceOrderAndCascadeLevel {
|
||||
let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX);
|
||||
bits |= (cascade_level as u8 as u32) << SOURCE_ORDER_BITS;
|
||||
SourceOrderAndCascadeLevel(bits)
|
||||
}
|
||||
|
||||
fn order(&self) -> u32 {
|
||||
self.0 & SOURCE_ORDER_MASK
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for SourceOrderAndCascadeLevel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("SourceOrderAndCascadeLevel")
|
||||
.field("order", &self.order())
|
||||
.field("level", &self.level())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ApplicableDeclarationBlock {
|
||||
/// The style source, either a style rule, or a property declaration block.
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
pub source: StyleSource,
|
||||
/// The source order of the block, and the cascade level it belongs to.
|
||||
order_and_level: SourceOrderAndCascadeLevel,
|
||||
/// 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::Declarations(declarations),
|
||||
order_and_level: SourceOrderAndCascadeLevel::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: source,
|
||||
order_and_level: SourceOrderAndCascadeLevel::new(order, level),
|
||||
specificity: specificity,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Returns the source order of the block.
|
||||
#[inline]
|
||||
pub fn source_order(&self) -> u32 {
|
||||
self.order_and_level.order()
|
||||
}
|
||||
|
||||
/// Returns the cascade level of the block.
|
||||
#[inline]
|
||||
pub fn level(&self) -> CascadeLevel {
|
||||
self.order_and_level.level()
|
||||
}
|
||||
|
||||
/// Convenience method to consume self and return the source alongside the
|
||||
/// level.
|
||||
#[inline]
|
||||
pub fn order_and_level(self) -> (StyleSource, CascadeLevel) {
|
||||
let level = self.level();
|
||||
(self.source, level)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue