stylist.rs (180025B)
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 //! Selector matching. 6 7 use crate::applicable_declarations::{ 8 ApplicableDeclarationBlock, ApplicableDeclarationList, CascadePriority, ScopeProximity, 9 }; 10 use crate::computed_value_flags::ComputedValueFlags; 11 use crate::context::{CascadeInputs, QuirksMode}; 12 use crate::custom_properties::ComputedCustomProperties; 13 use crate::derives::*; 14 use crate::dom::TElement; 15 #[cfg(feature = "gecko")] 16 use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion}; 17 use crate::invalidation::element::invalidation_map::{ 18 note_selector_for_invalidation, AdditionalRelativeSelectorInvalidationMap, Dependency, 19 DependencyInvalidationKind, InvalidationMap, ScopeDependencyInvalidationKind, 20 }; 21 use crate::invalidation::media_queries::{ 22 EffectiveMediaQueryResults, MediaListKey, ToMediaListKey, 23 }; 24 use crate::invalidation::stylesheets::{RuleChangeKind, StylesheetInvalidationSet}; 25 use crate::media_queries::Device; 26 use crate::properties::{ 27 self, AnimationDeclarations, CascadeMode, ComputedValues, FirstLineReparenting, 28 PropertyDeclarationBlock, StyleBuilder, 29 }; 30 use crate::properties_and_values::registry::{ 31 PropertyRegistration, PropertyRegistrationData, ScriptRegistry as CustomPropertyScriptRegistry, 32 }; 33 use crate::rule_cache::{RuleCache, RuleCacheConditions}; 34 use crate::rule_collector::RuleCollector; 35 use crate::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; 36 use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry}; 37 use crate::selector_parser::{NonTSPseudoClass, PerPseudoElementMap, PseudoElement, SelectorImpl}; 38 use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; 39 use crate::sharing::{RevalidationResult, ScopeRevalidationResult}; 40 use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind}; 41 use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher}; 42 use crate::stylesheets::container_rule::ContainerCondition; 43 use crate::stylesheets::import_rule::ImportLayer; 44 use crate::stylesheets::keyframes_rule::KeyframesAnimation; 45 use crate::stylesheets::layer_rule::{LayerName, LayerOrder}; 46 use crate::stylesheets::scope_rule::{ 47 collect_scope_roots, element_is_outside_of_scope, scope_selector_list_is_trivial, 48 ImplicitScopeRoot, ScopeRootCandidate, ScopeSubjectMap, ScopeTarget, 49 }; 50 use crate::stylesheets::{ 51 CounterStyleRule, CssRule, CssRuleRef, EffectiveRulesIterator, FontFaceRule, 52 FontFeatureValuesRule, FontPaletteValuesRule, Origin, OriginSet, PagePseudoClassFlags, 53 PageRule, PerOrigin, PerOriginIter, PositionTryRule, StylesheetContents, StylesheetInDocument, 54 }; 55 use crate::stylesheets::{CustomMediaEvaluator, CustomMediaMap}; 56 use crate::values::specified::position::PositionTryFallbacksItem; 57 use crate::values::specified::position::PositionTryFallbacksTryTactic; 58 use crate::values::{computed, AtomIdent}; 59 use crate::AllocErr; 60 use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded, WeakAtom}; 61 use dom::{DocumentState, ElementState}; 62 #[cfg(feature = "gecko")] 63 use malloc_size_of::MallocUnconditionalShallowSizeOf; 64 use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; 65 use rustc_hash::FxHashMap; 66 use selectors::attr::{CaseSensitivity, NamespaceConstraint}; 67 use selectors::bloom::BloomFilter; 68 use selectors::matching::{ 69 matches_selector, selector_may_match, MatchingContext, MatchingMode, NeedsSelectorFlags, 70 SelectorCaches, 71 }; 72 use selectors::matching::{MatchingForInvalidation, VisitedHandlingMode}; 73 use selectors::parser::{ 74 AncestorHashes, Combinator, Component, MatchesFeaturelessHost, Selector, SelectorIter, 75 SelectorList, 76 }; 77 use selectors::visitor::{SelectorListKind, SelectorVisitor}; 78 use servo_arc::{Arc, ArcBorrow, ThinArc}; 79 use smallvec::SmallVec; 80 use std::cmp::Ordering; 81 use std::hash::{Hash, Hasher}; 82 use std::mem; 83 use std::sync::{LazyLock, Mutex}; 84 85 /// The type of the stylesheets that the stylist contains. 86 #[cfg(feature = "servo")] 87 pub type StylistSheet = crate::stylesheets::DocumentStyleSheet; 88 89 /// The type of the stylesheets that the stylist contains. 90 #[cfg(feature = "gecko")] 91 pub type StylistSheet = crate::gecko::data::GeckoStyleSheet; 92 93 #[derive(Debug, Clone)] 94 struct StylesheetContentsPtr(Arc<StylesheetContents>); 95 96 impl PartialEq for StylesheetContentsPtr { 97 #[inline] 98 fn eq(&self, other: &Self) -> bool { 99 Arc::ptr_eq(&self.0, &other.0) 100 } 101 } 102 103 impl Eq for StylesheetContentsPtr {} 104 105 impl Hash for StylesheetContentsPtr { 106 fn hash<H: Hasher>(&self, state: &mut H) { 107 let contents: &StylesheetContents = &*self.0; 108 (contents as *const StylesheetContents).hash(state) 109 } 110 } 111 112 type StyleSheetContentList = Vec<StylesheetContentsPtr>; 113 114 /// The @position-try rules that have changed. 115 #[derive(Default, Debug, MallocSizeOf)] 116 pub struct CascadeDataDifference { 117 /// The set of changed @position-try rule names. 118 pub changed_position_try_names: PrecomputedHashSet<Atom>, 119 } 120 121 impl CascadeDataDifference { 122 /// Merges another difference into `self`. 123 pub fn merge_with(&mut self, other: Self) { 124 self.changed_position_try_names 125 .extend(other.changed_position_try_names.into_iter()) 126 } 127 128 /// Returns whether we're empty. 129 pub fn is_empty(&self) -> bool { 130 self.changed_position_try_names.is_empty() 131 } 132 133 fn update(&mut self, old_data: &PositionTryMap, new_data: &PositionTryMap) { 134 let mut any_different_key = false; 135 let different_len = old_data.len() != new_data.len(); 136 for (name, rules) in old_data.iter() { 137 let changed = match new_data.get(name) { 138 Some(new_rule) => !Arc::ptr_eq(&rules.last().unwrap().0, new_rule), 139 None => { 140 any_different_key = true; 141 true 142 }, 143 }; 144 if changed { 145 self.changed_position_try_names.insert(name.clone()); 146 } 147 } 148 149 if any_different_key || different_len { 150 for name in new_data.keys() { 151 // If the key exists in both, we've already checked it above. 152 if !old_data.contains_key(name) { 153 self.changed_position_try_names.insert(name.clone()); 154 } 155 } 156 } 157 } 158 } 159 160 /// A key in the cascade data cache. 161 #[derive(Debug, Hash, Default, PartialEq, Eq)] 162 struct CascadeDataCacheKey { 163 media_query_results: Vec<MediaListKey>, 164 contents: StyleSheetContentList, 165 } 166 167 unsafe impl Send for CascadeDataCacheKey {} 168 unsafe impl Sync for CascadeDataCacheKey {} 169 170 trait CascadeDataCacheEntry: Sized { 171 /// Rebuilds the cascade data for the new stylesheet collection. The 172 /// collection is guaranteed to be dirty. 173 fn rebuild<S>( 174 device: &Device, 175 quirks_mode: QuirksMode, 176 collection: SheetCollectionFlusher<S>, 177 guard: &SharedRwLockReadGuard, 178 old_entry: &Self, 179 difference: &mut CascadeDataDifference, 180 ) -> Result<Arc<Self>, AllocErr> 181 where 182 S: StylesheetInDocument + PartialEq + 'static; 183 /// Measures heap memory usage. 184 #[cfg(feature = "gecko")] 185 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes); 186 } 187 188 struct CascadeDataCache<Entry> { 189 entries: FxHashMap<CascadeDataCacheKey, Arc<Entry>>, 190 } 191 192 impl<Entry> CascadeDataCache<Entry> 193 where 194 Entry: CascadeDataCacheEntry, 195 { 196 fn new() -> Self { 197 Self { 198 entries: Default::default(), 199 } 200 } 201 202 fn len(&self) -> usize { 203 self.entries.len() 204 } 205 206 // FIXME(emilio): This may need to be keyed on quirks-mode too, though for 207 // UA sheets there aren't class / id selectors on those sheets, usually, so 208 // it's probably ok... For the other cache the quirks mode shouldn't differ 209 // so also should be fine. 210 fn lookup<'a, S>( 211 &'a mut self, 212 device: &Device, 213 quirks_mode: QuirksMode, 214 collection: SheetCollectionFlusher<S>, 215 guard: &SharedRwLockReadGuard, 216 old_entry: &Entry, 217 difference: &mut CascadeDataDifference, 218 ) -> Result<Option<Arc<Entry>>, AllocErr> 219 where 220 S: StylesheetInDocument + PartialEq + 'static, 221 { 222 use std::collections::hash_map::Entry as HashMapEntry; 223 debug!("StyleSheetCache::lookup({})", self.len()); 224 225 if !collection.dirty() { 226 return Ok(None); 227 } 228 229 let mut key = CascadeDataCacheKey::default(); 230 let mut custom_media_map = CustomMediaMap::default(); 231 for sheet in collection.sheets() { 232 CascadeData::collect_applicable_media_query_results_into( 233 device, 234 sheet, 235 guard, 236 &mut key.media_query_results, 237 &mut key.contents, 238 &mut custom_media_map, 239 ) 240 } 241 242 let new_entry; 243 match self.entries.entry(key) { 244 HashMapEntry::Vacant(e) => { 245 debug!("> Picking the slow path (not in the cache)"); 246 new_entry = Entry::rebuild( 247 device, 248 quirks_mode, 249 collection, 250 guard, 251 old_entry, 252 difference, 253 )?; 254 e.insert(new_entry.clone()); 255 }, 256 HashMapEntry::Occupied(mut e) => { 257 // Avoid reusing our old entry (this can happen if we get 258 // invalidated due to CSSOM mutations and our old stylesheet 259 // contents were already unique, for example). 260 if !std::ptr::eq(&**e.get(), old_entry) { 261 if log_enabled!(log::Level::Debug) { 262 debug!("cache hit for:"); 263 for sheet in collection.sheets() { 264 debug!(" > {:?}", sheet); 265 } 266 } 267 // The line below ensures the "committed" bit is updated 268 // properly. 269 collection.each(|_, _, _| true); 270 return Ok(Some(e.get().clone())); 271 } 272 273 debug!("> Picking the slow path due to same entry as old"); 274 new_entry = Entry::rebuild( 275 device, 276 quirks_mode, 277 collection, 278 guard, 279 old_entry, 280 difference, 281 )?; 282 e.insert(new_entry.clone()); 283 }, 284 } 285 286 Ok(Some(new_entry)) 287 } 288 289 /// Returns all the cascade datas that are not being used (that is, that are 290 /// held alive just by this cache). 291 /// 292 /// We return them instead of dropping in place because some of them may 293 /// keep alive some other documents (like the SVG documents kept alive by 294 /// URL references), and thus we don't want to drop them while locking the 295 /// cache to not deadlock. 296 fn take_unused(&mut self) -> SmallVec<[Arc<Entry>; 3]> { 297 let mut unused = SmallVec::new(); 298 self.entries.retain(|_key, value| { 299 // is_unique() returns false for static references, but we never 300 // have static references to UserAgentCascadeDatas. If we did, it 301 // may not make sense to put them in the cache in the first place. 302 if !value.is_unique() { 303 return true; 304 } 305 unused.push(value.clone()); 306 false 307 }); 308 unused 309 } 310 311 fn take_all(&mut self) -> FxHashMap<CascadeDataCacheKey, Arc<Entry>> { 312 mem::take(&mut self.entries) 313 } 314 315 #[cfg(feature = "gecko")] 316 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 317 sizes.mOther += self.entries.shallow_size_of(ops); 318 for (_key, arc) in self.entries.iter() { 319 // These are primary Arc references that can be measured 320 // unconditionally. 321 sizes.mOther += arc.unconditional_shallow_size_of(ops); 322 arc.add_size_of(ops, sizes); 323 } 324 } 325 } 326 327 /// Measure heap usage of UA_CASCADE_DATA_CACHE. 328 #[cfg(feature = "gecko")] 329 pub fn add_size_of_ua_cache(ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 330 UA_CASCADE_DATA_CACHE 331 .lock() 332 .unwrap() 333 .add_size_of(ops, sizes); 334 } 335 336 /// A cache of computed user-agent data, to be shared across documents. 337 static UA_CASCADE_DATA_CACHE: LazyLock<Mutex<UserAgentCascadeDataCache>> = 338 LazyLock::new(|| Mutex::new(UserAgentCascadeDataCache::new())); 339 340 impl CascadeDataCacheEntry for UserAgentCascadeData { 341 fn rebuild<S>( 342 device: &Device, 343 quirks_mode: QuirksMode, 344 collection: SheetCollectionFlusher<S>, 345 guard: &SharedRwLockReadGuard, 346 old: &Self, 347 difference: &mut CascadeDataDifference, 348 ) -> Result<Arc<Self>, AllocErr> 349 where 350 S: StylesheetInDocument + PartialEq + 'static, 351 { 352 // TODO: Maybe we should support incremental rebuilds, though they seem uncommon and 353 // rebuild() doesn't deal with precomputed_pseudo_element_decls for now so... 354 let mut new_data = servo_arc::UniqueArc::new(Self { 355 cascade_data: CascadeData::new(), 356 precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations::default(), 357 }); 358 359 for (index, sheet) in collection.sheets().enumerate() { 360 let new_data = &mut *new_data; 361 new_data.cascade_data.add_stylesheet( 362 device, 363 quirks_mode, 364 sheet, 365 index, 366 guard, 367 SheetRebuildKind::Full, 368 Some(&mut new_data.precomputed_pseudo_element_decls), 369 None, 370 )?; 371 } 372 373 new_data.cascade_data.did_finish_rebuild(); 374 difference.update( 375 &old.cascade_data.extra_data.position_try_rules, 376 &new_data.cascade_data.extra_data.position_try_rules, 377 ); 378 379 Ok(new_data.shareable()) 380 } 381 382 #[cfg(feature = "gecko")] 383 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 384 self.cascade_data.add_size_of(ops, sizes); 385 sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops); 386 } 387 } 388 389 type UserAgentCascadeDataCache = CascadeDataCache<UserAgentCascadeData>; 390 391 type PrecomputedPseudoElementDeclarations = PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>; 392 393 #[derive(Default)] 394 struct UserAgentCascadeData { 395 cascade_data: CascadeData, 396 397 /// Applicable declarations for a given non-eagerly cascaded pseudo-element. 398 /// 399 /// These are eagerly computed once, and then used to resolve the new 400 /// computed values on the fly on layout. 401 /// 402 /// These are only filled from UA stylesheets. 403 precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations, 404 } 405 406 /// The empty UA cascade data for un-filled stylists. 407 static EMPTY_UA_CASCADE_DATA: LazyLock<Arc<UserAgentCascadeData>> = LazyLock::new(|| { 408 let arc = Arc::new(UserAgentCascadeData::default()); 409 arc.mark_as_intentionally_leaked(); 410 arc 411 }); 412 413 /// All the computed information for all the stylesheets that apply to the 414 /// document. 415 #[derive(MallocSizeOf)] 416 pub struct DocumentCascadeData { 417 #[ignore_malloc_size_of = "Arc, owned by UserAgentCascadeDataCache or empty"] 418 user_agent: Arc<UserAgentCascadeData>, 419 user: CascadeData, 420 author: CascadeData, 421 per_origin: PerOrigin<()>, 422 } 423 424 impl Default for DocumentCascadeData { 425 fn default() -> Self { 426 Self { 427 user_agent: EMPTY_UA_CASCADE_DATA.clone(), 428 user: Default::default(), 429 author: Default::default(), 430 per_origin: Default::default(), 431 } 432 } 433 } 434 435 /// An iterator over the cascade data of a given document. 436 pub struct DocumentCascadeDataIter<'a> { 437 iter: PerOriginIter<'a, ()>, 438 cascade_data: &'a DocumentCascadeData, 439 } 440 441 impl<'a> Iterator for DocumentCascadeDataIter<'a> { 442 type Item = (&'a CascadeData, Origin); 443 444 fn next(&mut self) -> Option<Self::Item> { 445 let (_, origin) = self.iter.next()?; 446 Some((self.cascade_data.borrow_for_origin(origin), origin)) 447 } 448 } 449 450 impl DocumentCascadeData { 451 /// Borrows the cascade data for a given origin. 452 #[inline] 453 pub fn borrow_for_origin(&self, origin: Origin) -> &CascadeData { 454 match origin { 455 Origin::UserAgent => &self.user_agent.cascade_data, 456 Origin::Author => &self.author, 457 Origin::User => &self.user, 458 } 459 } 460 461 fn iter_origins(&self) -> DocumentCascadeDataIter<'_> { 462 DocumentCascadeDataIter { 463 iter: self.per_origin.iter_origins(), 464 cascade_data: self, 465 } 466 } 467 468 fn iter_origins_rev(&self) -> DocumentCascadeDataIter<'_> { 469 DocumentCascadeDataIter { 470 iter: self.per_origin.iter_origins_rev(), 471 cascade_data: self, 472 } 473 } 474 475 fn custom_media_for_sheet( 476 &self, 477 s: &StylistSheet, 478 guard: &SharedRwLockReadGuard, 479 ) -> &CustomMediaMap { 480 let origin = s.contents(guard).origin; 481 &self.borrow_for_origin(origin).custom_media 482 } 483 484 /// Rebuild the cascade data for the given document stylesheets, and 485 /// optionally with a set of user agent stylesheets. Returns Err(..) 486 /// to signify OOM. 487 fn rebuild<'a, S>( 488 &mut self, 489 device: &Device, 490 quirks_mode: QuirksMode, 491 mut flusher: DocumentStylesheetFlusher<'a, S>, 492 guards: &StylesheetGuards, 493 difference: &mut CascadeDataDifference, 494 ) -> Result<(), AllocErr> 495 where 496 S: StylesheetInDocument + PartialEq + 'static, 497 { 498 // First do UA sheets. 499 { 500 let origin_flusher = flusher.flush_origin(Origin::UserAgent); 501 // Dirty check is just a minor optimization (no need to grab the 502 // lock if nothing has changed). 503 if origin_flusher.dirty() { 504 let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap(); 505 let new_data = ua_cache.lookup( 506 device, 507 quirks_mode, 508 origin_flusher, 509 guards.ua_or_user, 510 &self.user_agent, 511 difference, 512 )?; 513 if let Some(new_data) = new_data { 514 self.user_agent = new_data; 515 } 516 let _unused_entries = ua_cache.take_unused(); 517 // See the comments in take_unused() as for why the following line. 518 std::mem::drop(ua_cache); 519 } 520 } 521 522 // Now do the user sheets. 523 self.user.rebuild( 524 device, 525 quirks_mode, 526 flusher.flush_origin(Origin::User), 527 guards.ua_or_user, 528 difference, 529 )?; 530 531 // And now the author sheets. 532 self.author.rebuild( 533 device, 534 quirks_mode, 535 flusher.flush_origin(Origin::Author), 536 guards.author, 537 difference, 538 )?; 539 540 Ok(()) 541 } 542 543 /// Measures heap usage. 544 #[cfg(feature = "gecko")] 545 pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 546 self.user.add_size_of(ops, sizes); 547 self.author.add_size_of(ops, sizes); 548 } 549 } 550 551 /// Whether author styles are enabled. 552 /// 553 /// This is used to support Gecko. 554 #[allow(missing_docs)] 555 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] 556 pub enum AuthorStylesEnabled { 557 Yes, 558 No, 559 } 560 561 /// A wrapper over a DocumentStylesheetSet that can be `Sync`, since it's only 562 /// used and exposed via mutable methods in the `Stylist`. 563 #[cfg_attr(feature = "servo", derive(MallocSizeOf))] 564 #[derive(Deref, DerefMut)] 565 struct StylistStylesheetSet(DocumentStylesheetSet<StylistSheet>); 566 // Read above to see why this is fine. 567 unsafe impl Sync for StylistStylesheetSet {} 568 569 impl StylistStylesheetSet { 570 fn new() -> Self { 571 StylistStylesheetSet(DocumentStylesheetSet::new()) 572 } 573 } 574 575 /// This structure holds all the selectors and device characteristics 576 /// for a given document. The selectors are converted into `Rule`s 577 /// and sorted into `SelectorMap`s keyed off stylesheet origin and 578 /// pseudo-element (see `CascadeData`). 579 /// 580 /// This structure is effectively created once per pipeline, in the 581 /// LayoutThread corresponding to that pipeline. 582 #[cfg_attr(feature = "servo", derive(MallocSizeOf))] 583 pub struct Stylist { 584 /// Device that the stylist is currently evaluating against. 585 /// 586 /// This field deserves a bigger comment due to the different use that Gecko 587 /// and Servo give to it (that we should eventually unify). 588 /// 589 /// With Gecko, the device is never changed. Gecko manually tracks whether 590 /// the device data should be reconstructed, and "resets" the state of the 591 /// device. 592 /// 593 /// On Servo, on the other hand, the device is a really cheap representation 594 /// that is recreated each time some constraint changes and calling 595 /// `set_device`. 596 device: Device, 597 598 /// The list of stylesheets. 599 stylesheets: StylistStylesheetSet, 600 601 /// A cache of CascadeDatas for AuthorStylesheetSets (i.e., shadow DOM). 602 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "XXX: how to handle this?")] 603 author_data_cache: CascadeDataCache<CascadeData>, 604 605 /// If true, the quirks-mode stylesheet is applied. 606 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "defined in selectors")] 607 quirks_mode: QuirksMode, 608 609 /// Selector maps for all of the style sheets in the stylist, after 610 /// evalutaing media rules against the current device, split out per 611 /// cascade level. 612 cascade_data: DocumentCascadeData, 613 614 /// Whether author styles are enabled. 615 author_styles_enabled: AuthorStylesEnabled, 616 617 /// The rule tree, that stores the results of selector matching. 618 rule_tree: RuleTree, 619 620 /// The set of registered custom properties from script. 621 /// <https://drafts.css-houdini.org/css-properties-values-api-1/#dom-window-registeredpropertyset-slot> 622 script_custom_properties: CustomPropertyScriptRegistry, 623 624 /// Initial values for registered custom properties. 625 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] 626 initial_values_for_custom_properties: ComputedCustomProperties, 627 628 /// Flags set from computing registered custom property initial values. 629 initial_values_for_custom_properties_flags: ComputedValueFlags, 630 631 /// The total number of times the stylist has been rebuilt. 632 num_rebuilds: usize, 633 } 634 635 /// What cascade levels to include when styling elements. 636 #[derive(Clone, Copy, PartialEq)] 637 pub enum RuleInclusion { 638 /// Include rules for style sheets at all cascade levels. This is the 639 /// normal rule inclusion mode. 640 All, 641 /// Only include rules from UA and user level sheets. Used to implement 642 /// `getDefaultComputedStyle`. 643 DefaultOnly, 644 } 645 646 #[cfg(feature = "gecko")] 647 impl From<StyleRuleInclusion> for RuleInclusion { 648 fn from(value: StyleRuleInclusion) -> Self { 649 match value { 650 StyleRuleInclusion::All => RuleInclusion::All, 651 StyleRuleInclusion::DefaultOnly => RuleInclusion::DefaultOnly, 652 } 653 } 654 } 655 656 /// `:scope` selector, depending on the use case, can match a shadow host. 657 /// If used outside of `@scope`, it cannot possibly match the host. 658 /// Even when inside of `@scope`, it's conditional if the selector will 659 /// match the shadow host. 660 #[derive(Clone, Copy, Eq, PartialEq)] 661 enum ScopeMatchesShadowHost { 662 NotApplicable, 663 No, 664 Yes, 665 } 666 667 impl Default for ScopeMatchesShadowHost { 668 fn default() -> Self { 669 Self::NotApplicable 670 } 671 } 672 673 impl ScopeMatchesShadowHost { 674 fn nest_for_scope(&mut self, matches_shadow_host: bool) { 675 match *self { 676 Self::NotApplicable => { 677 // We're at the outermost `@scope`. 678 *self = if matches_shadow_host { 679 Self::Yes 680 } else { 681 Self::No 682 }; 683 }, 684 Self::Yes if !matches_shadow_host => { 685 // Inner `@scope` will not be able to match the shadow host. 686 *self = Self::No; 687 }, 688 _ => (), 689 } 690 } 691 } 692 693 /// Nested declarations have effectively two behaviors: 694 /// * Inside style rules (where they behave as the containing selector). 695 /// * Inside @scope (where they behave as :where(:scope)). 696 /// It is a bit unfortunate ideally we wouldn't need this, because scope also pushes to the 697 /// ancestor_selector_lists, but the behavior isn't quite the same as wrapping in `&`, see 698 /// https://github.com/w3c/csswg-drafts/issues/10431 699 #[derive(Copy, Clone)] 700 enum NestedDeclarationsContext { 701 Style, 702 Scope, 703 } 704 705 /// A struct containing state related to scope rules 706 struct ContainingScopeRuleState { 707 id: ScopeConditionId, 708 inner_dependencies: Vec<Dependency>, 709 matches_shadow_host: ScopeMatchesShadowHost, 710 } 711 712 impl Default for ContainingScopeRuleState { 713 fn default() -> Self { 714 Self { 715 id: ScopeConditionId::none(), 716 inner_dependencies: Vec::new(), 717 matches_shadow_host: Default::default(), 718 } 719 } 720 } 721 722 impl ContainingScopeRuleState { 723 fn save(&self) -> SavedContainingScopeRuleState { 724 SavedContainingScopeRuleState { 725 id: self.id, 726 matches_shadow_host: self.matches_shadow_host, 727 inner_dependencies_len: self.inner_dependencies.len(), 728 } 729 } 730 731 fn restore( 732 &mut self, 733 saved: &SavedContainingScopeRuleState, 734 ) -> Option<(Vec<Dependency>, ScopeConditionId)> { 735 debug_assert!(self.inner_dependencies.len() >= saved.inner_dependencies_len); 736 737 if self.id == saved.id { 738 return None; 739 } 740 741 let scope_id = self.id; 742 let inner_deps = self 743 .inner_dependencies 744 .drain(saved.inner_dependencies_len..) 745 .collect(); 746 747 self.id = saved.id; 748 self.matches_shadow_host = saved.matches_shadow_host; 749 750 Some((inner_deps, scope_id)) 751 } 752 } 753 754 struct SavedContainingScopeRuleState { 755 id: ScopeConditionId, 756 matches_shadow_host: ScopeMatchesShadowHost, 757 inner_dependencies_len: usize, 758 } 759 760 /// A struct containing state from ancestor rules like @layer / @import / 761 /// @container / nesting / @scope. 762 struct ContainingRuleState { 763 layer_name: LayerName, 764 layer_id: LayerId, 765 container_condition_id: ContainerConditionId, 766 in_starting_style: bool, 767 containing_scope_rule_state: ContainingScopeRuleState, 768 ancestor_selector_lists: SmallVec<[SelectorList<SelectorImpl>; 2]>, 769 nested_declarations_context: NestedDeclarationsContext, 770 } 771 772 impl Default for ContainingRuleState { 773 fn default() -> Self { 774 Self { 775 layer_name: LayerName::new_empty(), 776 layer_id: LayerId::root(), 777 container_condition_id: ContainerConditionId::none(), 778 in_starting_style: false, 779 ancestor_selector_lists: Default::default(), 780 containing_scope_rule_state: Default::default(), 781 nested_declarations_context: NestedDeclarationsContext::Style, 782 } 783 } 784 } 785 786 struct SavedContainingRuleState { 787 ancestor_selector_lists_len: usize, 788 layer_name_len: usize, 789 layer_id: LayerId, 790 container_condition_id: ContainerConditionId, 791 in_starting_style: bool, 792 saved_containing_scope_rule_state: SavedContainingScopeRuleState, 793 nested_declarations_context: NestedDeclarationsContext, 794 } 795 796 impl ContainingRuleState { 797 fn save(&self) -> SavedContainingRuleState { 798 SavedContainingRuleState { 799 ancestor_selector_lists_len: self.ancestor_selector_lists.len(), 800 layer_name_len: self.layer_name.0.len(), 801 layer_id: self.layer_id, 802 container_condition_id: self.container_condition_id, 803 in_starting_style: self.in_starting_style, 804 saved_containing_scope_rule_state: self.containing_scope_rule_state.save(), 805 nested_declarations_context: self.nested_declarations_context, 806 } 807 } 808 809 fn restore( 810 &mut self, 811 saved: &SavedContainingRuleState, 812 ) -> Option<(Vec<Dependency>, ScopeConditionId)> { 813 debug_assert!(self.layer_name.0.len() >= saved.layer_name_len); 814 debug_assert!(self.ancestor_selector_lists.len() >= saved.ancestor_selector_lists_len); 815 816 self.ancestor_selector_lists 817 .truncate(saved.ancestor_selector_lists_len); 818 self.layer_name.0.truncate(saved.layer_name_len); 819 self.layer_id = saved.layer_id; 820 self.container_condition_id = saved.container_condition_id; 821 self.in_starting_style = saved.in_starting_style; 822 self.nested_declarations_context = saved.nested_declarations_context; 823 824 self.containing_scope_rule_state 825 .restore(&saved.saved_containing_scope_rule_state) 826 } 827 828 fn scope_is_effective(&self) -> bool { 829 self.containing_scope_rule_state.id != ScopeConditionId::none() 830 } 831 } 832 833 type ReplacedSelectors = SmallVec<[Selector<SelectorImpl>; 4]>; 834 835 impl Stylist { 836 /// Construct a new `Stylist`, using given `Device` and `QuirksMode`. 837 /// If more members are added here, think about whether they should 838 /// be reset in clear(). 839 #[inline] 840 pub fn new(device: Device, quirks_mode: QuirksMode) -> Self { 841 Self { 842 device, 843 quirks_mode, 844 stylesheets: StylistStylesheetSet::new(), 845 author_data_cache: CascadeDataCache::new(), 846 cascade_data: Default::default(), 847 author_styles_enabled: AuthorStylesEnabled::Yes, 848 rule_tree: RuleTree::new(), 849 script_custom_properties: Default::default(), 850 initial_values_for_custom_properties: Default::default(), 851 initial_values_for_custom_properties_flags: Default::default(), 852 num_rebuilds: 0, 853 } 854 } 855 856 /// Returns the document cascade data. 857 #[inline] 858 pub fn cascade_data(&self) -> &DocumentCascadeData { 859 &self.cascade_data 860 } 861 862 /// Returns whether author styles are enabled or not. 863 #[inline] 864 pub fn author_styles_enabled(&self) -> AuthorStylesEnabled { 865 self.author_styles_enabled 866 } 867 868 /// Iterate through all the cascade datas from the document. 869 #[inline] 870 pub fn iter_origins(&self) -> DocumentCascadeDataIter<'_> { 871 self.cascade_data.iter_origins() 872 } 873 874 /// Does what the name says, to prevent author_data_cache to grow without 875 /// bound. 876 pub fn remove_unique_author_data_cache_entries(&mut self) { 877 self.author_data_cache.take_unused(); 878 } 879 880 /// Returns the custom property registration for this property's name. 881 /// https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration 882 pub fn get_custom_property_registration(&self, name: &Atom) -> &PropertyRegistrationData { 883 if let Some(registration) = self.custom_property_script_registry().get(name) { 884 return ®istration.data; 885 } 886 for (data, _) in self.iter_origins() { 887 if let Some(registration) = data.custom_property_registrations.get(name) { 888 return ®istration.data; 889 } 890 } 891 PropertyRegistrationData::unregistered() 892 } 893 894 /// Returns custom properties with their registered initial values. 895 pub fn get_custom_property_initial_values(&self) -> &ComputedCustomProperties { 896 &self.initial_values_for_custom_properties 897 } 898 899 /// Returns flags set from computing the registered custom property initial values. 900 pub fn get_custom_property_initial_values_flags(&self) -> ComputedValueFlags { 901 self.initial_values_for_custom_properties_flags 902 } 903 904 /// Rebuild custom properties with their registered initial values. 905 /// https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration 906 pub fn rebuild_initial_values_for_custom_properties(&mut self) { 907 let mut initial_values = ComputedCustomProperties::default(); 908 let initial_values_flags; 909 { 910 let mut seen_names = PrecomputedHashSet::default(); 911 let mut rule_cache_conditions = RuleCacheConditions::default(); 912 let context = computed::Context::new_for_initial_at_property_value( 913 self, 914 &mut rule_cache_conditions, 915 ); 916 917 for (k, v) in self.custom_property_script_registry().properties().iter() { 918 seen_names.insert(k.clone()); 919 let Ok(value) = v.compute_initial_value(&context) else { 920 continue; 921 }; 922 let map = if v.inherits() { 923 &mut initial_values.inherited 924 } else { 925 &mut initial_values.non_inherited 926 }; 927 map.insert(k, value); 928 } 929 for (data, _) in self.iter_origins() { 930 for (k, v) in data.custom_property_registrations.iter() { 931 if seen_names.insert(k.clone()) { 932 let last_value = &v.last().unwrap().0; 933 let Ok(value) = last_value.compute_initial_value(&context) else { 934 continue; 935 }; 936 let map = if last_value.inherits() { 937 &mut initial_values.inherited 938 } else { 939 &mut initial_values.non_inherited 940 }; 941 map.insert(k, value); 942 } 943 } 944 } 945 initial_values_flags = context.builder.flags(); 946 } 947 self.initial_values_for_custom_properties_flags = initial_values_flags; 948 self.initial_values_for_custom_properties = initial_values; 949 } 950 951 /// Rebuilds (if needed) the CascadeData given a sheet collection. 952 pub fn rebuild_author_data<S>( 953 &mut self, 954 old_data: &CascadeData, 955 collection: SheetCollectionFlusher<S>, 956 guard: &SharedRwLockReadGuard, 957 difference: &mut CascadeDataDifference, 958 ) -> Result<Option<Arc<CascadeData>>, AllocErr> 959 where 960 S: StylesheetInDocument + PartialEq + 'static, 961 { 962 self.author_data_cache.lookup( 963 &self.device, 964 self.quirks_mode, 965 collection, 966 guard, 967 old_data, 968 difference, 969 ) 970 } 971 972 /// Iterate over the extra data in origin order. 973 #[inline] 974 pub fn iter_extra_data_origins(&self) -> ExtraStyleDataIterator<'_> { 975 ExtraStyleDataIterator(self.cascade_data.iter_origins()) 976 } 977 978 /// Iterate over the extra data in reverse origin order. 979 #[inline] 980 pub fn iter_extra_data_origins_rev(&self) -> ExtraStyleDataIterator<'_> { 981 ExtraStyleDataIterator(self.cascade_data.iter_origins_rev()) 982 } 983 984 /// Returns the number of selectors. 985 pub fn num_selectors(&self) -> usize { 986 self.cascade_data 987 .iter_origins() 988 .map(|(d, _)| d.num_selectors) 989 .sum() 990 } 991 992 /// Returns the number of declarations. 993 pub fn num_declarations(&self) -> usize { 994 self.cascade_data 995 .iter_origins() 996 .map(|(d, _)| d.num_declarations) 997 .sum() 998 } 999 1000 /// Returns the number of times the stylist has been rebuilt. 1001 pub fn num_rebuilds(&self) -> usize { 1002 self.num_rebuilds 1003 } 1004 1005 /// Returns the number of revalidation_selectors. 1006 pub fn num_revalidation_selectors(&self) -> usize { 1007 self.cascade_data 1008 .iter_origins() 1009 .map(|(data, _)| data.selectors_for_cache_revalidation.len()) 1010 .sum() 1011 } 1012 1013 /// Returns the number of entries in invalidation maps. 1014 pub fn num_invalidations(&self) -> usize { 1015 self.cascade_data 1016 .iter_origins() 1017 .map(|(data, _)| { 1018 data.invalidation_map.len() + data.relative_selector_invalidation_map.len() 1019 }) 1020 .sum() 1021 } 1022 1023 /// Returns whether the given DocumentState bit is relied upon by a selector 1024 /// of some rule. 1025 pub fn has_document_state_dependency(&self, state: DocumentState) -> bool { 1026 self.cascade_data 1027 .iter_origins() 1028 .any(|(d, _)| d.document_state_dependencies.intersects(state)) 1029 } 1030 1031 /// Flush the list of stylesheets if they changed, ensuring the stylist is 1032 /// up-to-date. 1033 pub fn flush(&mut self, guards: &StylesheetGuards) -> StylesheetInvalidationSet { 1034 if !self.stylesheets.has_changed() { 1035 return Default::default(); 1036 } 1037 1038 self.num_rebuilds += 1; 1039 1040 let (flusher, mut invalidations) = self.stylesheets.flush(); 1041 1042 self.cascade_data 1043 .rebuild( 1044 &self.device, 1045 self.quirks_mode, 1046 flusher, 1047 guards, 1048 &mut invalidations.cascade_data_difference, 1049 ) 1050 .unwrap_or_else(|_| { 1051 warn!("OOM in Stylist::flush"); 1052 }); 1053 1054 self.rebuild_initial_values_for_custom_properties(); 1055 invalidations 1056 } 1057 1058 /// Marks a given stylesheet origin as dirty, due to, for example, changes 1059 /// in the declarations that affect a given rule. 1060 /// 1061 /// FIXME(emilio): Eventually it'd be nice for this to become more 1062 /// fine-grained. 1063 pub fn force_stylesheet_origins_dirty(&mut self, origins: OriginSet) { 1064 self.stylesheets.force_dirty(origins) 1065 } 1066 1067 /// Sets whether author style is enabled or not. 1068 pub fn set_author_styles_enabled(&mut self, enabled: AuthorStylesEnabled) { 1069 self.author_styles_enabled = enabled; 1070 } 1071 1072 /// Returns whether we've recorded any stylesheet change so far. 1073 pub fn stylesheets_have_changed(&self) -> bool { 1074 self.stylesheets.has_changed() 1075 } 1076 1077 /// Insert a given stylesheet before another stylesheet in the document. 1078 pub fn insert_stylesheet_before( 1079 &mut self, 1080 sheet: StylistSheet, 1081 before_sheet: StylistSheet, 1082 guard: &SharedRwLockReadGuard, 1083 ) { 1084 let custom_media = self.cascade_data.custom_media_for_sheet(&sheet, guard); 1085 self.stylesheets.insert_stylesheet_before( 1086 Some(&self.device), 1087 custom_media, 1088 sheet, 1089 before_sheet, 1090 guard, 1091 ) 1092 } 1093 1094 /// Appends a new stylesheet to the current set. 1095 pub fn append_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) { 1096 let custom_media = self.cascade_data.custom_media_for_sheet(&sheet, guard); 1097 self.stylesheets 1098 .append_stylesheet(Some(&self.device), custom_media, sheet, guard) 1099 } 1100 1101 /// Remove a given stylesheet to the current set. 1102 pub fn remove_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) { 1103 let custom_media = self.cascade_data.custom_media_for_sheet(&sheet, guard); 1104 self.stylesheets 1105 .remove_stylesheet(Some(&self.device), custom_media, sheet, guard) 1106 } 1107 1108 /// Notify of a change of a given rule. 1109 pub fn rule_changed( 1110 &mut self, 1111 sheet: &StylistSheet, 1112 rule: &CssRule, 1113 guard: &SharedRwLockReadGuard, 1114 change_kind: RuleChangeKind, 1115 ancestors: &[CssRuleRef], 1116 ) { 1117 let custom_media = self.cascade_data.custom_media_for_sheet(&sheet, guard); 1118 self.stylesheets.rule_changed( 1119 Some(&self.device), 1120 custom_media, 1121 sheet, 1122 rule, 1123 guard, 1124 change_kind, 1125 ancestors, 1126 ) 1127 } 1128 1129 /// Get the total stylesheet count for a given origin. 1130 #[inline] 1131 pub fn sheet_count(&self, origin: Origin) -> usize { 1132 self.stylesheets.sheet_count(origin) 1133 } 1134 1135 /// Get the index-th stylesheet for a given origin. 1136 #[inline] 1137 pub fn sheet_at(&self, origin: Origin, index: usize) -> Option<&StylistSheet> { 1138 self.stylesheets.get(origin, index) 1139 } 1140 1141 /// Returns whether for any of the applicable style rule data a given 1142 /// condition is true. 1143 pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool 1144 where 1145 E: TElement, 1146 F: FnMut(&CascadeData) -> bool, 1147 { 1148 if f(&self.cascade_data.user_agent.cascade_data) { 1149 return true; 1150 } 1151 1152 let mut maybe = false; 1153 1154 let doc_author_rules_apply = 1155 element.each_applicable_non_document_style_rule_data(|data, _| { 1156 maybe = maybe || f(&*data); 1157 }); 1158 1159 if maybe || f(&self.cascade_data.user) { 1160 return true; 1161 } 1162 1163 doc_author_rules_apply && f(&self.cascade_data.author) 1164 } 1165 1166 /// Execute callback for all applicable style rule data. 1167 pub fn for_each_cascade_data_with_scope<'a, E, F>(&'a self, element: E, mut f: F) 1168 where 1169 E: TElement + 'a, 1170 F: FnMut(&'a CascadeData, Option<E>), 1171 { 1172 f(&self.cascade_data.user_agent.cascade_data, None); 1173 element.each_applicable_non_document_style_rule_data(|data, scope| { 1174 f(data, Some(scope)); 1175 }); 1176 f(&self.cascade_data.user, None); 1177 f(&self.cascade_data.author, None); 1178 } 1179 1180 /// Computes the style for a given "precomputed" pseudo-element, taking the 1181 /// universal rules and applying them. 1182 pub fn precomputed_values_for_pseudo<E>( 1183 &self, 1184 guards: &StylesheetGuards, 1185 pseudo: &PseudoElement, 1186 parent: Option<&ComputedValues>, 1187 ) -> Arc<ComputedValues> 1188 where 1189 E: TElement, 1190 { 1191 debug_assert!(pseudo.is_precomputed()); 1192 1193 let rule_node = self.rule_node_for_precomputed_pseudo(guards, pseudo, vec![]); 1194 1195 self.precomputed_values_for_pseudo_with_rule_node::<E>(guards, pseudo, parent, rule_node) 1196 } 1197 1198 /// Computes the style for a given "precomputed" pseudo-element with 1199 /// given rule node. 1200 /// 1201 /// TODO(emilio): The type parameter could go away with a void type 1202 /// implementing TElement. 1203 pub fn precomputed_values_for_pseudo_with_rule_node<E>( 1204 &self, 1205 guards: &StylesheetGuards, 1206 pseudo: &PseudoElement, 1207 parent: Option<&ComputedValues>, 1208 rules: StrongRuleNode, 1209 ) -> Arc<ComputedValues> 1210 where 1211 E: TElement, 1212 { 1213 self.compute_pseudo_element_style_with_inputs::<E>( 1214 CascadeInputs { 1215 rules: Some(rules), 1216 visited_rules: None, 1217 flags: Default::default(), 1218 }, 1219 pseudo, 1220 guards, 1221 parent, 1222 /* element */ None, 1223 ) 1224 } 1225 1226 /// Returns the rule node for a given precomputed pseudo-element. 1227 /// 1228 /// If we want to include extra declarations to this precomputed 1229 /// pseudo-element, we can provide a vector of ApplicableDeclarationBlocks 1230 /// to extra_declarations. This is useful for @page rules. 1231 pub fn rule_node_for_precomputed_pseudo( 1232 &self, 1233 guards: &StylesheetGuards, 1234 pseudo: &PseudoElement, 1235 mut extra_declarations: Vec<ApplicableDeclarationBlock>, 1236 ) -> StrongRuleNode { 1237 let mut declarations_with_extra; 1238 let declarations = match self 1239 .cascade_data 1240 .user_agent 1241 .precomputed_pseudo_element_decls 1242 .get(pseudo) 1243 { 1244 Some(declarations) => { 1245 if !extra_declarations.is_empty() { 1246 declarations_with_extra = declarations.clone(); 1247 declarations_with_extra.append(&mut extra_declarations); 1248 &*declarations_with_extra 1249 } else { 1250 &**declarations 1251 } 1252 }, 1253 None => &[], 1254 }; 1255 1256 self.rule_tree.insert_ordered_rules_with_important( 1257 declarations.into_iter().map(|a| a.clone().for_rule_tree()), 1258 guards, 1259 ) 1260 } 1261 1262 /// Returns the style for an anonymous box of the given type. 1263 /// 1264 /// TODO(emilio): The type parameter could go away with a void type 1265 /// implementing TElement. 1266 #[cfg(feature = "servo")] 1267 pub fn style_for_anonymous<E>( 1268 &self, 1269 guards: &StylesheetGuards, 1270 pseudo: &PseudoElement, 1271 parent_style: &ComputedValues, 1272 ) -> Arc<ComputedValues> 1273 where 1274 E: TElement, 1275 { 1276 self.precomputed_values_for_pseudo::<E>(guards, &pseudo, Some(parent_style)) 1277 } 1278 1279 /// Computes a pseudo-element style lazily during layout. 1280 /// 1281 /// This can only be done for a certain set of pseudo-elements, like 1282 /// :selection. 1283 /// 1284 /// Check the documentation on lazy pseudo-elements in 1285 /// docs/components/style.md 1286 pub fn lazily_compute_pseudo_element_style<E>( 1287 &self, 1288 guards: &StylesheetGuards, 1289 element: E, 1290 pseudo: &PseudoElement, 1291 rule_inclusion: RuleInclusion, 1292 originating_element_style: &ComputedValues, 1293 is_probe: bool, 1294 matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>, 1295 ) -> Option<Arc<ComputedValues>> 1296 where 1297 E: TElement, 1298 { 1299 let cascade_inputs = self.lazy_pseudo_rules( 1300 guards, 1301 element, 1302 originating_element_style, 1303 pseudo, 1304 is_probe, 1305 rule_inclusion, 1306 matching_fn, 1307 )?; 1308 1309 Some(self.compute_pseudo_element_style_with_inputs( 1310 cascade_inputs, 1311 pseudo, 1312 guards, 1313 Some(originating_element_style), 1314 Some(element), 1315 )) 1316 } 1317 1318 /// Computes a pseudo-element style lazily using the given CascadeInputs. 1319 /// This can be used for truly lazy pseudo-elements or to avoid redoing 1320 /// selector matching for eager pseudo-elements when we need to recompute 1321 /// their style with a new parent style. 1322 pub fn compute_pseudo_element_style_with_inputs<E>( 1323 &self, 1324 inputs: CascadeInputs, 1325 pseudo: &PseudoElement, 1326 guards: &StylesheetGuards, 1327 parent_style: Option<&ComputedValues>, 1328 element: Option<E>, 1329 ) -> Arc<ComputedValues> 1330 where 1331 E: TElement, 1332 { 1333 // FIXME(emilio): The lack of layout_parent_style here could be 1334 // worrying, but we're probably dropping the display fixup for 1335 // pseudos other than before and after, so it's probably ok. 1336 // 1337 // (Though the flags don't indicate so!) 1338 // 1339 // It'd be fine to assert that this isn't called with a parent style 1340 // where display contents is in effect, but in practice this is hard to 1341 // do for stuff like :-moz-fieldset-content with a 1342 // <fieldset style="display: contents">. That is, the computed value of 1343 // display for the fieldset is "contents", even though it's not the used 1344 // value, so we don't need to adjust in a different way anyway. 1345 self.cascade_style_and_visited( 1346 element, 1347 Some(pseudo), 1348 inputs, 1349 guards, 1350 parent_style, 1351 parent_style, 1352 FirstLineReparenting::No, 1353 &PositionTryFallbacksTryTactic::default(), 1354 /* rule_cache = */ None, 1355 &mut RuleCacheConditions::default(), 1356 ) 1357 } 1358 1359 /// Computes a fallback style lazily given the current and parent styles, and name. 1360 pub fn resolve_position_try<E>( 1361 &self, 1362 style: &ComputedValues, 1363 guards: &StylesheetGuards, 1364 element: E, 1365 fallback_item: &PositionTryFallbacksItem, 1366 ) -> Option<Arc<ComputedValues>> 1367 where 1368 E: TElement, 1369 { 1370 let name_and_try_tactic = match *fallback_item { 1371 PositionTryFallbacksItem::PositionArea(area) => { 1372 // We don't bother passing the parent_style argument here since 1373 // we probably don't need it. If we do, we could wrap this up in 1374 // a style_resolver::with_default_parent_styles call, as below. 1375 let mut builder = 1376 StyleBuilder::for_derived_style(&self.device, Some(self), style, None); 1377 builder.mutate_position().set_position_area(area); 1378 return Some(builder.build()); 1379 }, 1380 PositionTryFallbacksItem::IdentAndOrTactic(ref name_and_try_tactic) => { 1381 name_and_try_tactic 1382 }, 1383 }; 1384 1385 let fallback_rule = if !name_and_try_tactic.ident.is_empty() { 1386 Some(self.lookup_position_try(&name_and_try_tactic.ident.0, element)?) 1387 } else { 1388 None 1389 }; 1390 let fallback_block = fallback_rule 1391 .as_ref() 1392 .map(|r| &r.read_with(guards.author).block); 1393 let pseudo = style 1394 .pseudo() 1395 .or_else(|| element.implemented_pseudo_element()); 1396 let inputs = { 1397 let mut inputs = CascadeInputs::new_from_style(style); 1398 // @position-try doesn't care about any :visited-dependent property. 1399 inputs.visited_rules = None; 1400 let rules = inputs.rules.as_ref().unwrap_or(self.rule_tree.root()); 1401 let mut important_rules_changed = false; 1402 if let Some(fallback_block) = fallback_block { 1403 let new_rules = self.rule_tree.update_rule_at_level( 1404 CascadeLevel::PositionFallback, 1405 LayerOrder::root(), 1406 Some(fallback_block.borrow_arc()), 1407 rules, 1408 guards, 1409 &mut important_rules_changed, 1410 ); 1411 if new_rules.is_some() { 1412 inputs.rules = new_rules; 1413 } else { 1414 // This will return an identical style to `style`. We could consider optimizing 1415 // this a bit more but for now just perform the cascade, this can only happen with 1416 // the same position-try name repeated multiple times anyways. 1417 } 1418 } 1419 inputs 1420 }; 1421 crate::style_resolver::with_default_parent_styles( 1422 element, 1423 |parent_style, layout_parent_style| { 1424 Some(self.cascade_style_and_visited( 1425 Some(element), 1426 pseudo.as_ref(), 1427 inputs, 1428 guards, 1429 parent_style, 1430 layout_parent_style, 1431 FirstLineReparenting::No, 1432 &name_and_try_tactic.try_tactic, 1433 /* rule_cache = */ None, 1434 &mut RuleCacheConditions::default(), 1435 )) 1436 }, 1437 ) 1438 } 1439 1440 /// Computes a style using the given CascadeInputs. This can be used to 1441 /// compute a style any time we know what rules apply and just need to use 1442 /// the given parent styles. 1443 /// 1444 /// parent_style is the style to inherit from for properties affected by 1445 /// first-line ancestors. 1446 /// 1447 /// parent_style_ignoring_first_line is the style to inherit from for 1448 /// properties not affected by first-line ancestors. 1449 /// 1450 /// layout_parent_style is the style used for some property fixups. It's 1451 /// the style of the nearest ancestor with a layout box. 1452 pub fn cascade_style_and_visited<E>( 1453 &self, 1454 element: Option<E>, 1455 pseudo: Option<&PseudoElement>, 1456 inputs: CascadeInputs, 1457 guards: &StylesheetGuards, 1458 parent_style: Option<&ComputedValues>, 1459 layout_parent_style: Option<&ComputedValues>, 1460 first_line_reparenting: FirstLineReparenting, 1461 try_tactic: &PositionTryFallbacksTryTactic, 1462 rule_cache: Option<&RuleCache>, 1463 rule_cache_conditions: &mut RuleCacheConditions, 1464 ) -> Arc<ComputedValues> 1465 where 1466 E: TElement, 1467 { 1468 debug_assert!(pseudo.is_some() || element.is_some(), "Huh?"); 1469 1470 // We need to compute visited values if we have visited rules or if our 1471 // parent has visited values. 1472 let visited_rules = match inputs.visited_rules.as_ref() { 1473 Some(rules) => Some(rules), 1474 None => { 1475 if parent_style.and_then(|s| s.visited_style()).is_some() { 1476 Some(inputs.rules.as_ref().unwrap_or(self.rule_tree.root())) 1477 } else { 1478 None 1479 } 1480 }, 1481 }; 1482 1483 let mut implemented_pseudo = None; 1484 // Read the comment on `precomputed_values_for_pseudo` to see why it's 1485 // difficult to assert that display: contents nodes never arrive here 1486 // (tl;dr: It doesn't apply for replaced elements and such, but the 1487 // computed value is still "contents"). 1488 // 1489 // FIXME(emilio): We should assert that it holds if pseudo.is_none()! 1490 properties::cascade::<E>( 1491 &self, 1492 pseudo.or_else(|| { 1493 implemented_pseudo = element.unwrap().implemented_pseudo_element(); 1494 implemented_pseudo.as_ref() 1495 }), 1496 inputs.rules.as_ref().unwrap_or(self.rule_tree.root()), 1497 guards, 1498 parent_style, 1499 layout_parent_style, 1500 first_line_reparenting, 1501 try_tactic, 1502 visited_rules, 1503 inputs.flags, 1504 rule_cache, 1505 rule_cache_conditions, 1506 element, 1507 ) 1508 } 1509 1510 /// Computes the cascade inputs for a lazily-cascaded pseudo-element. 1511 /// 1512 /// See the documentation on lazy pseudo-elements in 1513 /// docs/components/style.md 1514 fn lazy_pseudo_rules<E>( 1515 &self, 1516 guards: &StylesheetGuards, 1517 element: E, 1518 originating_element_style: &ComputedValues, 1519 pseudo: &PseudoElement, 1520 is_probe: bool, 1521 rule_inclusion: RuleInclusion, 1522 matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>, 1523 ) -> Option<CascadeInputs> 1524 where 1525 E: TElement, 1526 { 1527 debug_assert!(pseudo.is_lazy()); 1528 1529 let mut selector_caches = SelectorCaches::default(); 1530 // No need to bother setting the selector flags when we're computing 1531 // default styles. 1532 let needs_selector_flags = if rule_inclusion == RuleInclusion::DefaultOnly { 1533 NeedsSelectorFlags::No 1534 } else { 1535 NeedsSelectorFlags::Yes 1536 }; 1537 1538 let mut declarations = ApplicableDeclarationList::new(); 1539 let mut matching_context = MatchingContext::<'_, E::Impl>::new( 1540 MatchingMode::ForStatelessPseudoElement, 1541 None, 1542 &mut selector_caches, 1543 self.quirks_mode, 1544 needs_selector_flags, 1545 MatchingForInvalidation::No, 1546 ); 1547 1548 matching_context.pseudo_element_matching_fn = matching_fn; 1549 matching_context.extra_data.originating_element_style = Some(originating_element_style); 1550 1551 self.push_applicable_declarations( 1552 element, 1553 Some(&pseudo), 1554 None, 1555 None, 1556 /* animation_declarations = */ Default::default(), 1557 rule_inclusion, 1558 &mut declarations, 1559 &mut matching_context, 1560 ); 1561 1562 if declarations.is_empty() && is_probe { 1563 return None; 1564 } 1565 1566 let rules = self.rule_tree.compute_rule_node(&mut declarations, guards); 1567 1568 let mut visited_rules = None; 1569 if originating_element_style.visited_style().is_some() { 1570 let mut declarations = ApplicableDeclarationList::new(); 1571 let mut selector_caches = SelectorCaches::default(); 1572 1573 let mut matching_context = MatchingContext::<'_, E::Impl>::new_for_visited( 1574 MatchingMode::ForStatelessPseudoElement, 1575 None, 1576 &mut selector_caches, 1577 VisitedHandlingMode::RelevantLinkVisited, 1578 selectors::matching::IncludeStartingStyle::No, 1579 self.quirks_mode, 1580 needs_selector_flags, 1581 MatchingForInvalidation::No, 1582 ); 1583 matching_context.pseudo_element_matching_fn = matching_fn; 1584 matching_context.extra_data.originating_element_style = Some(originating_element_style); 1585 1586 self.push_applicable_declarations( 1587 element, 1588 Some(&pseudo), 1589 None, 1590 None, 1591 /* animation_declarations = */ Default::default(), 1592 rule_inclusion, 1593 &mut declarations, 1594 &mut matching_context, 1595 ); 1596 if !declarations.is_empty() { 1597 let rule_node = self.rule_tree.insert_ordered_rules_with_important( 1598 declarations.drain(..).map(|a| a.for_rule_tree()), 1599 guards, 1600 ); 1601 if rule_node != *self.rule_tree.root() { 1602 visited_rules = Some(rule_node); 1603 } 1604 } 1605 } 1606 1607 Some(CascadeInputs { 1608 rules: Some(rules), 1609 visited_rules, 1610 flags: matching_context.extra_data.cascade_input_flags, 1611 }) 1612 } 1613 1614 /// Set a given device, which may change the styles that apply to the 1615 /// document. 1616 /// 1617 /// Returns the sheet origins that were actually affected. 1618 /// 1619 /// This means that we may need to rebuild style data even if the 1620 /// stylesheets haven't changed. 1621 /// 1622 /// Also, the device that arrives here may need to take the viewport rules 1623 /// into account. 1624 pub fn set_device(&mut self, device: Device, guards: &StylesheetGuards) -> OriginSet { 1625 self.device = device; 1626 self.media_features_change_changed_style(guards, &self.device) 1627 } 1628 1629 /// Returns whether, given a media feature change, any previously-applicable 1630 /// style has become non-applicable, or vice-versa for each origin, using 1631 /// `device`. 1632 pub fn media_features_change_changed_style( 1633 &self, 1634 guards: &StylesheetGuards, 1635 device: &Device, 1636 ) -> OriginSet { 1637 debug!("Stylist::media_features_change_changed_style {:?}", device); 1638 1639 let mut origins = OriginSet::empty(); 1640 let stylesheets = self.stylesheets.iter(); 1641 1642 for (stylesheet, origin) in stylesheets { 1643 if origins.contains(origin.into()) { 1644 continue; 1645 } 1646 1647 let guard = guards.for_origin(origin); 1648 let origin_cascade_data = self.cascade_data.borrow_for_origin(origin); 1649 1650 let affected_changed = !origin_cascade_data.media_feature_affected_matches( 1651 stylesheet, 1652 guard, 1653 device, 1654 self.quirks_mode, 1655 ); 1656 1657 if affected_changed { 1658 origins |= origin; 1659 } 1660 } 1661 1662 origins 1663 } 1664 1665 /// Returns the Quirks Mode of the document. 1666 pub fn quirks_mode(&self) -> QuirksMode { 1667 self.quirks_mode 1668 } 1669 1670 /// Sets the quirks mode of the document. 1671 pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) { 1672 if self.quirks_mode == quirks_mode { 1673 return; 1674 } 1675 self.quirks_mode = quirks_mode; 1676 self.force_stylesheet_origins_dirty(OriginSet::all()); 1677 } 1678 1679 /// Returns the applicable CSS declarations for the given element. 1680 pub fn push_applicable_declarations<E>( 1681 &self, 1682 element: E, 1683 pseudo_element: Option<&PseudoElement>, 1684 style_attribute: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>, 1685 smil_override: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>, 1686 animation_declarations: AnimationDeclarations, 1687 rule_inclusion: RuleInclusion, 1688 applicable_declarations: &mut ApplicableDeclarationList, 1689 context: &mut MatchingContext<E::Impl>, 1690 ) where 1691 E: TElement, 1692 { 1693 let mut cur = element; 1694 let mut pseudos = SmallVec::new(); 1695 if let Some(pseudo) = pseudo_element { 1696 pseudos.push(pseudo.clone()); 1697 } 1698 while let Some(p) = cur.implemented_pseudo_element() { 1699 pseudos.push(p); 1700 let Some(parent_pseudo) = cur.pseudo_element_originating_element() else { 1701 break; 1702 }; 1703 cur = parent_pseudo; 1704 } 1705 RuleCollector::new( 1706 self, 1707 element, 1708 pseudos, 1709 style_attribute, 1710 smil_override, 1711 animation_declarations, 1712 rule_inclusion, 1713 applicable_declarations, 1714 context, 1715 ) 1716 .collect_all(); 1717 } 1718 1719 /// Given an id, returns whether there might be any rules for that id in any 1720 /// of our rule maps. 1721 #[inline] 1722 pub fn may_have_rules_for_id<E>(&self, id: &WeakAtom, element: E) -> bool 1723 where 1724 E: TElement, 1725 { 1726 // If id needs to be compared case-insensitively, the logic below 1727 // wouldn't work. Just conservatively assume it may have such rules. 1728 match self.quirks_mode().classes_and_ids_case_sensitivity() { 1729 CaseSensitivity::AsciiCaseInsensitive => return true, 1730 CaseSensitivity::CaseSensitive => {}, 1731 } 1732 1733 self.any_applicable_rule_data(element, |data| data.mapped_ids.contains(id)) 1734 } 1735 1736 /// Looks up a CascadeData-dependent rule for a given element. 1737 /// 1738 /// NOTE(emilio): This is a best-effort thing, the right fix is a bit TBD because it involves 1739 /// "recording" which tree the name came from, see [1][2]. 1740 /// 1741 /// [1]: https://github.com/w3c/csswg-drafts/issues/1995 1742 /// [2]: https://bugzil.la/1458189 1743 #[inline] 1744 fn lookup_element_dependent_at_rule<'a, T, F, E>( 1745 &'a self, 1746 element: E, 1747 find_in: F, 1748 ) -> Option<&'a T> 1749 where 1750 E: TElement + 'a, 1751 F: Fn(&'a CascadeData) -> Option<&'a T>, 1752 { 1753 macro_rules! try_find_in { 1754 ($data:expr) => { 1755 if let Some(thing) = find_in(&$data) { 1756 return Some(thing); 1757 } 1758 }; 1759 } 1760 1761 let mut result = None; 1762 let doc_rules_apply = 1763 element.each_applicable_non_document_style_rule_data(|data, _host| { 1764 if result.is_none() { 1765 result = find_in(data); 1766 } 1767 }); 1768 1769 if result.is_some() { 1770 return result; 1771 } 1772 1773 if doc_rules_apply { 1774 try_find_in!(self.cascade_data.author); 1775 } 1776 try_find_in!(self.cascade_data.user); 1777 try_find_in!(self.cascade_data.user_agent.cascade_data); 1778 1779 None 1780 } 1781 1782 /// Returns the registered `@keyframes` animation for the specified name. 1783 #[inline] 1784 pub fn lookup_keyframes<'a, E>( 1785 &'a self, 1786 name: &Atom, 1787 element: E, 1788 ) -> Option<&'a KeyframesAnimation> 1789 where 1790 E: TElement + 'a, 1791 { 1792 self.lookup_element_dependent_at_rule(element, |data| data.animations.get(name)) 1793 } 1794 1795 /// Returns the registered `@position-try-rule` animation for the specified name. 1796 #[inline] 1797 #[cfg(feature = "gecko")] 1798 fn lookup_position_try<'a, E>( 1799 &'a self, 1800 name: &Atom, 1801 element: E, 1802 ) -> Option<&'a Arc<Locked<PositionTryRule>>> 1803 where 1804 E: TElement + 'a, 1805 { 1806 self.lookup_element_dependent_at_rule(element, |data| { 1807 data.extra_data.position_try_rules.get(name) 1808 }) 1809 } 1810 1811 /// Computes the match results of a given element against the set of 1812 /// revalidation selectors. 1813 pub fn match_revalidation_selectors<E>( 1814 &self, 1815 element: E, 1816 bloom: Option<&BloomFilter>, 1817 selector_caches: &mut SelectorCaches, 1818 needs_selector_flags: NeedsSelectorFlags, 1819 ) -> RevalidationResult 1820 where 1821 E: TElement, 1822 { 1823 // NB: `MatchingMode` doesn't really matter, given we don't share style 1824 // between pseudos. 1825 let mut matching_context = MatchingContext::new( 1826 MatchingMode::Normal, 1827 bloom, 1828 selector_caches, 1829 self.quirks_mode, 1830 needs_selector_flags, 1831 MatchingForInvalidation::No, 1832 ); 1833 1834 // Note that, by the time we're revalidating, we're guaranteed that the 1835 // candidate and the entry have the same id, classes, and local name. 1836 // This means we're guaranteed to get the same rulehash buckets for all 1837 // the lookups, which means that the bitvecs are comparable. We verify 1838 // this in the caller by asserting that the bitvecs are same-length. 1839 let mut result = RevalidationResult::default(); 1840 let mut relevant_attributes = &mut result.relevant_attributes; 1841 let selectors_matched = &mut result.selectors_matched; 1842 1843 let matches_document_rules = 1844 element.each_applicable_non_document_style_rule_data(|data, host| { 1845 matching_context.with_shadow_host(Some(host), |matching_context| { 1846 data.selectors_for_cache_revalidation.lookup( 1847 element, 1848 self.quirks_mode, 1849 Some(&mut relevant_attributes), 1850 |selector_and_hashes| { 1851 selectors_matched.push(matches_selector( 1852 &selector_and_hashes.selector, 1853 selector_and_hashes.selector_offset, 1854 Some(&selector_and_hashes.hashes), 1855 &element, 1856 matching_context, 1857 )); 1858 true 1859 }, 1860 ); 1861 }) 1862 }); 1863 1864 for (data, origin) in self.cascade_data.iter_origins() { 1865 if origin == Origin::Author && !matches_document_rules { 1866 continue; 1867 } 1868 1869 data.selectors_for_cache_revalidation.lookup( 1870 element, 1871 self.quirks_mode, 1872 Some(&mut relevant_attributes), 1873 |selector_and_hashes| { 1874 selectors_matched.push(matches_selector( 1875 &selector_and_hashes.selector, 1876 selector_and_hashes.selector_offset, 1877 Some(&selector_and_hashes.hashes), 1878 &element, 1879 &mut matching_context, 1880 )); 1881 true 1882 }, 1883 ); 1884 } 1885 1886 result 1887 } 1888 1889 /// Computes currently active scopes for the given element for revalidation purposes. 1890 pub fn revalidate_scopes<E: TElement>( 1891 &self, 1892 element: &E, 1893 selector_caches: &mut SelectorCaches, 1894 needs_selector_flags: NeedsSelectorFlags, 1895 ) -> ScopeRevalidationResult { 1896 let mut matching_context = MatchingContext::new( 1897 MatchingMode::Normal, 1898 None, 1899 selector_caches, 1900 self.quirks_mode, 1901 needs_selector_flags, 1902 MatchingForInvalidation::No, 1903 ); 1904 1905 let mut result = ScopeRevalidationResult::default(); 1906 let matches_document_rules = 1907 element.each_applicable_non_document_style_rule_data(|data, host| { 1908 matching_context.with_shadow_host(Some(host), |matching_context| { 1909 data.revalidate_scopes(element, matching_context, &mut result); 1910 }) 1911 }); 1912 1913 for (data, origin) in self.cascade_data.iter_origins() { 1914 if origin == Origin::Author && !matches_document_rules { 1915 continue; 1916 } 1917 1918 data.revalidate_scopes(element, &mut matching_context, &mut result); 1919 } 1920 1921 result 1922 } 1923 1924 /// Computes styles for a given declaration with parent_style. 1925 /// 1926 /// FIXME(emilio): the lack of pseudo / cascade flags look quite dubious, 1927 /// hopefully this is only used for some canvas font stuff. 1928 /// 1929 /// TODO(emilio): The type parameter can go away when 1930 /// https://github.com/rust-lang/rust/issues/35121 is fixed. 1931 pub fn compute_for_declarations<E>( 1932 &self, 1933 guards: &StylesheetGuards, 1934 parent_style: &ComputedValues, 1935 declarations: Arc<Locked<PropertyDeclarationBlock>>, 1936 ) -> Arc<ComputedValues> 1937 where 1938 E: TElement, 1939 { 1940 let block = declarations.read_with(guards.author); 1941 1942 // We don't bother inserting these declarations in the rule tree, since 1943 // it'd be quite useless and slow. 1944 // 1945 // TODO(emilio): Now that we fixed bug 1493420, we should consider 1946 // reversing this as it shouldn't be slow anymore, and should avoid 1947 // generating two instantiations of apply_declarations. 1948 properties::apply_declarations::<E, _>( 1949 &self, 1950 /* pseudo = */ None, 1951 self.rule_tree.root(), 1952 guards, 1953 block.declaration_importance_iter().map(|(declaration, _)| { 1954 ( 1955 declaration, 1956 CascadePriority::new( 1957 CascadeLevel::same_tree_author_normal(), 1958 LayerOrder::root(), 1959 ), 1960 ) 1961 }), 1962 Some(parent_style), 1963 Some(parent_style), 1964 FirstLineReparenting::No, 1965 &PositionTryFallbacksTryTactic::default(), 1966 CascadeMode::Unvisited { 1967 visited_rules: None, 1968 }, 1969 Default::default(), 1970 /* rule_cache = */ None, 1971 &mut Default::default(), 1972 /* element = */ None, 1973 ) 1974 } 1975 1976 /// Accessor for a shared reference to the device. 1977 #[inline] 1978 pub fn device(&self) -> &Device { 1979 &self.device 1980 } 1981 1982 /// Accessor for a mutable reference to the device. 1983 #[inline] 1984 pub fn device_mut(&mut self) -> &mut Device { 1985 &mut self.device 1986 } 1987 1988 /// Accessor for a shared reference to the rule tree. 1989 #[inline] 1990 pub fn rule_tree(&self) -> &RuleTree { 1991 &self.rule_tree 1992 } 1993 1994 /// Returns the script-registered custom property registry. 1995 #[inline] 1996 pub fn custom_property_script_registry(&self) -> &CustomPropertyScriptRegistry { 1997 &self.script_custom_properties 1998 } 1999 2000 /// Returns the script-registered custom property registry, as a mutable ref. 2001 #[inline] 2002 pub fn custom_property_script_registry_mut(&mut self) -> &mut CustomPropertyScriptRegistry { 2003 &mut self.script_custom_properties 2004 } 2005 2006 /// Measures heap usage. 2007 #[cfg(feature = "gecko")] 2008 pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 2009 self.cascade_data.add_size_of(ops, sizes); 2010 self.author_data_cache.add_size_of(ops, sizes); 2011 sizes.mRuleTree += self.rule_tree.size_of(ops); 2012 2013 // We may measure other fields in the future if DMD says it's worth it. 2014 } 2015 2016 /// Shutdown the static data that this module stores. 2017 pub fn shutdown() { 2018 let _entries = UA_CASCADE_DATA_CACHE.lock().unwrap().take_all(); 2019 } 2020 } 2021 2022 /// A vector that is sorted in layer order. 2023 #[derive(Clone, Debug, Deref, MallocSizeOf)] 2024 pub struct LayerOrderedVec<T>(Vec<(T, LayerId)>); 2025 impl<T> Default for LayerOrderedVec<T> { 2026 fn default() -> Self { 2027 Self(Default::default()) 2028 } 2029 } 2030 2031 /// A map that is sorted in layer order. 2032 #[derive(Clone, Debug, Deref, MallocSizeOf)] 2033 pub struct LayerOrderedMap<T>(PrecomputedHashMap<Atom, SmallVec<[(T, LayerId); 1]>>); 2034 impl<T> Default for LayerOrderedMap<T> { 2035 fn default() -> Self { 2036 Self(Default::default()) 2037 } 2038 } 2039 2040 #[cfg(feature = "gecko")] 2041 impl<T: 'static> LayerOrderedVec<T> { 2042 fn clear(&mut self) { 2043 self.0.clear(); 2044 } 2045 fn push(&mut self, v: T, id: LayerId) { 2046 self.0.push((v, id)); 2047 } 2048 fn sort(&mut self, layers: &[CascadeLayer]) { 2049 self.0 2050 .sort_by_key(|&(_, ref id)| layers[id.0 as usize].order) 2051 } 2052 } 2053 2054 impl<T: 'static> LayerOrderedMap<T> { 2055 fn shrink_if_needed(&mut self) { 2056 self.0.shrink_if_needed(); 2057 } 2058 fn clear(&mut self) { 2059 self.0.clear(); 2060 } 2061 fn try_insert(&mut self, name: Atom, v: T, id: LayerId) -> Result<(), AllocErr> { 2062 self.try_insert_with(name, v, id, |_, _| Ordering::Equal) 2063 } 2064 fn try_insert_with( 2065 &mut self, 2066 name: Atom, 2067 v: T, 2068 id: LayerId, 2069 cmp: impl Fn(&T, &T) -> Ordering, 2070 ) -> Result<(), AllocErr> { 2071 self.0.try_reserve(1)?; 2072 let vec = self.0.entry(name).or_default(); 2073 if let Some(&mut (ref mut val, ref last_id)) = vec.last_mut() { 2074 if *last_id == id { 2075 if cmp(&val, &v) != Ordering::Greater { 2076 *val = v; 2077 } 2078 return Ok(()); 2079 } 2080 } 2081 vec.push((v, id)); 2082 Ok(()) 2083 } 2084 fn sort(&mut self, layers: &[CascadeLayer]) { 2085 self.sort_with(layers, |_, _| Ordering::Equal) 2086 } 2087 fn sort_with(&mut self, layers: &[CascadeLayer], cmp: impl Fn(&T, &T) -> Ordering) { 2088 for (_, v) in self.0.iter_mut() { 2089 v.sort_by(|&(ref v1, ref id1), &(ref v2, ref id2)| { 2090 let order1 = layers[id1.0 as usize].order; 2091 let order2 = layers[id2.0 as usize].order; 2092 order1.cmp(&order2).then_with(|| cmp(v1, v2)) 2093 }) 2094 } 2095 } 2096 /// Get an entry on the LayerOrderedMap by name. 2097 pub fn get(&self, name: &Atom) -> Option<&T> { 2098 let vec = self.0.get(name)?; 2099 Some(&vec.last()?.0) 2100 } 2101 } 2102 2103 /// Wrapper to allow better tracking of memory usage by page rule lists. 2104 /// 2105 /// This includes the layer ID for use with the named page table. 2106 #[derive(Clone, Debug, MallocSizeOf)] 2107 pub struct PageRuleData { 2108 /// Layer ID for sorting page rules after matching. 2109 pub layer: LayerId, 2110 /// Page rule 2111 #[ignore_malloc_size_of = "Arc, stylesheet measures as primary ref"] 2112 pub rule: Arc<Locked<PageRule>>, 2113 } 2114 2115 /// Stores page rules indexed by page names. 2116 #[derive(Clone, Debug, Default, MallocSizeOf)] 2117 pub struct PageRuleMap { 2118 /// Page rules, indexed by page name. An empty atom indicates no page name. 2119 pub rules: PrecomputedHashMap<Atom, SmallVec<[PageRuleData; 1]>>, 2120 } 2121 2122 impl PageRuleMap { 2123 #[inline] 2124 fn clear(&mut self) { 2125 self.rules.clear(); 2126 } 2127 2128 /// Uses page-name and pseudo-classes to match all applicable 2129 /// page-rules and append them to the matched_rules vec. 2130 /// This will ensure correct rule order for cascading. 2131 pub fn match_and_append_rules( 2132 &self, 2133 matched_rules: &mut Vec<ApplicableDeclarationBlock>, 2134 origin: Origin, 2135 guards: &StylesheetGuards, 2136 cascade_data: &DocumentCascadeData, 2137 name: &Option<Atom>, 2138 pseudos: PagePseudoClassFlags, 2139 ) { 2140 let level = match origin { 2141 Origin::UserAgent => CascadeLevel::UANormal, 2142 Origin::User => CascadeLevel::UserNormal, 2143 Origin::Author => CascadeLevel::same_tree_author_normal(), 2144 }; 2145 let cascade_data = cascade_data.borrow_for_origin(origin); 2146 let start = matched_rules.len(); 2147 2148 self.match_and_add_rules( 2149 matched_rules, 2150 level, 2151 guards, 2152 cascade_data, 2153 &atom!(""), 2154 pseudos, 2155 ); 2156 if let Some(name) = name { 2157 self.match_and_add_rules(matched_rules, level, guards, cascade_data, name, pseudos); 2158 } 2159 2160 // Because page-rules do not have source location information stored, 2161 // use stable sort to ensure source locations are preserved. 2162 matched_rules[start..].sort_by_key(|block| block.sort_key()); 2163 } 2164 2165 fn match_and_add_rules( 2166 &self, 2167 extra_declarations: &mut Vec<ApplicableDeclarationBlock>, 2168 level: CascadeLevel, 2169 guards: &StylesheetGuards, 2170 cascade_data: &CascadeData, 2171 name: &Atom, 2172 pseudos: PagePseudoClassFlags, 2173 ) { 2174 let rules = match self.rules.get(name) { 2175 Some(rules) => rules, 2176 None => return, 2177 }; 2178 for data in rules.iter() { 2179 let rule = data.rule.read_with(level.guard(&guards)); 2180 let specificity = match rule.match_specificity(pseudos) { 2181 Some(specificity) => specificity, 2182 None => continue, 2183 }; 2184 let block = rule.block.clone(); 2185 extra_declarations.push(ApplicableDeclarationBlock::new( 2186 StyleSource::from_declarations(block), 2187 0, 2188 level, 2189 specificity, 2190 cascade_data.layer_order_for(data.layer), 2191 ScopeProximity::infinity(), // Page rule can't have nested rules anyway. 2192 )); 2193 } 2194 } 2195 } 2196 2197 impl MallocShallowSizeOf for PageRuleMap { 2198 fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { 2199 self.rules.shallow_size_of(ops) 2200 } 2201 } 2202 2203 type PositionTryMap = LayerOrderedMap<Arc<Locked<PositionTryRule>>>; 2204 2205 /// This struct holds data which users of Stylist may want to extract from stylesheets which can be 2206 /// done at the same time as updating. 2207 #[derive(Clone, Debug, Default)] 2208 pub struct ExtraStyleData { 2209 /// A list of effective font-face rules and their origin. 2210 pub font_faces: LayerOrderedVec<Arc<Locked<FontFaceRule>>>, 2211 2212 /// A list of effective font-feature-values rules. 2213 pub font_feature_values: LayerOrderedVec<Arc<FontFeatureValuesRule>>, 2214 2215 /// A list of effective font-palette-values rules. 2216 pub font_palette_values: LayerOrderedVec<Arc<FontPaletteValuesRule>>, 2217 2218 /// A map of effective counter-style rules. 2219 pub counter_styles: LayerOrderedMap<Arc<Locked<CounterStyleRule>>>, 2220 2221 /// A map of effective @position-try rules. 2222 pub position_try_rules: PositionTryMap, 2223 2224 /// A map of effective page rules. 2225 pub pages: PageRuleMap, 2226 } 2227 2228 impl ExtraStyleData { 2229 /// Add the given @font-face rule. 2230 fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>, layer: LayerId) { 2231 self.font_faces.push(rule.clone(), layer); 2232 } 2233 2234 /// Add the given @font-feature-values rule. 2235 fn add_font_feature_values(&mut self, rule: &Arc<FontFeatureValuesRule>, layer: LayerId) { 2236 self.font_feature_values.push(rule.clone(), layer); 2237 } 2238 2239 /// Add the given @font-palette-values rule. 2240 fn add_font_palette_values(&mut self, rule: &Arc<FontPaletteValuesRule>, layer: LayerId) { 2241 self.font_palette_values.push(rule.clone(), layer); 2242 } 2243 2244 /// Add the given @counter-style rule. 2245 fn add_counter_style( 2246 &mut self, 2247 guard: &SharedRwLockReadGuard, 2248 rule: &Arc<Locked<CounterStyleRule>>, 2249 layer: LayerId, 2250 ) -> Result<(), AllocErr> { 2251 let name = rule.read_with(guard).name().0.clone(); 2252 self.counter_styles.try_insert(name, rule.clone(), layer) 2253 } 2254 2255 /// Add the given @position-try rule. 2256 fn add_position_try( 2257 &mut self, 2258 name: Atom, 2259 rule: Arc<Locked<PositionTryRule>>, 2260 layer: LayerId, 2261 ) -> Result<(), AllocErr> { 2262 self.position_try_rules.try_insert(name, rule, layer) 2263 } 2264 2265 /// Add the given @page rule. 2266 fn add_page( 2267 &mut self, 2268 guard: &SharedRwLockReadGuard, 2269 rule: &Arc<Locked<PageRule>>, 2270 layer: LayerId, 2271 ) -> Result<(), AllocErr> { 2272 let page_rule = rule.read_with(guard); 2273 let mut add_rule = |name| { 2274 let vec = self.pages.rules.entry(name).or_default(); 2275 vec.push(PageRuleData { 2276 layer, 2277 rule: rule.clone(), 2278 }); 2279 }; 2280 if page_rule.selectors.0.is_empty() { 2281 add_rule(atom!("")); 2282 } else { 2283 for selector in page_rule.selectors.as_slice() { 2284 add_rule(selector.name.0.clone()); 2285 } 2286 } 2287 Ok(()) 2288 } 2289 2290 fn sort_by_layer(&mut self, layers: &[CascadeLayer]) { 2291 self.font_faces.sort(layers); 2292 self.font_feature_values.sort(layers); 2293 self.font_palette_values.sort(layers); 2294 self.counter_styles.sort(layers); 2295 self.position_try_rules.sort(layers); 2296 } 2297 2298 fn clear(&mut self) { 2299 self.font_faces.clear(); 2300 self.font_feature_values.clear(); 2301 self.font_palette_values.clear(); 2302 self.counter_styles.clear(); 2303 self.position_try_rules.clear(); 2304 self.pages.clear(); 2305 } 2306 } 2307 2308 // Don't let a prefixed keyframes animation override 2309 // a non-prefixed one. 2310 fn compare_keyframes_in_same_layer(v1: &KeyframesAnimation, v2: &KeyframesAnimation) -> Ordering { 2311 if v1.vendor_prefix.is_some() == v2.vendor_prefix.is_some() { 2312 Ordering::Equal 2313 } else if v2.vendor_prefix.is_some() { 2314 Ordering::Greater 2315 } else { 2316 Ordering::Less 2317 } 2318 } 2319 2320 /// An iterator over the different ExtraStyleData. 2321 pub struct ExtraStyleDataIterator<'a>(DocumentCascadeDataIter<'a>); 2322 2323 impl<'a> Iterator for ExtraStyleDataIterator<'a> { 2324 type Item = (&'a ExtraStyleData, Origin); 2325 2326 fn next(&mut self) -> Option<Self::Item> { 2327 self.0.next().map(|d| (&d.0.extra_data, d.1)) 2328 } 2329 } 2330 2331 impl MallocSizeOf for ExtraStyleData { 2332 /// Measure heap usage. 2333 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { 2334 let mut n = 0; 2335 n += self.font_faces.shallow_size_of(ops); 2336 n += self.font_feature_values.shallow_size_of(ops); 2337 n += self.font_palette_values.shallow_size_of(ops); 2338 n += self.counter_styles.shallow_size_of(ops); 2339 n += self.position_try_rules.shallow_size_of(ops); 2340 n += self.pages.shallow_size_of(ops); 2341 n 2342 } 2343 } 2344 2345 /// SelectorMapEntry implementation for use in our revalidation selector map. 2346 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] 2347 #[derive(Clone, Debug)] 2348 struct RevalidationSelectorAndHashes { 2349 #[cfg_attr( 2350 feature = "gecko", 2351 ignore_malloc_size_of = "CssRules have primary refs, we measure there" 2352 )] 2353 selector: Selector<SelectorImpl>, 2354 selector_offset: usize, 2355 hashes: AncestorHashes, 2356 } 2357 2358 impl RevalidationSelectorAndHashes { 2359 fn new(selector: Selector<SelectorImpl>, hashes: AncestorHashes) -> Self { 2360 let selector_offset = { 2361 // We basically want to check whether the first combinator is a 2362 // pseudo-element combinator. If it is, we want to use the offset 2363 // one past it. Otherwise, our offset is 0. 2364 let mut index = 0; 2365 let mut iter = selector.iter(); 2366 2367 // First skip over the first ComplexSelector. 2368 // 2369 // We can't check what sort of what combinator we have until we do 2370 // that. 2371 for _ in &mut iter { 2372 index += 1; // Simple selector 2373 } 2374 2375 match iter.next_sequence() { 2376 Some(Combinator::PseudoElement) => index + 1, // +1 for the combinator 2377 _ => 0, 2378 } 2379 }; 2380 2381 RevalidationSelectorAndHashes { 2382 selector, 2383 selector_offset, 2384 hashes, 2385 } 2386 } 2387 } 2388 2389 impl SelectorMapEntry for RevalidationSelectorAndHashes { 2390 fn selector(&self) -> SelectorIter<'_, SelectorImpl> { 2391 self.selector.iter_from(self.selector_offset) 2392 } 2393 } 2394 2395 /// A selector visitor implementation that collects all the state the Stylist 2396 /// cares about a selector. 2397 struct StylistSelectorVisitor<'a> { 2398 /// Whether we've past the rightmost compound selector, not counting 2399 /// pseudo-elements. 2400 passed_rightmost_selector: bool, 2401 2402 /// Whether the selector needs revalidation for the style sharing cache. 2403 needs_revalidation: &'a mut bool, 2404 2405 /// Flags for which selector list-containing components the visitor is 2406 /// inside of, if any 2407 in_selector_list_of: SelectorListKind, 2408 2409 /// The filter with all the id's getting referenced from rightmost 2410 /// selectors. 2411 mapped_ids: &'a mut PrecomputedHashSet<Atom>, 2412 2413 /// The filter with the IDs getting referenced from the selector list of 2414 /// :nth-child(... of <selector list>) selectors. 2415 nth_of_mapped_ids: &'a mut PrecomputedHashSet<Atom>, 2416 2417 /// The filter with the local names of attributes there are selectors for. 2418 attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>, 2419 2420 /// The filter with the classes getting referenced from the selector list of 2421 /// :nth-child(... of <selector list>) selectors. 2422 nth_of_class_dependencies: &'a mut PrecomputedHashSet<Atom>, 2423 2424 /// The filter with the local names of attributes there are selectors for 2425 /// within the selector list of :nth-child(... of <selector list>) 2426 /// selectors. 2427 nth_of_attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>, 2428 2429 /// The filter with the local names of custom states in selectors for 2430 /// within the selector list of :nth-child(... of <selector list>) 2431 /// selectors. 2432 nth_of_custom_state_dependencies: &'a mut PrecomputedHashSet<AtomIdent>, 2433 2434 /// All the states selectors in the page reference. 2435 state_dependencies: &'a mut ElementState, 2436 2437 /// All the state selectors in the page reference within the selector list 2438 /// of :nth-child(... of <selector list>) selectors. 2439 nth_of_state_dependencies: &'a mut ElementState, 2440 2441 /// All the document states selectors in the page reference. 2442 document_state_dependencies: &'a mut DocumentState, 2443 } 2444 2445 fn component_needs_revalidation( 2446 c: &Component<SelectorImpl>, 2447 passed_rightmost_selector: bool, 2448 ) -> bool { 2449 match *c { 2450 Component::ID(_) => { 2451 // TODO(emilio): This could also check that the ID is not already in 2452 // the rule hash. In that case, we could avoid making this a 2453 // revalidation selector too. 2454 // 2455 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1369611 2456 passed_rightmost_selector 2457 }, 2458 Component::AttributeInNoNamespaceExists { .. } 2459 | Component::AttributeInNoNamespace { .. } 2460 | Component::AttributeOther(_) 2461 | Component::Empty 2462 | Component::Nth(_) 2463 | Component::NthOf(_) 2464 | Component::Has(_) => true, 2465 Component::NonTSPseudoClass(ref p) => p.needs_cache_revalidation(), 2466 _ => false, 2467 } 2468 } 2469 2470 impl<'a> StylistSelectorVisitor<'a> { 2471 fn visit_nested_selector( 2472 &mut self, 2473 in_selector_list_of: SelectorListKind, 2474 selector: &Selector<SelectorImpl>, 2475 ) { 2476 let old_passed_rightmost_selector = self.passed_rightmost_selector; 2477 let old_in_selector_list_of = self.in_selector_list_of; 2478 2479 self.passed_rightmost_selector = false; 2480 self.in_selector_list_of = in_selector_list_of; 2481 let _ret = selector.visit(self); 2482 debug_assert!(_ret, "We never return false"); 2483 2484 self.passed_rightmost_selector = old_passed_rightmost_selector; 2485 self.in_selector_list_of = old_in_selector_list_of; 2486 } 2487 } 2488 2489 impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> { 2490 type Impl = SelectorImpl; 2491 2492 fn visit_complex_selector(&mut self, combinator: Option<Combinator>) -> bool { 2493 *self.needs_revalidation = 2494 *self.needs_revalidation || combinator.map_or(false, |c| c.is_sibling()); 2495 2496 // NOTE(emilio): this call happens before we visit any of the simple 2497 // selectors in the next ComplexSelector, so we can use this to skip 2498 // looking at them. 2499 self.passed_rightmost_selector = self.passed_rightmost_selector 2500 || !matches!(combinator, None | Some(Combinator::PseudoElement)); 2501 2502 true 2503 } 2504 2505 fn visit_selector_list( 2506 &mut self, 2507 list_kind: SelectorListKind, 2508 list: &[Selector<Self::Impl>], 2509 ) -> bool { 2510 let in_selector_list_of = self.in_selector_list_of | list_kind; 2511 for selector in list { 2512 self.visit_nested_selector(in_selector_list_of, selector); 2513 } 2514 true 2515 } 2516 2517 fn visit_relative_selector_list( 2518 &mut self, 2519 list: &[selectors::parser::RelativeSelector<Self::Impl>], 2520 ) -> bool { 2521 let in_selector_list_of = self.in_selector_list_of | SelectorListKind::HAS; 2522 for selector in list { 2523 self.visit_nested_selector(in_selector_list_of, &selector.selector); 2524 } 2525 true 2526 } 2527 2528 fn visit_attribute_selector( 2529 &mut self, 2530 _ns: &NamespaceConstraint<&Namespace>, 2531 name: &LocalName, 2532 lower_name: &LocalName, 2533 ) -> bool { 2534 if self.in_selector_list_of.relevant_to_nth_of_dependencies() { 2535 self.nth_of_attribute_dependencies.insert(name.clone()); 2536 if name != lower_name { 2537 self.nth_of_attribute_dependencies 2538 .insert(lower_name.clone()); 2539 } 2540 } 2541 2542 self.attribute_dependencies.insert(name.clone()); 2543 if name != lower_name { 2544 self.attribute_dependencies.insert(lower_name.clone()); 2545 } 2546 2547 true 2548 } 2549 2550 fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool { 2551 *self.needs_revalidation = *self.needs_revalidation 2552 || component_needs_revalidation(s, self.passed_rightmost_selector); 2553 2554 match *s { 2555 Component::NonTSPseudoClass(NonTSPseudoClass::CustomState(ref name)) => { 2556 // CustomStateSet is special cased as it is a functional pseudo 2557 // class with unbounded inner values. This is different to 2558 // other psuedo class like :emtpy or :dir() which can be packed 2559 // into the ElementState bitflags. For CustomState, however, 2560 // the state name should be checked for presence in the selector. 2561 if self.in_selector_list_of.relevant_to_nth_of_dependencies() { 2562 self.nth_of_custom_state_dependencies.insert(name.0.clone()); 2563 } 2564 }, 2565 Component::NonTSPseudoClass(ref p) => { 2566 self.state_dependencies.insert(p.state_flag()); 2567 self.document_state_dependencies 2568 .insert(p.document_state_flag()); 2569 2570 if self.in_selector_list_of.relevant_to_nth_of_dependencies() { 2571 self.nth_of_state_dependencies.insert(p.state_flag()); 2572 } 2573 }, 2574 Component::ID(ref id) => { 2575 // We want to stop storing mapped ids as soon as we've moved off 2576 // the rightmost ComplexSelector that is not a pseudo-element. 2577 // 2578 // That can be detected by a visit_complex_selector call with a 2579 // combinator other than None and PseudoElement. 2580 // 2581 // Importantly, this call happens before we visit any of the 2582 // simple selectors in that ComplexSelector. 2583 // 2584 // NOTE(emilio): See the comment regarding on when this may 2585 // break in visit_complex_selector. 2586 if !self.passed_rightmost_selector { 2587 self.mapped_ids.insert(id.0.clone()); 2588 } 2589 2590 if self.in_selector_list_of.relevant_to_nth_of_dependencies() { 2591 self.nth_of_mapped_ids.insert(id.0.clone()); 2592 } 2593 }, 2594 Component::Class(ref class) 2595 if self.in_selector_list_of.relevant_to_nth_of_dependencies() => 2596 { 2597 self.nth_of_class_dependencies.insert(class.0.clone()); 2598 }, 2599 _ => {}, 2600 } 2601 2602 true 2603 } 2604 } 2605 2606 /// A set of rules for element and pseudo-elements. 2607 #[derive(Clone, Debug, Default, MallocSizeOf)] 2608 struct GenericElementAndPseudoRules<Map> { 2609 /// Rules from stylesheets at this `CascadeData`'s origin. 2610 element_map: Map, 2611 2612 /// Rules from stylesheets at this `CascadeData`'s origin that correspond 2613 /// to a given pseudo-element. 2614 /// 2615 /// FIXME(emilio): There are a bunch of wasted entries here in practice. 2616 /// Figure out a good way to do a `PerNonAnonBox` and `PerAnonBox` (for 2617 /// `precomputed_values_for_pseudo`) without duplicating a lot of code. 2618 pseudos_map: PerPseudoElementMap<Self>, 2619 } 2620 2621 impl<Map: Default + MallocSizeOf> GenericElementAndPseudoRules<Map> { 2622 #[inline(always)] 2623 fn for_insertion<'a>(&mut self, pseudo_elements: &[&'a PseudoElement]) -> &mut Map { 2624 let mut current = self; 2625 for &pseudo_element in pseudo_elements { 2626 debug_assert!( 2627 !pseudo_element.is_precomputed() 2628 && !pseudo_element.is_unknown_webkit_pseudo_element(), 2629 "Precomputed pseudos should end up in precomputed_pseudo_element_decls, \ 2630 and unknown webkit pseudos should be discarded before getting here" 2631 ); 2632 2633 current = current 2634 .pseudos_map 2635 .get_or_insert_with(pseudo_element, Default::default); 2636 } 2637 2638 &mut current.element_map 2639 } 2640 2641 #[inline] 2642 fn rules(&self, pseudo_elements: &[PseudoElement]) -> Option<&Map> { 2643 let mut current = self; 2644 for pseudo in pseudo_elements { 2645 current = current.pseudos_map.get(&pseudo)?; 2646 } 2647 Some(¤t.element_map) 2648 } 2649 2650 /// Measures heap usage. 2651 #[cfg(feature = "gecko")] 2652 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 2653 sizes.mElementAndPseudosMaps += self.element_map.size_of(ops); 2654 2655 for elem in self.pseudos_map.iter() { 2656 sizes.mElementAndPseudosMaps += MallocSizeOf::size_of(elem, ops); 2657 } 2658 } 2659 } 2660 2661 type ElementAndPseudoRules = GenericElementAndPseudoRules<SelectorMap<Rule>>; 2662 type PartMap = PrecomputedHashMap<Atom, SmallVec<[Rule; 1]>>; 2663 type PartElementAndPseudoRules = GenericElementAndPseudoRules<PartMap>; 2664 2665 impl ElementAndPseudoRules { 2666 // TODO(emilio): Should we retain storage of these? 2667 fn clear(&mut self) { 2668 self.element_map.clear(); 2669 self.pseudos_map.clear(); 2670 } 2671 2672 fn shrink_if_needed(&mut self) { 2673 self.element_map.shrink_if_needed(); 2674 for pseudo in self.pseudos_map.iter_mut() { 2675 pseudo.shrink_if_needed(); 2676 } 2677 } 2678 } 2679 2680 impl PartElementAndPseudoRules { 2681 // TODO(emilio): Should we retain storage of these? 2682 fn clear(&mut self) { 2683 self.element_map.clear(); 2684 self.pseudos_map.clear(); 2685 } 2686 } 2687 2688 /// The id of a given layer, a sequentially-increasing identifier. 2689 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)] 2690 pub struct LayerId(u16); 2691 2692 impl LayerId { 2693 /// The id of the root layer. 2694 pub const fn root() -> Self { 2695 Self(0) 2696 } 2697 } 2698 2699 #[derive(Clone, Debug, MallocSizeOf)] 2700 struct CascadeLayer { 2701 id: LayerId, 2702 order: LayerOrder, 2703 children: Vec<LayerId>, 2704 } 2705 2706 impl CascadeLayer { 2707 const fn root() -> Self { 2708 Self { 2709 id: LayerId::root(), 2710 order: LayerOrder::root(), 2711 children: vec![], 2712 } 2713 } 2714 } 2715 2716 /// The id of a given container condition, a sequentially-increasing identifier 2717 /// for a given style set. 2718 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)] 2719 pub struct ContainerConditionId(u16); 2720 2721 impl ContainerConditionId { 2722 /// A special id that represents no container rule. 2723 pub const fn none() -> Self { 2724 Self(0) 2725 } 2726 } 2727 2728 #[derive(Clone, Debug, MallocSizeOf)] 2729 struct ContainerConditionReference { 2730 parent: ContainerConditionId, 2731 #[ignore_malloc_size_of = "Arc"] 2732 condition: Option<Arc<ContainerCondition>>, 2733 } 2734 2735 impl ContainerConditionReference { 2736 const fn none() -> Self { 2737 Self { 2738 parent: ContainerConditionId::none(), 2739 condition: None, 2740 } 2741 } 2742 } 2743 2744 /// The id of a given scope condition, a sequentially-increasing identifier 2745 /// for a given style set. 2746 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)] 2747 pub struct ScopeConditionId(u16); 2748 2749 impl ScopeConditionId { 2750 /// Construct a new scope condition id. 2751 pub fn new(id: u16) -> Self { 2752 Self(id) 2753 } 2754 2755 /// A special id that represents no scope rule. 2756 pub const fn none() -> Self { 2757 Self(0) 2758 } 2759 } 2760 2761 /// Data required to process this scope condition. 2762 #[derive(Clone, Debug, MallocSizeOf)] 2763 pub struct ScopeConditionReference { 2764 /// The ID of outer scope condition, `none()` otherwise. 2765 parent: ScopeConditionId, 2766 /// Start and end bounds of the scope. None implies sentinel data (i.e. Not a scope condition). 2767 condition: Option<ScopeBoundsWithHashes>, 2768 /// Implicit scope root of this scope condition, computed unconditionally, 2769 /// even if the start bound may be Some. 2770 #[ignore_malloc_size_of = "Raw ptr behind the scenes"] 2771 implicit_scope_root: StylistImplicitScopeRoot, 2772 /// Is the condition trivial? See `ScopeBoundsWithHashes::is_trivial`. 2773 is_trivial: bool, 2774 } 2775 2776 impl ScopeConditionReference { 2777 /// Create a new scope condition. 2778 pub fn new( 2779 parent: ScopeConditionId, 2780 condition: Option<ScopeBoundsWithHashes>, 2781 implicit_scope_root: ImplicitScopeRoot, 2782 is_trivial: bool, 2783 ) -> Self { 2784 Self { 2785 parent, 2786 condition, 2787 implicit_scope_root: StylistImplicitScopeRoot::Normal(implicit_scope_root), 2788 is_trivial, 2789 } 2790 } 2791 2792 /// Create a sentinel scope condition. 2793 pub const fn none() -> Self { 2794 Self { 2795 parent: ScopeConditionId::none(), 2796 condition: None, 2797 implicit_scope_root: StylistImplicitScopeRoot::default_const(), 2798 is_trivial: true, 2799 } 2800 } 2801 } 2802 2803 /// All potential sscope root candidates. 2804 pub struct ScopeRootCandidates { 2805 /// List of scope root candidates. 2806 pub candidates: Vec<ScopeRootCandidate>, 2807 /// Is the scope condition matching these candidates trivial? See `ScopeBoundsWithHashes::is_trivial`. 2808 pub is_trivial: bool, 2809 } 2810 2811 impl Default for ScopeRootCandidates { 2812 fn default() -> Self { 2813 Self { 2814 candidates: vec![], 2815 is_trivial: true, 2816 } 2817 } 2818 } 2819 2820 impl ScopeRootCandidates { 2821 fn empty(is_trivial: bool) -> Self { 2822 Self { 2823 candidates: vec![], 2824 is_trivial, 2825 } 2826 } 2827 } 2828 2829 /// Start and end bound of a scope, along with their selector hashes. 2830 #[derive(Clone, Debug, MallocSizeOf)] 2831 pub struct ScopeBoundWithHashes { 2832 // TODO(dshin): With replaced parent selectors, these may be unique... 2833 #[ignore_malloc_size_of = "Arc"] 2834 selectors: SelectorList<SelectorImpl>, 2835 hashes: SmallVec<[AncestorHashes; 1]>, 2836 } 2837 2838 impl ScopeBoundWithHashes { 2839 fn new(quirks_mode: QuirksMode, selectors: SelectorList<SelectorImpl>) -> Self { 2840 let mut hashes = SmallVec::with_capacity(selectors.len()); 2841 for selector in selectors.slice() { 2842 hashes.push(AncestorHashes::new(selector, quirks_mode)); 2843 } 2844 Self { selectors, hashes } 2845 } 2846 2847 fn new_no_hash(selectors: SelectorList<SelectorImpl>) -> Self { 2848 let hashes = selectors 2849 .slice() 2850 .iter() 2851 .map(|_| AncestorHashes { 2852 packed_hashes: [0, 0, 0], 2853 }) 2854 .collect(); 2855 Self { selectors, hashes } 2856 } 2857 } 2858 2859 /// Bounds for this scope, along with corresponding selector hashes. 2860 #[derive(Clone, Debug, MallocSizeOf)] 2861 pub struct ScopeBoundsWithHashes { 2862 /// Start of the scope bound. If None, implies implicit scope root. 2863 start: Option<ScopeBoundWithHashes>, 2864 /// Optional end of the scope bound. 2865 end: Option<ScopeBoundWithHashes>, 2866 } 2867 2868 impl ScopeBoundsWithHashes { 2869 /// Create a new scope bound, hashing selectors for fast rejection. 2870 fn new( 2871 quirks_mode: QuirksMode, 2872 start: Option<SelectorList<SelectorImpl>>, 2873 end: Option<SelectorList<SelectorImpl>>, 2874 ) -> Self { 2875 Self { 2876 start: start.map(|selectors| ScopeBoundWithHashes::new(quirks_mode, selectors)), 2877 end: end.map(|selectors| ScopeBoundWithHashes::new(quirks_mode, selectors)), 2878 } 2879 } 2880 2881 /// Create a new scope bound, but not hashing any selector. 2882 pub fn new_no_hash( 2883 start: Option<SelectorList<SelectorImpl>>, 2884 end: Option<SelectorList<SelectorImpl>>, 2885 ) -> Self { 2886 Self { 2887 start: start.map(|selectors| ScopeBoundWithHashes::new_no_hash(selectors)), 2888 end: end.map(|selectors| ScopeBoundWithHashes::new_no_hash(selectors)), 2889 } 2890 } 2891 2892 fn selectors_for<'a>( 2893 bound_with_hashes: Option<&'a ScopeBoundWithHashes>, 2894 ) -> impl Iterator<Item = &'a Selector<SelectorImpl>> { 2895 bound_with_hashes 2896 .map(|b| b.selectors.slice().iter()) 2897 .into_iter() 2898 .flatten() 2899 } 2900 2901 fn start_selectors<'a>(&'a self) -> impl Iterator<Item = &'a Selector<SelectorImpl>> { 2902 Self::selectors_for(self.start.as_ref()) 2903 } 2904 2905 fn end_selectors<'a>(&'a self) -> impl Iterator<Item = &'a Selector<SelectorImpl>> { 2906 Self::selectors_for(self.end.as_ref()) 2907 } 2908 2909 fn is_trivial(&self) -> bool { 2910 fn scope_bound_is_trivial(bound: &Option<ScopeBoundWithHashes>, default: bool) -> bool { 2911 bound.as_ref().map_or(default, |bound| { 2912 scope_selector_list_is_trivial(&bound.selectors) 2913 }) 2914 } 2915 2916 // Given an implicit scope, we are unable to tell if the cousins share the same implicit root. 2917 scope_bound_is_trivial(&self.start, false) && scope_bound_is_trivial(&self.end, true) 2918 } 2919 } 2920 2921 /// Find all scope conditions for a given condition ID, indexing into the given list of scope conditions. 2922 pub fn scope_root_candidates<E>( 2923 scope_conditions: &[ScopeConditionReference], 2924 id: ScopeConditionId, 2925 element: &E, 2926 override_matches_shadow_host_for_part: bool, 2927 scope_subject_map: &ScopeSubjectMap, 2928 context: &mut MatchingContext<SelectorImpl>, 2929 ) -> ScopeRootCandidates 2930 where 2931 E: TElement, 2932 { 2933 let condition_ref = &scope_conditions[id.0 as usize]; 2934 let bounds = match condition_ref.condition { 2935 None => return ScopeRootCandidates::default(), 2936 Some(ref c) => c, 2937 }; 2938 // Make sure the parent scopes ara evaluated first. This runs a bit counter to normal 2939 // selector matching where rightmost selectors match first. However, this avoids having 2940 // to traverse through descendants (i.e. Avoids tree traversal vs linear traversal). 2941 let outer_result = scope_root_candidates( 2942 scope_conditions, 2943 condition_ref.parent, 2944 element, 2945 override_matches_shadow_host_for_part, 2946 scope_subject_map, 2947 context, 2948 ); 2949 2950 let is_trivial = condition_ref.is_trivial && outer_result.is_trivial; 2951 let is_outermost_scope = condition_ref.parent == ScopeConditionId::none(); 2952 if !is_outermost_scope && outer_result.candidates.is_empty() { 2953 return ScopeRootCandidates::empty(is_trivial); 2954 } 2955 2956 let (root_target, matches_shadow_host) = if let Some(start) = bounds.start.as_ref() { 2957 if let Some(filter) = context.bloom_filter { 2958 // Use the bloom filter here. If our ancestors do not have the right hashes, 2959 // there's no point in traversing up. Besides, the filter is built for this depth, 2960 // so the filter contains more data than it should, the further we go up the ancestor 2961 // chain. It wouldn't generate wrong results, but makes the traversal even more pointless. 2962 if !start 2963 .hashes 2964 .iter() 2965 .any(|entry| selector_may_match(entry, filter)) 2966 { 2967 return ScopeRootCandidates::empty(is_trivial); 2968 } 2969 } 2970 ( 2971 ScopeTarget::Selector(&start.selectors), 2972 scope_start_matches_shadow_host(&start.selectors), 2973 ) 2974 } else { 2975 let implicit_root = condition_ref.implicit_scope_root; 2976 match implicit_root { 2977 StylistImplicitScopeRoot::Normal(r) => ( 2978 ScopeTarget::Implicit(r.element(context.current_host.clone())), 2979 r.matches_shadow_host(), 2980 ), 2981 StylistImplicitScopeRoot::Cached(index) => { 2982 let host = context 2983 .current_host 2984 .expect("Cached implicit scope for light DOM implicit scope"); 2985 match E::implicit_scope_for_sheet_in_shadow_root(host, index) { 2986 None => return ScopeRootCandidates::empty(is_trivial), 2987 Some(root) => ( 2988 ScopeTarget::Implicit(root.element(context.current_host.clone())), 2989 root.matches_shadow_host(), 2990 ), 2991 } 2992 }, 2993 } 2994 }; 2995 // For `::part`, we need to be able to reach the outer tree. Parts without the corresponding 2996 // `exportparts` attribute will be rejected at the selector matching time. 2997 let matches_shadow_host = override_matches_shadow_host_for_part || matches_shadow_host; 2998 2999 let potential_scope_roots = if is_outermost_scope { 3000 collect_scope_roots( 3001 *element, 3002 None, 3003 context, 3004 &root_target, 3005 matches_shadow_host, 3006 scope_subject_map, 3007 ) 3008 } else { 3009 let mut result = vec![]; 3010 for activation in outer_result.candidates { 3011 let mut this_result = collect_scope_roots( 3012 *element, 3013 Some(activation.root), 3014 context, 3015 &root_target, 3016 matches_shadow_host, 3017 scope_subject_map, 3018 ); 3019 result.append(&mut this_result); 3020 } 3021 result 3022 }; 3023 3024 if potential_scope_roots.is_empty() { 3025 return ScopeRootCandidates::empty(is_trivial); 3026 } 3027 3028 let candidates = if let Some(end) = bounds.end.as_ref() { 3029 let mut result = vec![]; 3030 // If any scope-end selector matches, we're not in scope. 3031 for scope_root in potential_scope_roots { 3032 if end 3033 .selectors 3034 .slice() 3035 .iter() 3036 .zip(end.hashes.iter()) 3037 .all(|(selector, hashes)| { 3038 // Like checking for scope-start, use the bloom filter here. 3039 if let Some(filter) = context.bloom_filter { 3040 if !selector_may_match(hashes, filter) { 3041 // Selector this hash belongs to won't cause us to be out of this scope. 3042 return true; 3043 } 3044 } 3045 3046 !element_is_outside_of_scope( 3047 selector, 3048 *element, 3049 scope_root.root, 3050 context, 3051 matches_shadow_host, 3052 ) 3053 }) 3054 { 3055 result.push(scope_root); 3056 } 3057 } 3058 result 3059 } else { 3060 potential_scope_roots 3061 }; 3062 3063 ScopeRootCandidates { 3064 candidates, 3065 is_trivial, 3066 } 3067 } 3068 3069 /// Implicit scope root, which may or may not be cached (i.e. For shadow DOM author 3070 /// styles that are cached and shared). 3071 #[derive(Copy, Clone, Debug, MallocSizeOf)] 3072 enum StylistImplicitScopeRoot { 3073 Normal(ImplicitScopeRoot), 3074 Cached(usize), 3075 } 3076 // Should be safe, only mutated through mutable methods in `Stylist`. 3077 unsafe impl Sync for StylistImplicitScopeRoot {} 3078 3079 impl StylistImplicitScopeRoot { 3080 const fn default_const() -> Self { 3081 // Use the "safest" fallback. 3082 Self::Normal(ImplicitScopeRoot::DocumentElement) 3083 } 3084 } 3085 3086 impl Default for StylistImplicitScopeRoot { 3087 fn default() -> Self { 3088 Self::default_const() 3089 } 3090 } 3091 3092 /// Data resulting from performing the CSS cascade that is specific to a given 3093 /// origin. 3094 /// 3095 /// FIXME(emilio): Consider renaming and splitting in `CascadeData` and 3096 /// `InvalidationData`? That'd make `clear_cascade_data()` clearer. 3097 #[derive(Debug, Clone, MallocSizeOf)] 3098 pub struct CascadeData { 3099 /// The data coming from normal style rules that apply to elements at this 3100 /// cascade level. 3101 normal_rules: ElementAndPseudoRules, 3102 3103 /// The `:host` pseudo rules that are the rightmost selector (without 3104 /// accounting for pseudo-elements), or `:scope` rules that may match 3105 /// the featureless host. 3106 featureless_host_rules: Option<Box<ElementAndPseudoRules>>, 3107 3108 /// The data coming from ::slotted() pseudo-element rules. 3109 /// 3110 /// We need to store them separately because an element needs to match 3111 /// ::slotted() pseudo-element rules in different shadow roots. 3112 /// 3113 /// In particular, we need to go through all the style data in all the 3114 /// containing style scopes starting from the closest assigned slot. 3115 slotted_rules: Option<Box<ElementAndPseudoRules>>, 3116 3117 /// The data coming from ::part() pseudo-element rules. 3118 /// 3119 /// We need to store them separately because an element needs to match 3120 /// ::part() pseudo-element rules in different shadow roots. 3121 part_rules: Option<Box<PartElementAndPseudoRules>>, 3122 3123 /// The invalidation map for these rules. 3124 invalidation_map: InvalidationMap, 3125 3126 /// The relative selector equivalent of the invalidation map. 3127 relative_selector_invalidation_map: InvalidationMap, 3128 3129 additional_relative_selector_invalidation_map: AdditionalRelativeSelectorInvalidationMap, 3130 3131 /// The attribute local names that appear in attribute selectors. Used 3132 /// to avoid taking element snapshots when an irrelevant attribute changes. 3133 /// (We don't bother storing the namespace, since namespaced attributes are 3134 /// rare.) 3135 attribute_dependencies: PrecomputedHashSet<LocalName>, 3136 3137 /// The classes that appear in the selector list of 3138 /// :nth-child(... of <selector list>). Used to avoid restyling siblings of 3139 /// an element when an irrelevant class changes. 3140 nth_of_class_dependencies: PrecomputedHashSet<Atom>, 3141 3142 /// The attributes that appear in the selector list of 3143 /// :nth-child(... of <selector list>). Used to avoid restyling siblings of 3144 /// an element when an irrelevant attribute changes. 3145 nth_of_attribute_dependencies: PrecomputedHashSet<LocalName>, 3146 3147 /// The custom states that appear in the selector list of 3148 /// :nth-child(... of <selector list>). Used to avoid restyling siblings of 3149 /// an element when an irrelevant custom state changes. 3150 nth_of_custom_state_dependencies: PrecomputedHashSet<AtomIdent>, 3151 3152 /// The element state bits that are relied on by selectors. Like 3153 /// `attribute_dependencies`, this is used to avoid taking element snapshots 3154 /// when an irrelevant element state bit changes. 3155 state_dependencies: ElementState, 3156 3157 /// The element state bits that are relied on by selectors that appear in 3158 /// the selector list of :nth-child(... of <selector list>). 3159 nth_of_state_dependencies: ElementState, 3160 3161 /// The document state bits that are relied on by selectors. This is used 3162 /// to tell whether we need to restyle the entire document when a document 3163 /// state bit changes. 3164 document_state_dependencies: DocumentState, 3165 3166 /// The ids that appear in the rightmost complex selector of selectors (and 3167 /// hence in our selector maps). Used to determine when sharing styles is 3168 /// safe: we disallow style sharing for elements whose id matches this 3169 /// filter, and hence might be in one of our selector maps. 3170 mapped_ids: PrecomputedHashSet<Atom>, 3171 3172 /// The IDs that appear in the selector list of 3173 /// :nth-child(... of <selector list>). Used to avoid restyling siblings 3174 /// of an element when an irrelevant ID changes. 3175 nth_of_mapped_ids: PrecomputedHashSet<Atom>, 3176 3177 /// Selectors that require explicit cache revalidation (i.e. which depend 3178 /// on state that is not otherwise visible to the cache, like attributes or 3179 /// tree-structural state like child index and pseudos). 3180 #[ignore_malloc_size_of = "Arc"] 3181 selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>, 3182 3183 /// A map with all the animations at this `CascadeData`'s origin, indexed 3184 /// by name. 3185 animations: LayerOrderedMap<KeyframesAnimation>, 3186 3187 /// A map with all the layer-ordered registrations from style at this `CascadeData`'s origin, 3188 /// indexed by name. 3189 #[ignore_malloc_size_of = "Arc"] 3190 custom_property_registrations: LayerOrderedMap<Arc<PropertyRegistration>>, 3191 3192 /// Custom media query registrations. 3193 custom_media: CustomMediaMap, 3194 3195 /// A map from cascade layer name to layer order. 3196 layer_id: FxHashMap<LayerName, LayerId>, 3197 3198 /// The list of cascade layers, indexed by their layer id. 3199 layers: SmallVec<[CascadeLayer; 1]>, 3200 3201 /// The list of container conditions, indexed by their id. 3202 container_conditions: SmallVec<[ContainerConditionReference; 1]>, 3203 3204 /// The list of scope conditions, indexed by their id. 3205 scope_conditions: SmallVec<[ScopeConditionReference; 1]>, 3206 3207 /// Map of unique selectors on scope start selectors' subjects. 3208 scope_subject_map: ScopeSubjectMap, 3209 3210 /// Effective media query results cached from the last rebuild. 3211 effective_media_query_results: EffectiveMediaQueryResults, 3212 3213 /// Extra data, like different kinds of rules, etc. 3214 extra_data: ExtraStyleData, 3215 3216 /// A monotonically increasing counter to represent the order on which a 3217 /// style rule appears in a stylesheet, needed to sort them by source order. 3218 rules_source_order: u32, 3219 3220 /// The total number of selectors. 3221 num_selectors: usize, 3222 3223 /// The total number of declarations. 3224 num_declarations: usize, 3225 } 3226 3227 static IMPLICIT_SCOPE: LazyLock<SelectorList<SelectorImpl>> = LazyLock::new(|| { 3228 // Implicit scope, as per https://github.com/w3c/csswg-drafts/issues/10196 3229 // Also, `&` is `:where(:scope)`, as per https://github.com/w3c/csswg-drafts/issues/9740 3230 // ``:where(:scope)` effectively behaves the same as the implicit scope. 3231 let list = SelectorList::implicit_scope(); 3232 list.mark_as_intentionally_leaked(); 3233 list 3234 }); 3235 3236 fn scope_start_matches_shadow_host(start: &SelectorList<SelectorImpl>) -> bool { 3237 // TODO(emilio): Should we carry a MatchesFeaturelessHost rather than a bool around? 3238 // Pre-existing behavior with multiple selectors matches this tho. 3239 start 3240 .slice() 3241 .iter() 3242 .any(|s| s.matches_featureless_host(true).may_match()) 3243 } 3244 3245 /// Replace any occurrence of parent selector in the given selector with a implicit scope selector. 3246 pub fn replace_parent_selector_with_implicit_scope( 3247 selectors: &SelectorList<SelectorImpl>, 3248 ) -> SelectorList<SelectorImpl> { 3249 selectors.replace_parent_selector(&IMPLICIT_SCOPE) 3250 } 3251 3252 impl CascadeData { 3253 /// Creates an empty `CascadeData`. 3254 pub fn new() -> Self { 3255 Self { 3256 normal_rules: ElementAndPseudoRules::default(), 3257 featureless_host_rules: None, 3258 slotted_rules: None, 3259 part_rules: None, 3260 invalidation_map: InvalidationMap::new(), 3261 relative_selector_invalidation_map: InvalidationMap::new(), 3262 additional_relative_selector_invalidation_map: 3263 AdditionalRelativeSelectorInvalidationMap::new(), 3264 nth_of_mapped_ids: PrecomputedHashSet::default(), 3265 nth_of_class_dependencies: PrecomputedHashSet::default(), 3266 nth_of_attribute_dependencies: PrecomputedHashSet::default(), 3267 nth_of_custom_state_dependencies: PrecomputedHashSet::default(), 3268 nth_of_state_dependencies: ElementState::empty(), 3269 attribute_dependencies: PrecomputedHashSet::default(), 3270 state_dependencies: ElementState::empty(), 3271 document_state_dependencies: DocumentState::empty(), 3272 mapped_ids: PrecomputedHashSet::default(), 3273 selectors_for_cache_revalidation: SelectorMap::new(), 3274 animations: Default::default(), 3275 custom_property_registrations: Default::default(), 3276 custom_media: Default::default(), 3277 layer_id: Default::default(), 3278 layers: smallvec::smallvec![CascadeLayer::root()], 3279 container_conditions: smallvec::smallvec![ContainerConditionReference::none()], 3280 scope_conditions: smallvec::smallvec![ScopeConditionReference::none()], 3281 scope_subject_map: Default::default(), 3282 extra_data: ExtraStyleData::default(), 3283 effective_media_query_results: EffectiveMediaQueryResults::new(), 3284 rules_source_order: 0, 3285 num_selectors: 0, 3286 num_declarations: 0, 3287 } 3288 } 3289 3290 /// Rebuild the cascade data from a given SheetCollection, incrementally if possible. 3291 pub fn rebuild<'a, S>( 3292 &mut self, 3293 device: &Device, 3294 quirks_mode: QuirksMode, 3295 collection: SheetCollectionFlusher<S>, 3296 guard: &SharedRwLockReadGuard, 3297 difference: &mut CascadeDataDifference, 3298 ) -> Result<(), AllocErr> 3299 where 3300 S: StylesheetInDocument + PartialEq + 'static, 3301 { 3302 if !collection.dirty() { 3303 return Ok(()); 3304 } 3305 3306 let validity = collection.data_validity(); 3307 3308 let mut old_position_try_data = LayerOrderedMap::default(); 3309 if validity != DataValidity::Valid { 3310 old_position_try_data = std::mem::take(&mut self.extra_data.position_try_rules); 3311 self.clear_cascade_data(); 3312 if validity == DataValidity::FullyInvalid { 3313 self.clear_invalidation_data(); 3314 } 3315 } 3316 3317 let mut result = Ok(()); 3318 3319 collection.each(|index, stylesheet, rebuild_kind| { 3320 result = self.add_stylesheet( 3321 device, 3322 quirks_mode, 3323 stylesheet, 3324 index, 3325 guard, 3326 rebuild_kind, 3327 /* precomputed_pseudo_element_decls = */ None, 3328 if validity == DataValidity::Valid { 3329 Some(difference) 3330 } else { 3331 None 3332 }, 3333 ); 3334 result.is_ok() 3335 }); 3336 3337 self.did_finish_rebuild(); 3338 3339 // For DataValidity::Valid, we pass the difference down to `add_stylesheet` so that we 3340 // populate it with new data. Otherwise we need to diff with the old data. 3341 if validity != DataValidity::Valid { 3342 difference.update(&old_position_try_data, &self.extra_data.position_try_rules); 3343 } 3344 3345 result 3346 } 3347 3348 /// Returns the custom media query map. 3349 pub fn custom_media_map(&self) -> &CustomMediaMap { 3350 &self.custom_media 3351 } 3352 3353 /// Returns the invalidation map. 3354 pub fn invalidation_map(&self) -> &InvalidationMap { 3355 &self.invalidation_map 3356 } 3357 3358 /// Returns the relative selector invalidation map. 3359 pub fn relative_selector_invalidation_map(&self) -> &InvalidationMap { 3360 &self.relative_selector_invalidation_map 3361 } 3362 3363 /// Returns the relative selector invalidation map data. 3364 pub fn relative_invalidation_map_attributes( 3365 &self, 3366 ) -> &AdditionalRelativeSelectorInvalidationMap { 3367 &self.additional_relative_selector_invalidation_map 3368 } 3369 3370 /// Returns whether the given ElementState bit is relied upon by a selector 3371 /// of some rule. 3372 #[inline] 3373 pub fn has_state_dependency(&self, state: ElementState) -> bool { 3374 self.state_dependencies.intersects(state) 3375 } 3376 3377 /// Returns whether the given Custom State is relied upon by a selector 3378 /// of some rule in the selector list of :nth-child(... of <selector list>). 3379 #[inline] 3380 pub fn has_nth_of_custom_state_dependency(&self, state: &AtomIdent) -> bool { 3381 self.nth_of_custom_state_dependencies.contains(state) 3382 } 3383 3384 /// Returns whether the given ElementState bit is relied upon by a selector 3385 /// of some rule in the selector list of :nth-child(... of <selector list>). 3386 #[inline] 3387 pub fn has_nth_of_state_dependency(&self, state: ElementState) -> bool { 3388 self.nth_of_state_dependencies.intersects(state) 3389 } 3390 3391 /// Returns whether the given attribute might appear in an attribute 3392 /// selector of some rule. 3393 #[inline] 3394 pub fn might_have_attribute_dependency(&self, local_name: &LocalName) -> bool { 3395 self.attribute_dependencies.contains(local_name) 3396 } 3397 3398 /// Returns whether the given ID might appear in an ID selector in the 3399 /// selector list of :nth-child(... of <selector list>). 3400 #[inline] 3401 pub fn might_have_nth_of_id_dependency(&self, id: &Atom) -> bool { 3402 self.nth_of_mapped_ids.contains(id) 3403 } 3404 3405 /// Returns whether the given class might appear in a class selector in the 3406 /// selector list of :nth-child(... of <selector list>). 3407 #[inline] 3408 pub fn might_have_nth_of_class_dependency(&self, class: &Atom) -> bool { 3409 self.nth_of_class_dependencies.contains(class) 3410 } 3411 3412 /// Returns whether the given attribute might appear in an attribute 3413 /// selector in the selector list of :nth-child(... of <selector list>). 3414 #[inline] 3415 pub fn might_have_nth_of_attribute_dependency(&self, local_name: &LocalName) -> bool { 3416 self.nth_of_attribute_dependencies.contains(local_name) 3417 } 3418 3419 /// Returns the normal rule map for a given pseudo-element. 3420 #[inline] 3421 pub fn normal_rules(&self, pseudo_elements: &[PseudoElement]) -> Option<&SelectorMap<Rule>> { 3422 self.normal_rules.rules(pseudo_elements) 3423 } 3424 3425 /// Returns the featureless pseudo rule map for a given pseudo-element. 3426 #[inline] 3427 pub fn featureless_host_rules( 3428 &self, 3429 pseudo_elements: &[PseudoElement], 3430 ) -> Option<&SelectorMap<Rule>> { 3431 self.featureless_host_rules 3432 .as_ref() 3433 .and_then(|d| d.rules(pseudo_elements)) 3434 } 3435 3436 /// Whether there's any featureless rule that could match in this scope. 3437 pub fn any_featureless_host_rules(&self) -> bool { 3438 self.featureless_host_rules.is_some() 3439 } 3440 3441 /// Returns the slotted rule map for a given pseudo-element. 3442 #[inline] 3443 pub fn slotted_rules(&self, pseudo_elements: &[PseudoElement]) -> Option<&SelectorMap<Rule>> { 3444 self.slotted_rules 3445 .as_ref() 3446 .and_then(|d| d.rules(pseudo_elements)) 3447 } 3448 3449 /// Whether there's any ::slotted rule that could match in this scope. 3450 pub fn any_slotted_rule(&self) -> bool { 3451 self.slotted_rules.is_some() 3452 } 3453 3454 /// Returns the parts rule map for a given pseudo-element. 3455 #[inline] 3456 pub fn part_rules(&self, pseudo_elements: &[PseudoElement]) -> Option<&PartMap> { 3457 self.part_rules 3458 .as_ref() 3459 .and_then(|d| d.rules(pseudo_elements)) 3460 } 3461 3462 /// Whether there's any ::part rule that could match in this scope. 3463 pub fn any_part_rule(&self) -> bool { 3464 self.part_rules.is_some() 3465 } 3466 3467 #[inline] 3468 fn layer_order_for(&self, id: LayerId) -> LayerOrder { 3469 self.layers[id.0 as usize].order 3470 } 3471 3472 pub(crate) fn container_condition_matches<E>( 3473 &self, 3474 mut id: ContainerConditionId, 3475 stylist: &Stylist, 3476 element: E, 3477 context: &mut MatchingContext<E::Impl>, 3478 ) -> bool 3479 where 3480 E: TElement, 3481 { 3482 loop { 3483 let condition_ref = &self.container_conditions[id.0 as usize]; 3484 let condition = match condition_ref.condition { 3485 None => return true, 3486 Some(ref c) => c, 3487 }; 3488 let matches = condition 3489 .matches( 3490 stylist, 3491 element, 3492 context.extra_data.originating_element_style, 3493 &mut context.extra_data.cascade_input_flags, 3494 ) 3495 .to_bool(/* unknown = */ false); 3496 if !matches { 3497 return false; 3498 } 3499 id = condition_ref.parent; 3500 } 3501 } 3502 3503 pub(crate) fn find_scope_proximity_if_matching<E: TElement>( 3504 &self, 3505 rule: &Rule, 3506 element: E, 3507 context: &mut MatchingContext<E::Impl>, 3508 ) -> ScopeProximity { 3509 context 3510 .extra_data 3511 .cascade_input_flags 3512 .insert(ComputedValueFlags::CONSIDERED_NONTRIVIAL_SCOPED_STYLE); 3513 3514 // Whether the scope root matches a shadow host mostly olny depends on scope-intrinsic 3515 // parameters (i.e. bounds/implicit scope) - except for the use of `::parts`, where 3516 // matching crosses the shadow boundary. 3517 let result = scope_root_candidates( 3518 &self.scope_conditions, 3519 rule.scope_condition_id, 3520 &element, 3521 rule.selector.is_part(), 3522 &self.scope_subject_map, 3523 context, 3524 ); 3525 for candidate in result.candidates { 3526 if context.nest_for_scope(Some(candidate.root), |context| { 3527 matches_selector(&rule.selector, 0, Some(&rule.hashes), &element, context) 3528 }) { 3529 return candidate.proximity; 3530 } 3531 } 3532 ScopeProximity::infinity() 3533 } 3534 3535 fn did_finish_rebuild(&mut self) { 3536 self.shrink_maps_if_needed(); 3537 self.compute_layer_order(); 3538 } 3539 3540 fn shrink_maps_if_needed(&mut self) { 3541 self.normal_rules.shrink_if_needed(); 3542 if let Some(ref mut host_rules) = self.featureless_host_rules { 3543 host_rules.shrink_if_needed(); 3544 } 3545 if let Some(ref mut slotted_rules) = self.slotted_rules { 3546 slotted_rules.shrink_if_needed(); 3547 } 3548 self.animations.shrink_if_needed(); 3549 self.custom_property_registrations.shrink_if_needed(); 3550 self.invalidation_map.shrink_if_needed(); 3551 self.relative_selector_invalidation_map.shrink_if_needed(); 3552 self.additional_relative_selector_invalidation_map 3553 .shrink_if_needed(); 3554 self.attribute_dependencies.shrink_if_needed(); 3555 self.nth_of_attribute_dependencies.shrink_if_needed(); 3556 self.nth_of_custom_state_dependencies.shrink_if_needed(); 3557 self.nth_of_class_dependencies.shrink_if_needed(); 3558 self.nth_of_mapped_ids.shrink_if_needed(); 3559 self.mapped_ids.shrink_if_needed(); 3560 self.layer_id.shrink_if_needed(); 3561 self.selectors_for_cache_revalidation.shrink_if_needed(); 3562 self.scope_subject_map.shrink_if_needed(); 3563 } 3564 3565 fn compute_layer_order(&mut self) { 3566 debug_assert_ne!( 3567 self.layers.len(), 3568 0, 3569 "There should be at least the root layer!" 3570 ); 3571 if self.layers.len() == 1 { 3572 return; // Nothing to do 3573 } 3574 let (first, remaining) = self.layers.split_at_mut(1); 3575 let root = &mut first[0]; 3576 let mut order = LayerOrder::first(); 3577 compute_layer_order_for_subtree(root, remaining, &mut order); 3578 3579 // NOTE(emilio): This is a bit trickier than it should to avoid having 3580 // to clone() around layer indices. 3581 fn compute_layer_order_for_subtree( 3582 parent: &mut CascadeLayer, 3583 remaining_layers: &mut [CascadeLayer], 3584 order: &mut LayerOrder, 3585 ) { 3586 for child in parent.children.iter() { 3587 debug_assert!( 3588 parent.id < *child, 3589 "Children are always registered after parents" 3590 ); 3591 let child_index = (child.0 - parent.id.0 - 1) as usize; 3592 let (first, remaining) = remaining_layers.split_at_mut(child_index + 1); 3593 let child = &mut first[child_index]; 3594 compute_layer_order_for_subtree(child, remaining, order); 3595 } 3596 3597 if parent.id != LayerId::root() { 3598 parent.order = *order; 3599 order.inc(); 3600 } 3601 } 3602 #[cfg(feature = "gecko")] 3603 self.extra_data.sort_by_layer(&self.layers); 3604 self.animations 3605 .sort_with(&self.layers, compare_keyframes_in_same_layer); 3606 self.custom_property_registrations.sort(&self.layers) 3607 } 3608 3609 /// Collects all the applicable media query results into `results`. 3610 /// 3611 /// This duplicates part of the logic in `add_stylesheet`, which is 3612 /// a bit unfortunate. 3613 /// 3614 /// FIXME(emilio): With a bit of smartness in 3615 /// `media_feature_affected_matches`, we could convert 3616 /// `EffectiveMediaQueryResults` into a vector without too much effort. 3617 fn collect_applicable_media_query_results_into<S>( 3618 device: &Device, 3619 stylesheet: &S, 3620 guard: &SharedRwLockReadGuard, 3621 results: &mut Vec<MediaListKey>, 3622 contents_list: &mut StyleSheetContentList, 3623 custom_media_map: &mut CustomMediaMap, 3624 ) where 3625 S: StylesheetInDocument + 'static, 3626 { 3627 if !stylesheet.enabled() { 3628 return; 3629 } 3630 if !stylesheet.is_effective_for_device(device, &custom_media_map, guard) { 3631 return; 3632 } 3633 3634 debug!(" + {:?}", stylesheet); 3635 let contents = stylesheet.contents(guard); 3636 results.push(contents.to_media_list_key()); 3637 3638 // Safety: StyleSheetContents are reference-counted with Arc. 3639 contents_list.push(StylesheetContentsPtr(unsafe { 3640 Arc::from_raw_addrefed(&*contents) 3641 })); 3642 3643 let mut iter = stylesheet 3644 .contents(guard) 3645 .effective_rules(device, custom_media_map, guard); 3646 while let Some(rule) = iter.next() { 3647 match *rule { 3648 CssRule::CustomMedia(ref custom_media) => { 3649 iter.custom_media() 3650 .insert(custom_media.name.0.clone(), custom_media.condition.clone()); 3651 }, 3652 CssRule::Import(ref lock) => { 3653 let import_rule = lock.read_with(guard); 3654 debug!(" + {:?}", import_rule.stylesheet.media(guard)); 3655 results.push(import_rule.to_media_list_key()); 3656 }, 3657 CssRule::Media(ref media_rule) => { 3658 debug!(" + {:?}", media_rule.media_queries.read_with(guard)); 3659 results.push(media_rule.to_media_list_key()); 3660 }, 3661 _ => {}, 3662 } 3663 } 3664 } 3665 3666 fn add_styles( 3667 &mut self, 3668 selectors: &SelectorList<SelectorImpl>, 3669 declarations: &Arc<Locked<PropertyDeclarationBlock>>, 3670 ancestor_selectors: Option<&SelectorList<SelectorImpl>>, 3671 containing_rule_state: &ContainingRuleState, 3672 mut replaced_selectors: Option<&mut ReplacedSelectors>, 3673 guard: &SharedRwLockReadGuard, 3674 rebuild_kind: SheetRebuildKind, 3675 mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>, 3676 quirks_mode: QuirksMode, 3677 mut collected_scope_dependencies: Option<&mut Vec<Dependency>>, 3678 ) -> Result<(), AllocErr> { 3679 self.num_declarations += declarations.read_with(guard).len(); 3680 for selector in selectors.slice() { 3681 self.num_selectors += 1; 3682 3683 let pseudo_elements = selector.pseudo_elements(); 3684 let inner_pseudo_element = pseudo_elements.get(0); 3685 if let Some(pseudo) = inner_pseudo_element { 3686 if pseudo.is_precomputed() { 3687 debug_assert!(selector.is_universal()); 3688 debug_assert!(ancestor_selectors.is_none()); 3689 debug_assert_eq!(containing_rule_state.layer_id, LayerId::root()); 3690 // Because we precompute pseudos, we cannot possibly calculate scope proximity. 3691 debug_assert!(!containing_rule_state.scope_is_effective()); 3692 precomputed_pseudo_element_decls 3693 .as_mut() 3694 .expect("Expected precomputed declarations for the UA level") 3695 .get_or_insert_with(pseudo, Vec::new) 3696 .push(ApplicableDeclarationBlock::new( 3697 StyleSource::from_declarations(declarations.clone()), 3698 self.rules_source_order, 3699 CascadeLevel::UANormal, 3700 selector.specificity(), 3701 LayerOrder::root(), 3702 ScopeProximity::infinity(), 3703 )); 3704 continue; 3705 } 3706 if pseudo_elements 3707 .iter() 3708 .any(|p| p.is_unknown_webkit_pseudo_element()) 3709 { 3710 continue; 3711 } 3712 } 3713 3714 debug_assert!(!pseudo_elements 3715 .iter() 3716 .any(|p| p.is_precomputed() || p.is_unknown_webkit_pseudo_element())); 3717 3718 let selector = match ancestor_selectors { 3719 Some(ref s) => selector.replace_parent_selector(&s), 3720 None => selector.clone(), 3721 }; 3722 3723 let hashes = AncestorHashes::new(&selector, quirks_mode); 3724 3725 let rule = Rule::new( 3726 selector, 3727 hashes, 3728 StyleSource::from_declarations(declarations.clone()), 3729 self.rules_source_order, 3730 containing_rule_state.layer_id, 3731 containing_rule_state.container_condition_id, 3732 containing_rule_state.in_starting_style, 3733 containing_rule_state.containing_scope_rule_state.id, 3734 ); 3735 3736 if let Some(ref mut replaced_selectors) = replaced_selectors { 3737 replaced_selectors.push(rule.selector.clone()) 3738 } 3739 3740 if rebuild_kind.should_rebuild_invalidation() { 3741 let mut scope_dependencies = note_selector_for_invalidation( 3742 &rule.selector, 3743 quirks_mode, 3744 &mut self.invalidation_map, 3745 &mut self.relative_selector_invalidation_map, 3746 &mut self.additional_relative_selector_invalidation_map, 3747 None, 3748 None, 3749 )?; 3750 let mut needs_revalidation = false; 3751 let mut visitor = StylistSelectorVisitor { 3752 needs_revalidation: &mut needs_revalidation, 3753 passed_rightmost_selector: false, 3754 in_selector_list_of: SelectorListKind::default(), 3755 mapped_ids: &mut self.mapped_ids, 3756 nth_of_mapped_ids: &mut self.nth_of_mapped_ids, 3757 attribute_dependencies: &mut self.attribute_dependencies, 3758 nth_of_class_dependencies: &mut self.nth_of_class_dependencies, 3759 nth_of_attribute_dependencies: &mut self.nth_of_attribute_dependencies, 3760 nth_of_custom_state_dependencies: &mut self.nth_of_custom_state_dependencies, 3761 state_dependencies: &mut self.state_dependencies, 3762 nth_of_state_dependencies: &mut self.nth_of_state_dependencies, 3763 document_state_dependencies: &mut self.document_state_dependencies, 3764 }; 3765 rule.selector.visit(&mut visitor); 3766 3767 if needs_revalidation { 3768 self.selectors_for_cache_revalidation.insert( 3769 RevalidationSelectorAndHashes::new( 3770 rule.selector.clone(), 3771 rule.hashes.clone(), 3772 ), 3773 quirks_mode, 3774 )?; 3775 } 3776 3777 match ( 3778 scope_dependencies.as_mut(), 3779 collected_scope_dependencies.as_mut(), 3780 ) { 3781 (Some(inner_scope_deps), Some(scope_deps)) => { 3782 scope_deps.append(inner_scope_deps) 3783 }, 3784 _ => {}, 3785 } 3786 } 3787 3788 // Part is special, since given it doesn't have any 3789 // selectors inside, it's not worth using a whole 3790 // SelectorMap for it. 3791 if let Some(parts) = rule.selector.parts() { 3792 // ::part() has all semantics, so we just need to 3793 // put any of them in the selector map. 3794 // 3795 // We choose the last one quite arbitrarily, 3796 // expecting it's slightly more likely to be more 3797 // specific. 3798 let map = self 3799 .part_rules 3800 .get_or_insert_with(|| Box::new(Default::default())) 3801 .for_insertion(&pseudo_elements); 3802 map.try_reserve(1)?; 3803 let vec = map.entry(parts.last().unwrap().clone().0).or_default(); 3804 vec.try_reserve(1)?; 3805 vec.push(rule); 3806 } else { 3807 let scope_matches_shadow_host = containing_rule_state 3808 .containing_scope_rule_state 3809 .matches_shadow_host 3810 == ScopeMatchesShadowHost::Yes; 3811 let matches_featureless_host_only = match rule 3812 .selector 3813 .matches_featureless_host(scope_matches_shadow_host) 3814 { 3815 MatchesFeaturelessHost::Only => true, 3816 MatchesFeaturelessHost::Yes => { 3817 // We need to insert this in featureless_host_rules but also normal_rules. 3818 self.featureless_host_rules 3819 .get_or_insert_with(|| Box::new(Default::default())) 3820 .for_insertion(&pseudo_elements) 3821 .insert(rule.clone(), quirks_mode)?; 3822 false 3823 }, 3824 MatchesFeaturelessHost::Never => false, 3825 }; 3826 3827 // NOTE(emilio): It's fine to look at :host and then at 3828 // ::slotted(..), since :host::slotted(..) could never 3829 // possibly match, as <slot> is not a valid shadow host. 3830 // :scope may match featureless shadow host if the scope 3831 // root is the shadow root. 3832 // See https://github.com/w3c/csswg-drafts/issues/9025 3833 let rules = if matches_featureless_host_only { 3834 self.featureless_host_rules 3835 .get_or_insert_with(|| Box::new(Default::default())) 3836 } else if rule.selector.is_slotted() { 3837 self.slotted_rules 3838 .get_or_insert_with(|| Box::new(Default::default())) 3839 } else { 3840 &mut self.normal_rules 3841 } 3842 .for_insertion(&pseudo_elements); 3843 rules.insert(rule, quirks_mode)?; 3844 } 3845 } 3846 self.rules_source_order += 1; 3847 Ok(()) 3848 } 3849 3850 fn add_rule_list<S>( 3851 &mut self, 3852 rules: std::slice::Iter<CssRule>, 3853 device: &Device, 3854 quirks_mode: QuirksMode, 3855 stylesheet: &S, 3856 sheet_index: usize, 3857 guard: &SharedRwLockReadGuard, 3858 rebuild_kind: SheetRebuildKind, 3859 containing_rule_state: &mut ContainingRuleState, 3860 mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>, 3861 mut difference: Option<&mut CascadeDataDifference>, 3862 ) -> Result<(), AllocErr> 3863 where 3864 S: StylesheetInDocument + 'static, 3865 { 3866 for rule in rules { 3867 // Handle leaf rules first, as those are by far the most common 3868 // ones, and are always effective, so we can skip some checks. 3869 let mut handled = true; 3870 let mut list_for_nested_rules = None; 3871 match *rule { 3872 CssRule::Style(ref locked) => { 3873 let style_rule = locked.read_with(guard); 3874 let has_nested_rules = style_rule.rules.is_some(); 3875 let mut replaced_selectors = ReplacedSelectors::new(); 3876 let ancestor_selectors = containing_rule_state.ancestor_selector_lists.last(); 3877 let collect_replaced_selectors = 3878 has_nested_rules && ancestor_selectors.is_some(); 3879 let mut inner_dependencies: Option<Vec<Dependency>> = containing_rule_state 3880 .scope_is_effective() 3881 .then(|| Vec::new()); 3882 self.add_styles( 3883 &style_rule.selectors, 3884 &style_rule.block, 3885 ancestor_selectors, 3886 containing_rule_state, 3887 if collect_replaced_selectors { 3888 Some(&mut replaced_selectors) 3889 } else { 3890 None 3891 }, 3892 guard, 3893 rebuild_kind, 3894 precomputed_pseudo_element_decls.as_deref_mut(), 3895 quirks_mode, 3896 inner_dependencies.as_mut(), 3897 )?; 3898 if let Some(mut scope_dependencies) = inner_dependencies { 3899 containing_rule_state 3900 .containing_scope_rule_state 3901 .inner_dependencies 3902 .append(&mut scope_dependencies); 3903 } 3904 if has_nested_rules { 3905 handled = false; 3906 list_for_nested_rules = Some(if collect_replaced_selectors { 3907 SelectorList::from_iter(replaced_selectors.drain(..)) 3908 } else { 3909 style_rule.selectors.clone() 3910 }); 3911 } 3912 }, 3913 CssRule::NestedDeclarations(ref rule) => { 3914 if let Some(ref ancestor_selectors) = 3915 containing_rule_state.ancestor_selector_lists.last() 3916 { 3917 let decls = &rule.read_with(guard).block; 3918 let selectors = match containing_rule_state.nested_declarations_context { 3919 NestedDeclarationsContext::Style => ancestor_selectors, 3920 NestedDeclarationsContext::Scope => &*IMPLICIT_SCOPE, 3921 }; 3922 let mut inner_dependencies: Option<Vec<Dependency>> = containing_rule_state 3923 .scope_is_effective() 3924 .then(|| Vec::new()); 3925 self.add_styles( 3926 selectors, 3927 decls, 3928 /* ancestor_selectors = */ None, 3929 containing_rule_state, 3930 /* replaced_selectors = */ None, 3931 guard, 3932 // We don't need to rebuild invalidation data, since our ancestor style 3933 // rule would've done this. 3934 SheetRebuildKind::CascadeOnly, 3935 precomputed_pseudo_element_decls.as_deref_mut(), 3936 quirks_mode, 3937 inner_dependencies.as_mut(), 3938 )?; 3939 if let Some(mut scope_dependencies) = inner_dependencies { 3940 containing_rule_state 3941 .containing_scope_rule_state 3942 .inner_dependencies 3943 .append(&mut scope_dependencies); 3944 } 3945 } 3946 }, 3947 CssRule::Keyframes(ref keyframes_rule) => { 3948 debug!("Found valid keyframes rule: {:?}", *keyframes_rule); 3949 let keyframes_rule = keyframes_rule.read_with(guard); 3950 let name = keyframes_rule.name.as_atom().clone(); 3951 let animation = KeyframesAnimation::from_keyframes( 3952 &keyframes_rule.keyframes, 3953 keyframes_rule.vendor_prefix.clone(), 3954 guard, 3955 ); 3956 self.animations.try_insert_with( 3957 name, 3958 animation, 3959 containing_rule_state.layer_id, 3960 compare_keyframes_in_same_layer, 3961 )?; 3962 }, 3963 CssRule::Property(ref registration) => { 3964 self.custom_property_registrations.try_insert( 3965 registration.name.0.clone(), 3966 Arc::clone(registration), 3967 containing_rule_state.layer_id, 3968 )?; 3969 }, 3970 CssRule::FontFace(ref rule) => { 3971 // NOTE(emilio): We don't care about container_condition_id 3972 // because: 3973 // 3974 // Global, name-defining at-rules such as @keyframes or 3975 // @font-face or @layer that are defined inside container 3976 // queries are not constrained by the container query 3977 // conditions. 3978 // 3979 // https://drafts.csswg.org/css-contain-3/#container-rule 3980 // (Same elsewhere) 3981 self.extra_data 3982 .add_font_face(rule, containing_rule_state.layer_id); 3983 }, 3984 CssRule::FontFeatureValues(ref rule) => { 3985 self.extra_data 3986 .add_font_feature_values(rule, containing_rule_state.layer_id); 3987 }, 3988 CssRule::FontPaletteValues(ref rule) => { 3989 self.extra_data 3990 .add_font_palette_values(rule, containing_rule_state.layer_id); 3991 }, 3992 CssRule::CounterStyle(ref rule) => { 3993 self.extra_data.add_counter_style( 3994 guard, 3995 rule, 3996 containing_rule_state.layer_id, 3997 )?; 3998 }, 3999 CssRule::PositionTry(ref rule) => { 4000 let name = rule.read_with(guard).name.0.clone(); 4001 if let Some(ref mut difference) = difference { 4002 difference.changed_position_try_names.insert(name.clone()); 4003 } 4004 self.extra_data.add_position_try( 4005 name, 4006 rule.clone(), 4007 containing_rule_state.layer_id, 4008 )?; 4009 }, 4010 CssRule::Page(ref rule) => { 4011 self.extra_data 4012 .add_page(guard, rule, containing_rule_state.layer_id)?; 4013 handled = false; 4014 }, 4015 _ => { 4016 handled = false; 4017 }, 4018 } 4019 4020 if handled { 4021 // Assert that there are no children, and that the rule is 4022 // effective. 4023 if cfg!(debug_assertions) { 4024 let mut effective = false; 4025 let children = EffectiveRulesIterator::<&CustomMediaMap>::children( 4026 rule, 4027 device, 4028 quirks_mode, 4029 &self.custom_media, 4030 guard, 4031 &mut effective, 4032 ); 4033 debug_assert!(children.is_none()); 4034 debug_assert!(effective); 4035 } 4036 continue; 4037 } 4038 4039 let mut effective = false; 4040 let children = EffectiveRulesIterator::<&CustomMediaMap>::children( 4041 rule, 4042 device, 4043 quirks_mode, 4044 &self.custom_media, 4045 guard, 4046 &mut effective, 4047 ); 4048 if !effective { 4049 continue; 4050 } 4051 4052 fn maybe_register_layer(data: &mut CascadeData, layer: &LayerName) -> LayerId { 4053 // TODO: Measure what's more common / expensive, if 4054 // layer.clone() or the double hash lookup in the insert 4055 // case. 4056 if let Some(id) = data.layer_id.get(layer) { 4057 return *id; 4058 } 4059 let id = LayerId(data.layers.len() as u16); 4060 4061 let parent_layer_id = if layer.layer_names().len() > 1 { 4062 let mut parent = layer.clone(); 4063 parent.0.pop(); 4064 4065 *data 4066 .layer_id 4067 .get_mut(&parent) 4068 .expect("Parent layers should be registered before child layers") 4069 } else { 4070 LayerId::root() 4071 }; 4072 4073 data.layers[parent_layer_id.0 as usize].children.push(id); 4074 data.layers.push(CascadeLayer { 4075 id, 4076 // NOTE(emilio): Order is evaluated after rebuild in 4077 // compute_layer_order. 4078 order: LayerOrder::first(), 4079 children: vec![], 4080 }); 4081 4082 data.layer_id.insert(layer.clone(), id); 4083 4084 id 4085 } 4086 4087 fn maybe_register_layers( 4088 data: &mut CascadeData, 4089 name: Option<&LayerName>, 4090 containing_rule_state: &mut ContainingRuleState, 4091 ) { 4092 let anon_name; 4093 let name = match name { 4094 Some(name) => name, 4095 None => { 4096 anon_name = LayerName::new_anonymous(); 4097 &anon_name 4098 }, 4099 }; 4100 for name in name.layer_names() { 4101 containing_rule_state.layer_name.0.push(name.clone()); 4102 containing_rule_state.layer_id = 4103 maybe_register_layer(data, &containing_rule_state.layer_name); 4104 } 4105 debug_assert_ne!(containing_rule_state.layer_id, LayerId::root()); 4106 } 4107 4108 let saved_containing_rule_state = containing_rule_state.save(); 4109 match *rule { 4110 CssRule::Import(ref lock) => { 4111 let import_rule = lock.read_with(guard); 4112 if rebuild_kind.should_rebuild_invalidation() { 4113 self.effective_media_query_results 4114 .saw_effective(import_rule); 4115 } 4116 match import_rule.layer { 4117 ImportLayer::Named(ref name) => { 4118 maybe_register_layers(self, Some(name), containing_rule_state) 4119 }, 4120 ImportLayer::Anonymous => { 4121 maybe_register_layers(self, None, containing_rule_state) 4122 }, 4123 ImportLayer::None => {}, 4124 } 4125 }, 4126 CssRule::Media(ref media_rule) => { 4127 if rebuild_kind.should_rebuild_invalidation() { 4128 self.effective_media_query_results 4129 .saw_effective(&**media_rule); 4130 } 4131 }, 4132 CssRule::LayerBlock(ref rule) => { 4133 maybe_register_layers(self, rule.name.as_ref(), containing_rule_state); 4134 }, 4135 CssRule::CustomMedia(ref custom_media) => { 4136 self.custom_media 4137 .insert(custom_media.name.0.clone(), custom_media.condition.clone()); 4138 }, 4139 CssRule::LayerStatement(ref rule) => { 4140 for name in &*rule.names { 4141 maybe_register_layers(self, Some(name), containing_rule_state); 4142 // Register each layer individually. 4143 containing_rule_state.restore(&saved_containing_rule_state); 4144 } 4145 }, 4146 CssRule::Style(..) => { 4147 containing_rule_state.nested_declarations_context = 4148 NestedDeclarationsContext::Style; 4149 if let Some(s) = list_for_nested_rules { 4150 containing_rule_state.ancestor_selector_lists.push(s); 4151 } 4152 }, 4153 CssRule::Container(ref rule) => { 4154 let id = ContainerConditionId(self.container_conditions.len() as u16); 4155 self.container_conditions.push(ContainerConditionReference { 4156 parent: containing_rule_state.container_condition_id, 4157 condition: Some(rule.condition.clone()), 4158 }); 4159 containing_rule_state.container_condition_id = id; 4160 }, 4161 CssRule::StartingStyle(..) => { 4162 containing_rule_state.in_starting_style = true; 4163 }, 4164 CssRule::Scope(ref rule) => { 4165 containing_rule_state.nested_declarations_context = 4166 NestedDeclarationsContext::Scope; 4167 let id = ScopeConditionId(self.scope_conditions.len() as u16); 4168 let mut matches_shadow_host = false; 4169 let implicit_scope_root = if let Some(start) = rule.bounds.start.as_ref() { 4170 matches_shadow_host = scope_start_matches_shadow_host(start); 4171 // Would be unused, but use the default as fallback. 4172 StylistImplicitScopeRoot::default() 4173 } else { 4174 // (Re)Moving stylesheets trigger a complete flush, so saving the implicit 4175 // root here should be safe. 4176 if let Some(root) = stylesheet.implicit_scope_root() { 4177 matches_shadow_host = root.matches_shadow_host(); 4178 match root { 4179 ImplicitScopeRoot::InLightTree(_) 4180 | ImplicitScopeRoot::Constructed 4181 | ImplicitScopeRoot::DocumentElement => { 4182 StylistImplicitScopeRoot::Normal(root) 4183 }, 4184 ImplicitScopeRoot::ShadowHost(_) 4185 | ImplicitScopeRoot::InShadowTree(_) => { 4186 // Style data can be shared between shadow trees, so we must 4187 // query the implicit root for that specific tree. 4188 // Shared stylesheet means shared sheet indices, so we can 4189 // use that to locate the implicit root. 4190 // Technically, this can also be applied to the light tree, 4191 // but that requires also knowing about what cascade level we're at. 4192 StylistImplicitScopeRoot::Cached(sheet_index) 4193 }, 4194 } 4195 } else { 4196 // Could not find implicit scope root, but use the default as fallback. 4197 StylistImplicitScopeRoot::default() 4198 } 4199 }; 4200 4201 let replaced = 4202 { 4203 let start = rule.bounds.start.as_ref().map(|selector| { 4204 match containing_rule_state.ancestor_selector_lists.last() { 4205 Some(s) => selector.replace_parent_selector(s), 4206 None => selector.clone(), 4207 } 4208 }); 4209 let implicit_scope_selector = &*IMPLICIT_SCOPE; 4210 let end = rule.bounds.end.as_ref().map(|selector| { 4211 selector.replace_parent_selector(implicit_scope_selector) 4212 }); 4213 containing_rule_state 4214 .ancestor_selector_lists 4215 .push(implicit_scope_selector.clone()); 4216 ScopeBoundsWithHashes::new(quirks_mode, start, end) 4217 }; 4218 4219 if let Some(selectors) = replaced.start.as_ref() { 4220 self.scope_subject_map 4221 .add_bound_start(&selectors.selectors, quirks_mode); 4222 } 4223 4224 let is_trivial = replaced.is_trivial(); 4225 self.scope_conditions.push(ScopeConditionReference { 4226 parent: containing_rule_state.containing_scope_rule_state.id, 4227 condition: Some(replaced), 4228 implicit_scope_root, 4229 is_trivial, 4230 }); 4231 4232 containing_rule_state 4233 .containing_scope_rule_state 4234 .matches_shadow_host 4235 .nest_for_scope(matches_shadow_host); 4236 containing_rule_state.containing_scope_rule_state.id = id; 4237 containing_rule_state 4238 .containing_scope_rule_state 4239 .inner_dependencies 4240 .reserve(children.iter().len()); 4241 }, 4242 // We don't care about any other rule. 4243 _ => {}, 4244 } 4245 4246 if let Some(children) = children { 4247 self.add_rule_list( 4248 children, 4249 device, 4250 quirks_mode, 4251 stylesheet, 4252 sheet_index, 4253 guard, 4254 rebuild_kind, 4255 containing_rule_state, 4256 precomputed_pseudo_element_decls.as_deref_mut(), 4257 difference.as_deref_mut(), 4258 )?; 4259 } 4260 4261 if let Some(scope_restore_data) = 4262 containing_rule_state.restore(&saved_containing_rule_state) 4263 { 4264 let (cur_scope_inner_dependencies, scope_idx) = scope_restore_data; 4265 let cur_scope = &self.scope_conditions[scope_idx.0 as usize]; 4266 if let Some(cond) = cur_scope.condition.as_ref() { 4267 let mut _unused = false; 4268 let visitor = StylistSelectorVisitor { 4269 needs_revalidation: &mut _unused, 4270 passed_rightmost_selector: true, 4271 in_selector_list_of: SelectorListKind::default(), 4272 mapped_ids: &mut self.mapped_ids, 4273 nth_of_mapped_ids: &mut self.nth_of_mapped_ids, 4274 attribute_dependencies: &mut self.attribute_dependencies, 4275 nth_of_class_dependencies: &mut self.nth_of_class_dependencies, 4276 nth_of_attribute_dependencies: &mut self.nth_of_attribute_dependencies, 4277 nth_of_custom_state_dependencies: &mut self 4278 .nth_of_custom_state_dependencies, 4279 state_dependencies: &mut self.state_dependencies, 4280 nth_of_state_dependencies: &mut self.nth_of_state_dependencies, 4281 document_state_dependencies: &mut self.document_state_dependencies, 4282 }; 4283 4284 let dependency_vector = build_scope_dependencies( 4285 quirks_mode, 4286 cur_scope_inner_dependencies, 4287 visitor, 4288 cond, 4289 &mut self.invalidation_map, 4290 &mut self.relative_selector_invalidation_map, 4291 &mut self.additional_relative_selector_invalidation_map, 4292 )?; 4293 4294 containing_rule_state 4295 .containing_scope_rule_state 4296 .inner_dependencies 4297 .extend(dependency_vector); 4298 } 4299 } 4300 } 4301 4302 Ok(()) 4303 } 4304 4305 // Returns Err(..) to signify OOM 4306 fn add_stylesheet<S>( 4307 &mut self, 4308 device: &Device, 4309 quirks_mode: QuirksMode, 4310 stylesheet: &S, 4311 sheet_index: usize, 4312 guard: &SharedRwLockReadGuard, 4313 rebuild_kind: SheetRebuildKind, 4314 mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>, 4315 mut difference: Option<&mut CascadeDataDifference>, 4316 ) -> Result<(), AllocErr> 4317 where 4318 S: StylesheetInDocument + 'static, 4319 { 4320 if !stylesheet.enabled() { 4321 return Ok(()); 4322 } 4323 4324 if !stylesheet.is_effective_for_device(device, &self.custom_media, guard) { 4325 return Ok(()); 4326 } 4327 4328 let contents = stylesheet.contents(guard); 4329 if rebuild_kind.should_rebuild_invalidation() { 4330 self.effective_media_query_results.saw_effective(&*contents); 4331 } 4332 4333 let mut state = ContainingRuleState::default(); 4334 self.add_rule_list( 4335 contents.rules(guard).iter(), 4336 device, 4337 quirks_mode, 4338 stylesheet, 4339 sheet_index, 4340 guard, 4341 rebuild_kind, 4342 &mut state, 4343 precomputed_pseudo_element_decls.as_deref_mut(), 4344 difference.as_deref_mut(), 4345 )?; 4346 4347 Ok(()) 4348 } 4349 4350 /// Returns whether all the media-feature affected values matched before and 4351 /// match now in the given stylesheet. 4352 pub fn media_feature_affected_matches<S>( 4353 &self, 4354 stylesheet: &S, 4355 guard: &SharedRwLockReadGuard, 4356 device: &Device, 4357 quirks_mode: QuirksMode, 4358 ) -> bool 4359 where 4360 S: StylesheetInDocument + 'static, 4361 { 4362 use crate::invalidation::media_queries::PotentiallyEffectiveMediaRules; 4363 4364 let effective_now = stylesheet.is_effective_for_device(device, &self.custom_media, guard); 4365 4366 let contents = stylesheet.contents(guard); 4367 let effective_then = self.effective_media_query_results.was_effective(contents); 4368 4369 if effective_now != effective_then { 4370 debug!( 4371 " > Stylesheet {:?} changed -> {}, {}", 4372 stylesheet.media(guard), 4373 effective_then, 4374 effective_now 4375 ); 4376 return false; 4377 } 4378 4379 if !effective_now { 4380 return true; 4381 } 4382 4383 // We don't need a custom media map for PotentiallyEffectiveMediaRules. 4384 let custom_media = CustomMediaMap::default(); 4385 let mut iter = 4386 contents.iter_rules::<PotentiallyEffectiveMediaRules, _>(device, &custom_media, guard); 4387 while let Some(rule) = iter.next() { 4388 match *rule { 4389 CssRule::Style(..) 4390 | CssRule::NestedDeclarations(..) 4391 | CssRule::Namespace(..) 4392 | CssRule::FontFace(..) 4393 | CssRule::Container(..) 4394 | CssRule::CounterStyle(..) 4395 | CssRule::Supports(..) 4396 | CssRule::Keyframes(..) 4397 | CssRule::Margin(..) 4398 | CssRule::Page(..) 4399 | CssRule::Property(..) 4400 | CssRule::Document(..) 4401 | CssRule::LayerBlock(..) 4402 | CssRule::LayerStatement(..) 4403 | CssRule::FontPaletteValues(..) 4404 | CssRule::FontFeatureValues(..) 4405 | CssRule::Scope(..) 4406 | CssRule::StartingStyle(..) 4407 | CssRule::CustomMedia(..) 4408 | CssRule::PositionTry(..) => { 4409 // Not affected by device changes. @custom-media is handled by the potential 4410 // @media rules referencing it being handled. 4411 continue; 4412 }, 4413 CssRule::Import(ref lock) => { 4414 let import_rule = lock.read_with(guard); 4415 let effective_now = match import_rule.stylesheet.media(guard) { 4416 Some(m) => m.evaluate( 4417 device, 4418 quirks_mode, 4419 &mut CustomMediaEvaluator::new(&self.custom_media, guard), 4420 ), 4421 None => true, 4422 }; 4423 let effective_then = self 4424 .effective_media_query_results 4425 .was_effective(import_rule); 4426 if effective_now != effective_then { 4427 debug!( 4428 " > @import rule {:?} changed {} -> {}", 4429 import_rule.stylesheet.media(guard), 4430 effective_then, 4431 effective_now 4432 ); 4433 return false; 4434 } 4435 4436 if !effective_now { 4437 iter.skip_children(); 4438 } 4439 }, 4440 CssRule::Media(ref media_rule) => { 4441 let mq = media_rule.media_queries.read_with(guard); 4442 let effective_now = mq.evaluate( 4443 device, 4444 quirks_mode, 4445 &mut CustomMediaEvaluator::new(&self.custom_media, guard), 4446 ); 4447 let effective_then = self 4448 .effective_media_query_results 4449 .was_effective(&**media_rule); 4450 4451 if effective_now != effective_then { 4452 debug!( 4453 " > @media rule {:?} changed {} -> {}", 4454 mq, effective_then, effective_now 4455 ); 4456 return false; 4457 } 4458 4459 if !effective_now { 4460 iter.skip_children(); 4461 } 4462 }, 4463 } 4464 } 4465 4466 true 4467 } 4468 4469 /// Returns the custom properties map. 4470 pub fn custom_property_registrations(&self) -> &LayerOrderedMap<Arc<PropertyRegistration>> { 4471 &self.custom_property_registrations 4472 } 4473 4474 fn revalidate_scopes<E: TElement>( 4475 &self, 4476 element: &E, 4477 matching_context: &mut MatchingContext<E::Impl>, 4478 result: &mut ScopeRevalidationResult, 4479 ) { 4480 // TODO(dshin): A scope block may not contain style rule for this element, but we don't keep 4481 // track of that, so we check _all_ scope conditions. It's possible for two comparable elements 4482 // to share scope & relevant styles rules, but also differ in scopes that do not contain style 4483 // rules relevant to them. So while we can be certain that an identical result share scoped styles 4484 // (Given that other sharing conditions are met), it is uncertain if elements with non-matching 4485 // results do not. 4486 for condition_id in 1..self.scope_conditions.len() { 4487 let condition = &self.scope_conditions[condition_id]; 4488 let matches = if condition.is_trivial { 4489 // Just ignore this condition - for style sharing candidates, guaranteed 4490 // the same match result. 4491 continue; 4492 } else { 4493 let result = scope_root_candidates( 4494 &self.scope_conditions, 4495 ScopeConditionId(condition_id as u16), 4496 element, 4497 // This should be ok since we aren't sharing styles across shadow boundaries. 4498 false, 4499 &self.scope_subject_map, 4500 matching_context, 4501 ); 4502 !result.candidates.is_empty() 4503 }; 4504 result.scopes_matched.push(matches); 4505 } 4506 } 4507 4508 /// Clears the cascade data, but not the invalidation data. 4509 fn clear_cascade_data(&mut self) { 4510 self.normal_rules.clear(); 4511 if let Some(ref mut slotted_rules) = self.slotted_rules { 4512 slotted_rules.clear(); 4513 } 4514 if let Some(ref mut part_rules) = self.part_rules { 4515 part_rules.clear(); 4516 } 4517 if let Some(ref mut host_rules) = self.featureless_host_rules { 4518 host_rules.clear(); 4519 } 4520 self.animations.clear(); 4521 self.custom_property_registrations.clear(); 4522 self.layer_id.clear(); 4523 self.layers.clear(); 4524 self.layers.push(CascadeLayer::root()); 4525 self.custom_media.clear(); 4526 self.container_conditions.clear(); 4527 self.container_conditions 4528 .push(ContainerConditionReference::none()); 4529 self.scope_conditions.clear(); 4530 self.scope_conditions.push(ScopeConditionReference::none()); 4531 #[cfg(feature = "gecko")] 4532 self.extra_data.clear(); 4533 self.rules_source_order = 0; 4534 self.num_selectors = 0; 4535 self.num_declarations = 0; 4536 } 4537 4538 fn clear_invalidation_data(&mut self) { 4539 self.invalidation_map.clear(); 4540 self.relative_selector_invalidation_map.clear(); 4541 self.additional_relative_selector_invalidation_map.clear(); 4542 self.attribute_dependencies.clear(); 4543 self.nth_of_attribute_dependencies.clear(); 4544 self.nth_of_custom_state_dependencies.clear(); 4545 self.nth_of_class_dependencies.clear(); 4546 self.state_dependencies = ElementState::empty(); 4547 self.nth_of_state_dependencies = ElementState::empty(); 4548 self.document_state_dependencies = DocumentState::empty(); 4549 self.mapped_ids.clear(); 4550 self.nth_of_mapped_ids.clear(); 4551 self.selectors_for_cache_revalidation.clear(); 4552 self.effective_media_query_results.clear(); 4553 self.scope_subject_map.clear(); 4554 } 4555 } 4556 4557 fn note_scope_selector_for_invalidation( 4558 quirks_mode: QuirksMode, 4559 scope_dependencies: &Arc<servo_arc::HeaderSlice<(), Dependency>>, 4560 dependency_vector: &mut Vec<Dependency>, 4561 invalidation_map: &mut InvalidationMap, 4562 relative_selector_invalidation_map: &mut InvalidationMap, 4563 additional_relative_selector_invalidation_map: &mut AdditionalRelativeSelectorInvalidationMap, 4564 visitor: &mut StylistSelectorVisitor<'_>, 4565 scope_kind: ScopeDependencyInvalidationKind, 4566 s: &Selector<SelectorImpl>, 4567 ) -> Result<(), AllocErr> { 4568 let mut new_inner_dependencies = note_selector_for_invalidation( 4569 &s.clone(), 4570 quirks_mode, 4571 invalidation_map, 4572 relative_selector_invalidation_map, 4573 additional_relative_selector_invalidation_map, 4574 Some(&scope_dependencies), 4575 Some(scope_kind), 4576 )?; 4577 s.visit(visitor); 4578 new_inner_dependencies.as_mut().map(|dep| { 4579 dependency_vector.append(dep); 4580 }); 4581 Ok(()) 4582 } 4583 4584 fn build_scope_dependencies( 4585 quirks_mode: QuirksMode, 4586 mut cur_scope_inner_dependencies: Vec<Dependency>, 4587 mut visitor: StylistSelectorVisitor<'_>, 4588 cond: &ScopeBoundsWithHashes, 4589 mut invalidation_map: &mut InvalidationMap, 4590 mut relative_selector_invalidation_map: &mut InvalidationMap, 4591 mut additional_relative_selector_invalidation_map: &mut AdditionalRelativeSelectorInvalidationMap, 4592 ) -> Result<Vec<Dependency>, AllocErr> { 4593 if cond.end.is_some() { 4594 let deps = 4595 ThinArc::from_header_and_iter((), cur_scope_inner_dependencies.clone().into_iter()); 4596 let mut end_dependency_vector = Vec::new(); 4597 for s in cond.end_selectors() { 4598 note_scope_selector_for_invalidation( 4599 quirks_mode, 4600 &deps, 4601 &mut end_dependency_vector, 4602 &mut invalidation_map, 4603 &mut relative_selector_invalidation_map, 4604 &mut additional_relative_selector_invalidation_map, 4605 &mut visitor, 4606 ScopeDependencyInvalidationKind::ScopeEnd, 4607 s, 4608 )?; 4609 } 4610 cur_scope_inner_dependencies.append(&mut end_dependency_vector); 4611 } 4612 let inner_scope_dependencies = 4613 ThinArc::from_header_and_iter((), cur_scope_inner_dependencies.into_iter()); 4614 4615 Ok(if cond.start.is_some() { 4616 let mut dependency_vector = Vec::new(); 4617 for s in cond.start_selectors() { 4618 note_scope_selector_for_invalidation( 4619 quirks_mode, 4620 &inner_scope_dependencies, 4621 &mut dependency_vector, 4622 &mut invalidation_map, 4623 &mut relative_selector_invalidation_map, 4624 &mut additional_relative_selector_invalidation_map, 4625 &mut visitor, 4626 ScopeDependencyInvalidationKind::ExplicitScope, 4627 s, 4628 )?; 4629 } 4630 dependency_vector 4631 } else { 4632 vec![Dependency::new( 4633 IMPLICIT_SCOPE.slice()[0].clone(), 4634 0, 4635 Some(inner_scope_dependencies), 4636 DependencyInvalidationKind::Scope(ScopeDependencyInvalidationKind::ImplicitScope), 4637 )] 4638 }) 4639 } 4640 4641 impl CascadeDataCacheEntry for CascadeData { 4642 fn rebuild<S>( 4643 device: &Device, 4644 quirks_mode: QuirksMode, 4645 collection: SheetCollectionFlusher<S>, 4646 guard: &SharedRwLockReadGuard, 4647 old: &Self, 4648 difference: &mut CascadeDataDifference, 4649 ) -> Result<Arc<Self>, AllocErr> 4650 where 4651 S: StylesheetInDocument + PartialEq + 'static, 4652 { 4653 debug_assert!(collection.dirty(), "We surely need to do something?"); 4654 // If we're doing a full rebuild anyways, don't bother cloning the data. 4655 let mut updatable_entry = match collection.data_validity() { 4656 DataValidity::Valid | DataValidity::CascadeInvalid => old.clone(), 4657 DataValidity::FullyInvalid => Self::new(), 4658 }; 4659 updatable_entry.rebuild(device, quirks_mode, collection, guard, difference)?; 4660 Ok(Arc::new(updatable_entry)) 4661 } 4662 4663 #[cfg(feature = "gecko")] 4664 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 4665 self.normal_rules.add_size_of(ops, sizes); 4666 if let Some(ref slotted_rules) = self.slotted_rules { 4667 slotted_rules.add_size_of(ops, sizes); 4668 } 4669 if let Some(ref part_rules) = self.part_rules { 4670 part_rules.add_size_of(ops, sizes); 4671 } 4672 if let Some(ref host_rules) = self.featureless_host_rules { 4673 host_rules.add_size_of(ops, sizes); 4674 } 4675 sizes.mInvalidationMap += self.invalidation_map.size_of(ops); 4676 sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops); 4677 sizes.mOther += self.animations.size_of(ops); 4678 sizes.mOther += self.effective_media_query_results.size_of(ops); 4679 sizes.mOther += self.extra_data.size_of(ops); 4680 } 4681 } 4682 4683 impl Default for CascadeData { 4684 fn default() -> Self { 4685 CascadeData::new() 4686 } 4687 } 4688 4689 /// A rule, that wraps a style rule, but represents a single selector of the 4690 /// rule. 4691 #[derive(Clone, Debug, MallocSizeOf)] 4692 pub struct Rule { 4693 /// The selector this struct represents. We store this and the 4694 /// any_{important,normal} booleans inline in the Rule to avoid 4695 /// pointer-chasing when gathering applicable declarations, which 4696 /// can ruin performance when there are a lot of rules. 4697 #[ignore_malloc_size_of = "CssRules have primary refs, we measure there"] 4698 pub selector: Selector<SelectorImpl>, 4699 4700 /// The ancestor hashes associated with the selector. 4701 pub hashes: AncestorHashes, 4702 4703 /// The source order this style rule appears in. Note that we only use 4704 /// three bytes to store this value in ApplicableDeclarationsBlock, so 4705 /// we could repurpose that storage here if we needed to. 4706 pub source_order: u32, 4707 4708 /// The current layer id of this style rule. 4709 pub layer_id: LayerId, 4710 4711 /// The current @container rule id. 4712 pub container_condition_id: ContainerConditionId, 4713 4714 /// True if this rule is inside @starting-style. 4715 pub is_starting_style: bool, 4716 4717 /// The current @scope rule id. 4718 pub scope_condition_id: ScopeConditionId, 4719 4720 /// The actual style rule. 4721 #[ignore_malloc_size_of = "Secondary ref. Primary ref is in StyleRule under Stylesheet."] 4722 pub style_source: StyleSource, 4723 } 4724 4725 impl SelectorMapEntry for Rule { 4726 fn selector(&self) -> SelectorIter<'_, SelectorImpl> { 4727 self.selector.iter() 4728 } 4729 } 4730 4731 impl Rule { 4732 /// Returns the specificity of the rule. 4733 pub fn specificity(&self) -> u32 { 4734 self.selector.specificity() 4735 } 4736 4737 /// Turns this rule into an `ApplicableDeclarationBlock` for the given 4738 /// cascade level. 4739 pub fn to_applicable_declaration_block( 4740 &self, 4741 level: CascadeLevel, 4742 cascade_data: &CascadeData, 4743 scope_proximity: ScopeProximity, 4744 ) -> ApplicableDeclarationBlock { 4745 ApplicableDeclarationBlock::new( 4746 self.style_source.clone(), 4747 self.source_order, 4748 level, 4749 self.specificity(), 4750 cascade_data.layer_order_for(self.layer_id), 4751 scope_proximity, 4752 ) 4753 } 4754 4755 /// Creates a new Rule. 4756 pub fn new( 4757 selector: Selector<SelectorImpl>, 4758 hashes: AncestorHashes, 4759 style_source: StyleSource, 4760 source_order: u32, 4761 layer_id: LayerId, 4762 container_condition_id: ContainerConditionId, 4763 is_starting_style: bool, 4764 scope_condition_id: ScopeConditionId, 4765 ) -> Self { 4766 Self { 4767 selector, 4768 hashes, 4769 style_source, 4770 source_order, 4771 layer_id, 4772 container_condition_id, 4773 is_starting_style, 4774 scope_condition_id, 4775 } 4776 } 4777 } 4778 4779 // The size of this is critical to performance on the bloom-basic 4780 // microbenchmark. 4781 // When iterating over a large Rule array, we want to be able to fast-reject 4782 // selectors (with the inline hashes) with as few cache misses as possible. 4783 size_of_test!(Rule, 40); 4784 4785 /// A function to be able to test the revalidation stuff. 4786 pub fn needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool { 4787 let mut needs_revalidation = false; 4788 let mut mapped_ids = Default::default(); 4789 let mut nth_of_mapped_ids = Default::default(); 4790 let mut attribute_dependencies = Default::default(); 4791 let mut nth_of_class_dependencies = Default::default(); 4792 let mut nth_of_attribute_dependencies = Default::default(); 4793 let mut nth_of_custom_state_dependencies = Default::default(); 4794 let mut state_dependencies = ElementState::empty(); 4795 let mut nth_of_state_dependencies = ElementState::empty(); 4796 let mut document_state_dependencies = DocumentState::empty(); 4797 let mut visitor = StylistSelectorVisitor { 4798 passed_rightmost_selector: false, 4799 needs_revalidation: &mut needs_revalidation, 4800 in_selector_list_of: SelectorListKind::default(), 4801 mapped_ids: &mut mapped_ids, 4802 nth_of_mapped_ids: &mut nth_of_mapped_ids, 4803 attribute_dependencies: &mut attribute_dependencies, 4804 nth_of_class_dependencies: &mut nth_of_class_dependencies, 4805 nth_of_attribute_dependencies: &mut nth_of_attribute_dependencies, 4806 nth_of_custom_state_dependencies: &mut nth_of_custom_state_dependencies, 4807 state_dependencies: &mut state_dependencies, 4808 nth_of_state_dependencies: &mut nth_of_state_dependencies, 4809 document_state_dependencies: &mut document_state_dependencies, 4810 }; 4811 s.visit(&mut visitor); 4812 needs_revalidation 4813 }