Skip to main content

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