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