mod.rs (15879B)
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 #![deny(unsafe_code)] 6 7 //! The rule tree. 8 9 use crate::applicable_declarations::{ApplicableDeclarationList, CascadePriority}; 10 use crate::properties::{LonghandIdSet, PropertyDeclarationBlock}; 11 use crate::shared_lock::{Locked, StylesheetGuards}; 12 use crate::stylesheets::layer_rule::LayerOrder; 13 use servo_arc::ArcBorrow; 14 use smallvec::SmallVec; 15 use std::io::{self, Write}; 16 17 mod core; 18 mod level; 19 mod map; 20 mod source; 21 mod unsafe_box; 22 23 pub use self::core::{RuleTree, StrongRuleNode}; 24 pub use self::level::{CascadeLevel, ShadowCascadeOrder}; 25 pub use self::source::StyleSource; 26 27 impl RuleTree { 28 fn dump<W: Write>(&self, guards: &StylesheetGuards, writer: &mut W) { 29 let _ = writeln!(writer, " + RuleTree"); 30 self.root().dump(guards, writer, 0); 31 } 32 33 /// Dump the rule tree to stdout. 34 pub fn dump_stdout(&self, guards: &StylesheetGuards) { 35 let mut stdout = io::stdout(); 36 self.dump(guards, &mut stdout); 37 } 38 39 /// Inserts the given rules, that must be in proper order by specifity, and 40 /// returns the corresponding rule node representing the last inserted one. 41 /// 42 /// !important rules are detected and inserted into the appropriate position 43 /// in the rule tree. This allows selector matching to ignore importance, 44 /// while still maintaining the appropriate cascade order in the rule tree. 45 pub fn insert_ordered_rules_with_important<'a, I>( 46 &self, 47 iter: I, 48 guards: &StylesheetGuards, 49 ) -> StrongRuleNode 50 where 51 I: Iterator<Item = (StyleSource, CascadePriority)>, 52 { 53 use self::CascadeLevel::*; 54 let mut current = self.root().clone(); 55 56 let mut found_important = false; 57 58 let mut important_author = SmallVec::<[(StyleSource, CascadePriority); 4]>::new(); 59 let mut important_user = SmallVec::<[(StyleSource, CascadePriority); 4]>::new(); 60 let mut important_ua = SmallVec::<[(StyleSource, CascadePriority); 4]>::new(); 61 let mut transition = None; 62 63 for (source, priority) in iter { 64 let level = priority.cascade_level(); 65 debug_assert!(!level.is_important(), "Important levels handled internally"); 66 67 let any_important = { 68 let pdb = source.read(level.guard(guards)); 69 pdb.any_important() 70 }; 71 72 if any_important { 73 found_important = true; 74 match level { 75 AuthorNormal { .. } => { 76 important_author.push((source.clone(), priority.important())) 77 }, 78 UANormal => important_ua.push((source.clone(), priority.important())), 79 UserNormal => important_user.push((source.clone(), priority.important())), 80 _ => {}, 81 }; 82 } 83 84 // We don't optimize out empty rules, even though we could. 85 // 86 // Inspector relies on every rule being inserted in the normal level 87 // at least once, in order to return the rules with the correct 88 // specificity order. 89 // 90 // TODO(emilio): If we want to apply these optimizations without 91 // breaking inspector's expectations, we'd need to run 92 // selector-matching again at the inspector's request. That may or 93 // may not be a better trade-off. 94 if matches!(level, Transitions) && found_important { 95 // There can be at most one transition, and it will come at 96 // the end of the iterator. Stash it and apply it after 97 // !important rules. 98 debug_assert!(transition.is_none()); 99 transition = Some(source); 100 } else { 101 current = current.ensure_child(self.root(), source, priority); 102 } 103 } 104 105 // Early-return in the common case of no !important declarations. 106 if !found_important { 107 return current; 108 } 109 110 // Insert important declarations, in order of increasing importance, 111 // followed by any transition rule. 112 // 113 // Important rules are sorted differently from unimportant ones by 114 // shadow order and cascade order. 115 if !important_author.is_empty() 116 && important_author.first().unwrap().1 != important_author.last().unwrap().1 117 { 118 // We only need to sort if the important rules come from 119 // different trees, but we need this sort to be stable. 120 // 121 // FIXME(emilio): This could maybe be smarter, probably by chunking 122 // the important rules while inserting, and iterating the outer 123 // chunks in reverse order. 124 // 125 // That is, if we have rules with levels like: -1 -1 -1 0 0 0 1 1 1, 126 // we're really only sorting the chunks, while keeping elements 127 // inside the same chunk already sorted. Seems like we could try to 128 // keep a SmallVec-of-SmallVecs with the chunks and just iterate the 129 // outer in reverse. 130 important_author.sort_by_key(|&(_, priority)| priority); 131 } 132 133 for (source, priority) in important_author.drain(..) { 134 current = current.ensure_child(self.root(), source, priority); 135 } 136 137 for (source, priority) in important_user.drain(..) { 138 current = current.ensure_child(self.root(), source, priority); 139 } 140 141 for (source, priority) in important_ua.drain(..) { 142 current = current.ensure_child(self.root(), source, priority); 143 } 144 145 if let Some(source) = transition { 146 current = current.ensure_child( 147 self.root(), 148 source, 149 CascadePriority::new(Transitions, LayerOrder::root()), 150 ); 151 } 152 153 current 154 } 155 156 /// Given a list of applicable declarations, insert the rules and return the 157 /// corresponding rule node. 158 pub fn compute_rule_node( 159 &self, 160 applicable_declarations: &mut ApplicableDeclarationList, 161 guards: &StylesheetGuards, 162 ) -> StrongRuleNode { 163 self.insert_ordered_rules_with_important( 164 applicable_declarations.drain(..).map(|d| d.for_rule_tree()), 165 guards, 166 ) 167 } 168 169 /// Insert the given rules, that must be in proper order by specifity, and 170 /// return the corresponding rule node representing the last inserted one. 171 pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode 172 where 173 I: Iterator<Item = (StyleSource, CascadePriority)>, 174 { 175 self.insert_ordered_rules_from(self.root().clone(), iter) 176 } 177 178 fn insert_ordered_rules_from<'a, I>(&self, from: StrongRuleNode, iter: I) -> StrongRuleNode 179 where 180 I: Iterator<Item = (StyleSource, CascadePriority)>, 181 { 182 let mut current = from; 183 for (source, priority) in iter { 184 current = current.ensure_child(self.root(), source, priority); 185 } 186 current 187 } 188 189 /// Replaces a rule in a given level (if present) for another rule. 190 /// 191 /// Returns the resulting node that represents the new path, or None if 192 /// the old path is still valid. 193 pub fn update_rule_at_level( 194 &self, 195 level: CascadeLevel, 196 layer_order: LayerOrder, 197 pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>, 198 path: &StrongRuleNode, 199 guards: &StylesheetGuards, 200 important_rules_changed: &mut bool, 201 ) -> Option<StrongRuleNode> { 202 // TODO(emilio): Being smarter with lifetimes we could avoid a bit of 203 // the refcount churn. 204 let mut current = path.clone(); 205 *important_rules_changed = false; 206 207 // First walk up until the first less-or-equally specific rule. 208 let mut children = SmallVec::<[_; 10]>::new(); 209 while current.cascade_priority().cascade_level() > level { 210 children.push(( 211 current.style_source().unwrap().clone(), 212 current.cascade_priority(), 213 )); 214 current = current.parent().unwrap().clone(); 215 } 216 217 let cascade_priority = CascadePriority::new(level, layer_order); 218 219 // Then remove the one at the level we want to replace, if any. 220 // 221 // NOTE: Here we assume that only one rule can be at the level + priority we're replacing, 222 // which holds because we only use this for HTML style attribute, animations and transition 223 // rules. 224 // 225 // This is certainly true for HTML style attribute rules, animations, transitions, and 226 // SMIL. 227 if current.cascade_priority() == cascade_priority { 228 *important_rules_changed |= level.is_important(); 229 230 let current_decls = current.style_source().unwrap().get(); 231 232 // If the only rule at the level we're replacing is exactly the 233 // same as `pdb`, we're done, and `path` is still valid. 234 if let Some(ref pdb) = pdb { 235 // If the only rule at the level we're replacing is exactly the 236 // same as `pdb`, we're done, and `path` is still valid. 237 // 238 // TODO(emilio): Another potential optimization is the one where 239 // we can just replace the rule at that level for `pdb`, and 240 // then we don't need to re-create the children, and `path` is 241 // also equally valid. This is less likely, and would require an 242 // in-place mutation of the source, which is, at best, fiddly, 243 // so let's skip it for now. 244 let is_here_already = ArcBorrow::ptr_eq(pdb, ¤t_decls.borrow_arc()); 245 if is_here_already { 246 debug!("Picking the fast path in rule replacement"); 247 return None; 248 } 249 } 250 251 current = current.parent().unwrap().clone(); 252 } 253 254 // Insert the rule if it's relevant at this level in the cascade. 255 // 256 // These optimizations are likely to be important, because the levels where replacements 257 // apply (style and animations) tend to trigger pretty bad styling cases already. 258 if let Some(pdb) = pdb { 259 if level.is_important() { 260 if pdb.read_with(level.guard(guards)).any_important() { 261 current = current.ensure_child( 262 self.root(), 263 StyleSource::from_declarations(pdb.clone_arc()), 264 cascade_priority, 265 ); 266 *important_rules_changed = true; 267 } 268 } else { 269 if pdb.read_with(level.guard(guards)).any_normal() { 270 current = current.ensure_child( 271 self.root(), 272 StyleSource::from_declarations(pdb.clone_arc()), 273 cascade_priority, 274 ); 275 } 276 } 277 } 278 279 // Now the rule is in the relevant place, push the children as 280 // necessary. 281 let rule = self.insert_ordered_rules_from(current, children.drain(..).rev()); 282 Some(rule) 283 } 284 285 /// Returns new rule nodes without Transitions level rule. 286 pub fn remove_transition_rule_if_applicable(&self, path: &StrongRuleNode) -> StrongRuleNode { 287 // Return a clone if there is no transition level. 288 if path.cascade_level() != CascadeLevel::Transitions { 289 return path.clone(); 290 } 291 292 path.parent().unwrap().clone() 293 } 294 295 /// Returns new rule node without rules from declarative animations. 296 pub fn remove_animation_rules(&self, path: &StrongRuleNode) -> StrongRuleNode { 297 // Return a clone if there are no animation rules. 298 if !path.has_animation_or_transition_rules() { 299 return path.clone(); 300 } 301 302 let iter = path 303 .self_and_ancestors() 304 .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride); 305 let mut last = path; 306 let mut children = SmallVec::<[_; 10]>::new(); 307 for node in iter { 308 if !node.cascade_level().is_animation() { 309 children.push(( 310 node.style_source().unwrap().clone(), 311 node.cascade_priority(), 312 )); 313 } 314 last = node; 315 } 316 317 let rule = self 318 .insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain(..).rev()); 319 rule 320 } 321 } 322 323 impl StrongRuleNode { 324 /// Get an iterator for this rule node and its ancestors. 325 pub fn self_and_ancestors(&self) -> SelfAndAncestors<'_> { 326 SelfAndAncestors { 327 current: Some(self), 328 } 329 } 330 331 /// Returns true if there is either animation or transition level rule. 332 pub fn has_animation_or_transition_rules(&self) -> bool { 333 self.self_and_ancestors() 334 .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride) 335 .any(|node| node.cascade_level().is_animation()) 336 } 337 338 /// Get a set of properties whose CascadeLevel are higher than Animations 339 /// but not equal to Transitions. 340 /// 341 /// If there are any custom properties, we set the boolean value of the 342 /// returned tuple to true. 343 pub fn get_properties_overriding_animations( 344 &self, 345 guards: &StylesheetGuards, 346 ) -> (LonghandIdSet, bool) { 347 use crate::properties::PropertyDeclarationId; 348 349 // We want to iterate over cascade levels that override the animations 350 // level, i.e. !important levels and the transitions level. 351 // 352 // However, we actually want to skip the transitions level because 353 // although it is higher in the cascade than animations, when both 354 // transitions and animations are present for a given element and 355 // property, transitions are suppressed so that they don't actually 356 // override animations. 357 let iter = self 358 .self_and_ancestors() 359 .skip_while(|node| node.cascade_level() == CascadeLevel::Transitions) 360 .take_while(|node| node.cascade_level() > CascadeLevel::Animations); 361 let mut result = (LonghandIdSet::new(), false); 362 for node in iter { 363 let style = node.style_source().unwrap(); 364 for (decl, important) in style 365 .read(node.cascade_level().guard(guards)) 366 .declaration_importance_iter() 367 { 368 // Although we are only iterating over cascade levels that 369 // override animations, in a given property declaration block we 370 // can have a mixture of !important and non-!important 371 // declarations but only the !important declarations actually 372 // override animations. 373 if important.important() { 374 match decl.id() { 375 PropertyDeclarationId::Longhand(id) => result.0.insert(id), 376 PropertyDeclarationId::Custom(_) => result.1 = true, 377 } 378 } 379 } 380 } 381 result 382 } 383 } 384 385 /// An iterator over a rule node and its ancestors. 386 #[derive(Clone)] 387 pub struct SelfAndAncestors<'a> { 388 current: Option<&'a StrongRuleNode>, 389 } 390 391 impl<'a> Iterator for SelfAndAncestors<'a> { 392 type Item = &'a StrongRuleNode; 393 394 fn next(&mut self) -> Option<Self::Item> { 395 self.current.map(|node| { 396 self.current = node.parent(); 397 node 398 }) 399 } 400 }