style/
stylist.rs

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