style/
stylist.rs

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