applicable_declarations.rs (9817B)
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::derives::*; 8 use crate::properties::PropertyDeclarationBlock; 9 use crate::rule_tree::{CascadeLevel, StyleSource}; 10 use crate::shared_lock::Locked; 11 use crate::stylesheets::layer_rule::LayerOrder; 12 use servo_arc::Arc; 13 use smallvec::SmallVec; 14 15 /// List of applicable declarations. This is a transient structure that shuttles 16 /// declarations between selector matching and inserting into the rule tree, and 17 /// therefore we want to avoid heap-allocation where possible. 18 /// 19 /// In measurements on wikipedia, we pretty much never have more than 8 applicable 20 /// declarations, so we could consider making this 8 entries instead of 16. 21 /// However, it may depend a lot on workload, and stack space is cheap. 22 pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>; 23 24 /// Blink uses 18 bits to store source order, and does not check overflow [1]. 25 /// That's a limit that could be reached in realistic webpages, so we use 26 /// 24 bits and enforce defined behavior in the overflow case. 27 /// 28 /// Note that right now this restriction could be lifted if wanted (because we 29 /// no longer stash the cascade level in the remaining bits), but we keep it in 30 /// place in case we come up with a use-case for them, lacking reports of the 31 /// current limit being too small. 32 /// 33 /// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/ 34 /// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3 35 const SOURCE_ORDER_BITS: usize = 24; 36 const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1; 37 const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX; 38 39 /// The cascade-level+layer order of this declaration. 40 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] 41 pub struct CascadePriority { 42 cascade_level: CascadeLevel, 43 layer_order: LayerOrder, 44 } 45 46 const_assert_eq!( 47 std::mem::size_of::<CascadePriority>(), 48 std::mem::size_of::<u32>() 49 ); 50 51 impl PartialOrd for CascadePriority { 52 #[inline] 53 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { 54 Some(self.cmp(other)) 55 } 56 } 57 58 impl Ord for CascadePriority { 59 fn cmp(&self, other: &Self) -> std::cmp::Ordering { 60 self.cascade_level.cmp(&other.cascade_level).then_with(|| { 61 let ordering = self.layer_order.cmp(&other.layer_order); 62 if ordering == std::cmp::Ordering::Equal { 63 return ordering; 64 } 65 // https://drafts.csswg.org/css-cascade-5/#cascade-layering 66 // 67 // Cascade layers (like declarations) are ordered by order 68 // of appearance. When comparing declarations that belong to 69 // different layers, then for normal rules the declaration 70 // whose cascade layer is last wins, and for important rules 71 // the declaration whose cascade layer is first wins. 72 // 73 // But the style attribute layer for some reason is special. 74 if self.cascade_level.is_important() 75 && !self.layer_order.is_style_attribute_layer() 76 && !other.layer_order.is_style_attribute_layer() 77 { 78 ordering.reverse() 79 } else { 80 ordering 81 } 82 }) 83 } 84 } 85 86 impl CascadePriority { 87 /// Construct a new CascadePriority for a given (level, order) pair. 88 pub fn new(cascade_level: CascadeLevel, layer_order: LayerOrder) -> Self { 89 Self { 90 cascade_level, 91 layer_order, 92 } 93 } 94 95 /// Returns the layer order. 96 #[inline] 97 pub fn layer_order(&self) -> LayerOrder { 98 self.layer_order 99 } 100 101 /// Returns the cascade level. 102 #[inline] 103 pub fn cascade_level(&self) -> CascadeLevel { 104 self.cascade_level 105 } 106 107 /// Whether this declaration should be allowed if `revert` or `revert-layer` 108 /// have been specified on a given origin. 109 /// 110 /// `self` is the priority at which the `revert` or `revert-layer` keyword 111 /// have been specified. 112 pub fn allows_when_reverted(&self, other: &Self, origin_revert: bool) -> bool { 113 if origin_revert { 114 other.cascade_level.origin() < self.cascade_level.origin() 115 } else { 116 other.unimportant() < self.unimportant() 117 } 118 } 119 120 /// Convert this priority from "important" to "non-important", if needed. 121 pub fn unimportant(&self) -> Self { 122 Self::new(self.cascade_level().unimportant(), self.layer_order()) 123 } 124 125 /// Convert this priority from "non-important" to "important", if needed. 126 pub fn important(&self) -> Self { 127 Self::new(self.cascade_level().important(), self.layer_order()) 128 } 129 130 /// The same tree, in author origin, at the root layer. 131 pub fn same_tree_author_normal_at_root_layer() -> Self { 132 Self::new(CascadeLevel::same_tree_author_normal(), LayerOrder::root()) 133 } 134 } 135 136 /// Proximity to the scope root. 137 /// 138 /// https://drafts.csswg.org/css-cascade-6/#cascade-proximity 139 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] 140 pub struct ScopeProximity(u16); 141 142 impl PartialOrd for ScopeProximity { 143 #[inline] 144 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { 145 Some(self.cmp(other)) 146 } 147 } 148 149 impl Ord for ScopeProximity { 150 fn cmp(&self, other: &Self) -> std::cmp::Ordering { 151 // Lower proximity to scope root wins 152 other.0.cmp(&self.0) 153 } 154 } 155 156 /// Sacrifice the largest possible value for infinity. This makes the comparison 157 /// trivial. 158 const PROXIMITY_INFINITY: u16 = u16::MAX; 159 160 impl ScopeProximity { 161 /// Construct a new scope proximity. 162 pub fn new(proximity: usize) -> Self { 163 if cfg!(debug_assertions) && proximity >= PROXIMITY_INFINITY as usize { 164 warn!("Proximity out of bounds"); 165 } 166 Self(proximity.clamp(0, (PROXIMITY_INFINITY - 1) as usize) as u16) 167 } 168 169 /// Create a scope proximity for delcarations outside of any scope root. 170 pub fn infinity() -> Self { 171 Self(PROXIMITY_INFINITY) 172 } 173 174 /// If the proximity is finite, get the value. 175 pub fn get(&self) -> Option<u16> { 176 (self.0 != PROXIMITY_INFINITY).then(|| self.0) 177 } 178 } 179 180 /// A property declaration together with its precedence among rules of equal 181 /// specificity so that we can sort them. 182 /// 183 /// This represents the declarations in a given declaration block for a given 184 /// importance. 185 #[derive(Clone, Debug, MallocSizeOf, PartialEq)] 186 pub struct ApplicableDeclarationBlock { 187 /// The style source, either a style rule, or a property declaration block. 188 #[ignore_malloc_size_of = "Arc"] 189 pub source: StyleSource, 190 /// Order of appearance in which this rule appears - Set to 0 if not relevant 191 /// (e.g. Declaration from `style="/*...*/"`, presentation hints, animations 192 /// - See `CascadePriority` instead). 193 source_order: u32, 194 /// The specificity of the selector. 195 pub specificity: u32, 196 /// The proximity to the scope root. 197 pub scope_proximity: ScopeProximity, 198 /// The cascade priority of the rule. 199 pub cascade_priority: CascadePriority, 200 } 201 202 impl ApplicableDeclarationBlock { 203 /// Constructs an applicable declaration block from a given property 204 /// declaration block and importance. 205 #[inline] 206 pub fn from_declarations( 207 declarations: Arc<Locked<PropertyDeclarationBlock>>, 208 level: CascadeLevel, 209 layer_order: LayerOrder, 210 ) -> Self { 211 ApplicableDeclarationBlock { 212 source: StyleSource::from_declarations(declarations), 213 source_order: 0, 214 specificity: 0, 215 scope_proximity: ScopeProximity::infinity(), 216 cascade_priority: CascadePriority::new(level, layer_order), 217 } 218 } 219 220 /// Constructs an applicable declaration block from the given components. 221 #[inline] 222 pub fn new( 223 source: StyleSource, 224 source_order: u32, 225 level: CascadeLevel, 226 specificity: u32, 227 layer_order: LayerOrder, 228 scope_proximity: ScopeProximity, 229 ) -> Self { 230 ApplicableDeclarationBlock { 231 source, 232 source_order: source_order & SOURCE_ORDER_MASK, 233 specificity, 234 scope_proximity, 235 cascade_priority: CascadePriority::new(level, layer_order), 236 } 237 } 238 239 /// Returns the source order of the block. 240 #[inline] 241 pub fn source_order(&self) -> u32 { 242 self.source_order 243 } 244 245 /// Returns the cascade level of the block. 246 #[inline] 247 pub fn level(&self) -> CascadeLevel { 248 self.cascade_priority.cascade_level() 249 } 250 251 /// Returns the cascade level of the block. 252 #[inline] 253 pub fn layer_order(&self) -> LayerOrder { 254 self.cascade_priority.layer_order() 255 } 256 257 /// Returns the scope proximity of the block. 258 #[inline] 259 pub fn scope_proximity(&self) -> ScopeProximity { 260 self.scope_proximity 261 } 262 263 /// Convenience method to consume self and return the right thing for the 264 /// rule tree to iterate over. 265 #[inline] 266 pub fn for_rule_tree(self) -> (StyleSource, CascadePriority) { 267 (self.source, self.cascade_priority) 268 } 269 270 /// Return the key used to sort applicable declarations. 271 #[inline] 272 pub fn sort_key(&self) -> (LayerOrder, u32, ScopeProximity, u32) { 273 ( 274 self.layer_order(), 275 self.specificity, 276 self.scope_proximity(), 277 self.source_order(), 278 ) 279 } 280 } 281 282 // Size of this struct determines sorting and selector-matching performance. 283 size_of_test!(ApplicableDeclarationBlock, 24);