Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5
//! Applicable declarations management.
6
7
use crate::properties::PropertyDeclarationBlock;
8
use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder, StyleSource};
9
use crate::shared_lock::Locked;
10
use servo_arc::Arc;
11
use smallvec::SmallVec;
12
use std::fmt::{self, Debug};
13
14
/// List of applicable declarations. This is a transient structure that shuttles
15
/// declarations between selector matching and inserting into the rule tree, and
16
/// therefore we want to avoid heap-allocation where possible.
17
///
18
/// In measurements on wikipedia, we pretty much never have more than 8 applicable
19
/// declarations, so we could consider making this 8 entries instead of 16.
20
/// However, it may depend a lot on workload, and stack space is cheap.
21
pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
22
23
/// Blink uses 18 bits to store source order, and does not check overflow [1].
24
/// That's a limit that could be reached in realistic webpages, so we use
25
/// 24 bits and enforce defined behavior in the overflow case.
26
///
28
/// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
29
const SOURCE_ORDER_SHIFT: usize = 0;
30
const SOURCE_ORDER_BITS: usize = 24;
31
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
32
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
33
34
/// We store up-to-15 shadow order levels.
35
///
36
/// You'd need an element slotted across 16 components with ::slotted rules to
37
/// trigger this as of this writing, which looks... Unlikely.
38
const SHADOW_CASCADE_ORDER_SHIFT: usize = SOURCE_ORDER_BITS;
39
const SHADOW_CASCADE_ORDER_BITS: usize = 4;
40
const SHADOW_CASCADE_ORDER_MAX: u8 = (1 << SHADOW_CASCADE_ORDER_BITS) - 1;
41
const SHADOW_CASCADE_ORDER_MASK: u32 =
42
(SHADOW_CASCADE_ORDER_MAX as u32) << SHADOW_CASCADE_ORDER_SHIFT;
43
44
const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS + SHADOW_CASCADE_ORDER_BITS;
45
const CASCADE_LEVEL_BITS: usize = 4;
46
const CASCADE_LEVEL_MAX: u8 = (1 << CASCADE_LEVEL_BITS) - 1;
47
const CASCADE_LEVEL_MASK: u32 = (CASCADE_LEVEL_MAX as u32) << CASCADE_LEVEL_SHIFT;
48
49
/// Stores the source order of a block, the cascade level it belongs to, and the
50
/// counter needed to handle Shadow DOM cascade order properly.
51
#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)]
52
struct ApplicableDeclarationBits(u32);
53
54
impl ApplicableDeclarationBits {
55
fn new(
56
source_order: u32,
57
cascade_level: CascadeLevel,
58
shadow_cascade_order: ShadowCascadeOrder,
59
) -> Self {
60
debug_assert!(
61
cascade_level as u8 <= CASCADE_LEVEL_MAX,
62
"Gotta find more bits!"
63
);
64
let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX);
65
bits |= ((shadow_cascade_order & SHADOW_CASCADE_ORDER_MAX) as u32) <<
66
SHADOW_CASCADE_ORDER_SHIFT;
67
bits |= (cascade_level as u8 as u32) << CASCADE_LEVEL_SHIFT;
68
ApplicableDeclarationBits(bits)
69
}
70
71
fn source_order(&self) -> u32 {
72
(self.0 & SOURCE_ORDER_MASK) >> SOURCE_ORDER_SHIFT
73
}
74
75
fn shadow_cascade_order(&self) -> ShadowCascadeOrder {
76
((self.0 & SHADOW_CASCADE_ORDER_MASK) >> SHADOW_CASCADE_ORDER_SHIFT) as ShadowCascadeOrder
77
}
78
79
fn level(&self) -> CascadeLevel {
80
let byte = ((self.0 & CASCADE_LEVEL_MASK) >> CASCADE_LEVEL_SHIFT) as u8;
81
unsafe { CascadeLevel::from_byte(byte) }
82
}
83
}
84
85
impl Debug for ApplicableDeclarationBits {
86
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87
f.debug_struct("ApplicableDeclarationBits")
88
.field("source_order", &self.source_order())
89
.field("shadow_cascade_order", &self.shadow_cascade_order())
90
.field("level", &self.level())
91
.finish()
92
}
93
}
94
95
/// A property declaration together with its precedence among rules of equal
96
/// specificity so that we can sort them.
97
///
98
/// This represents the declarations in a given declaration block for a given
99
/// importance.
100
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
101
pub struct ApplicableDeclarationBlock {
102
/// The style source, either a style rule, or a property declaration block.
103
#[ignore_malloc_size_of = "Arc"]
104
pub source: StyleSource,
105
/// The bits containing the source order, cascade level, and shadow cascade
106
/// order.
107
bits: ApplicableDeclarationBits,
108
/// The specificity of the selector this block is represented by.
109
pub specificity: u32,
110
}
111
112
impl ApplicableDeclarationBlock {
113
/// Constructs an applicable declaration block from a given property
114
/// declaration block and importance.
115
#[inline]
116
pub fn from_declarations(
117
declarations: Arc<Locked<PropertyDeclarationBlock>>,
118
level: CascadeLevel,
119
) -> Self {
120
ApplicableDeclarationBlock {
121
source: StyleSource::from_declarations(declarations),
122
bits: ApplicableDeclarationBits::new(0, level, 0),
123
specificity: 0,
124
}
125
}
126
127
/// Constructs an applicable declaration block from the given components
128
#[inline]
129
pub fn new(
130
source: StyleSource,
131
order: u32,
132
level: CascadeLevel,
133
specificity: u32,
134
shadow_cascade_order: ShadowCascadeOrder,
135
) -> Self {
136
ApplicableDeclarationBlock {
137
source,
138
bits: ApplicableDeclarationBits::new(order, level, shadow_cascade_order),
139
specificity,
140
}
141
}
142
143
/// Returns the source order of the block.
144
#[inline]
145
pub fn source_order(&self) -> u32 {
146
self.bits.source_order()
147
}
148
149
/// Returns the cascade level of the block.
150
#[inline]
151
pub fn level(&self) -> CascadeLevel {
152
self.bits.level()
153
}
154
155
/// Convenience method to consume self and return the right thing for the
156
/// rule tree to iterate over.
157
#[inline]
158
pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) {
159
let level = self.level();
160
let cascade_order = self.bits.shadow_cascade_order();
161
(self.source, level, cascade_order)
162
}
163
}