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/. */
7 use crate::applicable_declarations::{
8 ApplicableDeclarationBlock, ApplicableDeclarationList, CascadePriority,
10 use crate::context::{CascadeInputs, QuirksMode};
11 use crate::dom::TElement;
12 #[cfg(feature = "gecko")]
13 use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
14 use crate::invalidation::element::invalidation_map::{
15 note_selector_for_invalidation, InvalidationMap, RelativeSelectorInvalidationMap,
17 use crate::invalidation::media_queries::{
18 EffectiveMediaQueryResults, MediaListKey, ToMediaListKey,
20 use crate::invalidation::stylesheets::RuleChangeKind;
21 use crate::media_queries::Device;
22 use crate::properties::{self, CascadeMode, ComputedValues, FirstLineReparenting};
23 use crate::properties::{AnimationDeclarations, PropertyDeclarationBlock};
24 use crate::properties_and_values::registry::{ScriptRegistry as CustomPropertyScriptRegistry, PropertyRegistration};
25 use crate::rule_cache::{RuleCache, RuleCacheConditions};
26 use crate::rule_collector::RuleCollector;
27 use crate::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
28 use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
29 use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
30 use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
31 use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind};
32 use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher};
33 use crate::stylesheets::container_rule::ContainerCondition;
34 use crate::stylesheets::import_rule::ImportLayer;
35 use crate::stylesheets::keyframes_rule::KeyframesAnimation;
36 use crate::stylesheets::layer_rule::{LayerName, LayerOrder};
37 #[cfg(feature = "gecko")]
38 use crate::stylesheets::{
39 CounterStyleRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule,
41 use crate::stylesheets::{
42 CssRule, EffectiveRulesIterator, Origin, OriginSet, PerOrigin, PerOriginIter,
43 PagePseudoClassFlags, PageRule,
45 use crate::stylesheets::{StyleRule, StylesheetContents, StylesheetInDocument};
47 use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded, WeakAtom};
48 use dom::{DocumentState, ElementState};
49 use fxhash::FxHashMap;
50 use malloc_size_of::MallocSizeOf;
51 #[cfg(feature = "gecko")]
52 use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
53 use selectors::attr::{CaseSensitivity, NamespaceConstraint};
54 use selectors::bloom::BloomFilter;
55 use selectors::matching::{
56 matches_selector, MatchingContext, MatchingMode, NeedsSelectorFlags, SelectorCaches,
58 use selectors::matching::{MatchingForInvalidation, VisitedHandlingMode};
59 use selectors::parser::{
60 ArcSelectorList, AncestorHashes, Combinator, Component, Selector, SelectorIter, SelectorList,
62 use selectors::visitor::{SelectorListKind, SelectorVisitor};
63 use servo_arc::{Arc, ArcBorrow};
64 use smallbitvec::SmallBitVec;
65 use smallvec::SmallVec;
67 use std::cmp::Ordering;
68 use std::hash::{Hash, Hasher};
72 /// The type of the stylesheets that the stylist contains.
73 #[cfg(feature = "servo")]
74 pub type StylistSheet = crate::stylesheets::DocumentStyleSheet;
76 /// The type of the stylesheets that the stylist contains.
77 #[cfg(feature = "gecko")]
78 pub type StylistSheet = crate::gecko::data::GeckoStyleSheet;
80 #[derive(Debug, Clone)]
81 struct StylesheetContentsPtr(Arc<StylesheetContents>);
83 impl PartialEq for StylesheetContentsPtr {
85 fn eq(&self, other: &Self) -> bool {
86 Arc::ptr_eq(&self.0, &other.0)
90 impl Eq for StylesheetContentsPtr {}
92 impl Hash for StylesheetContentsPtr {
93 fn hash<H: Hasher>(&self, state: &mut H) {
94 let contents: &StylesheetContents = &*self.0;
95 (contents as *const StylesheetContents).hash(state)
99 type StyleSheetContentList = Vec<StylesheetContentsPtr>;
101 /// A key in the cascade data cache.
102 #[derive(Debug, Hash, Default, PartialEq, Eq)]
103 struct CascadeDataCacheKey {
104 media_query_results: Vec<MediaListKey>,
105 contents: StyleSheetContentList,
108 unsafe impl Send for CascadeDataCacheKey {}
109 unsafe impl Sync for CascadeDataCacheKey {}
111 trait CascadeDataCacheEntry: Sized {
112 /// Returns a reference to the cascade data.
113 fn cascade_data(&self) -> &CascadeData;
114 /// Rebuilds the cascade data for the new stylesheet collection. The
115 /// collection is guaranteed to be dirty.
118 quirks_mode: QuirksMode,
119 collection: SheetCollectionFlusher<S>,
120 guard: &SharedRwLockReadGuard,
122 ) -> Result<Arc<Self>, AllocErr>
124 S: StylesheetInDocument + PartialEq + 'static;
125 /// Measures heap memory usage.
126 #[cfg(feature = "gecko")]
127 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes);
130 struct CascadeDataCache<Entry> {
131 entries: FxHashMap<CascadeDataCacheKey, Arc<Entry>>,
134 impl<Entry> CascadeDataCache<Entry>
136 Entry: CascadeDataCacheEntry,
140 entries: Default::default(),
144 fn len(&self) -> usize {
148 // FIXME(emilio): This may need to be keyed on quirks-mode too, though for
149 // UA sheets there aren't class / id selectors on those sheets, usually, so
150 // it's probably ok... For the other cache the quirks mode shouldn't differ
151 // so also should be fine.
155 quirks_mode: QuirksMode,
156 collection: SheetCollectionFlusher<S>,
157 guard: &SharedRwLockReadGuard,
159 ) -> Result<Option<Arc<Entry>>, AllocErr>
161 S: StylesheetInDocument + PartialEq + 'static,
163 use std::collections::hash_map::Entry as HashMapEntry;
164 debug!("StyleSheetCache::lookup({})", self.len());
166 if !collection.dirty() {
170 let mut key = CascadeDataCacheKey::default();
171 for sheet in collection.sheets() {
172 CascadeData::collect_applicable_media_query_results_into(
176 &mut key.media_query_results,
182 match self.entries.entry(key) {
183 HashMapEntry::Vacant(e) => {
184 debug!("> Picking the slow path (not in the cache)");
185 new_entry = Entry::rebuild(device, quirks_mode, collection, guard, old_entry)?;
186 e.insert(new_entry.clone());
188 HashMapEntry::Occupied(mut e) => {
189 // Avoid reusing our old entry (this can happen if we get
190 // invalidated due to CSSOM mutations and our old stylesheet
191 // contents were already unique, for example).
192 if !std::ptr::eq(&**e.get(), old_entry) {
193 if log_enabled!(log::Level::Debug) {
194 debug!("cache hit for:");
195 for sheet in collection.sheets() {
196 debug!(" > {:?}", sheet);
199 // The line below ensures the "committed" bit is updated
201 collection.each(|_, _| true);
202 return Ok(Some(e.get().clone()));
205 debug!("> Picking the slow path due to same entry as old");
206 new_entry = Entry::rebuild(device, quirks_mode, collection, guard, old_entry)?;
207 e.insert(new_entry.clone());
214 /// Returns all the cascade datas that are not being used (that is, that are
215 /// held alive just by this cache).
217 /// We return them instead of dropping in place because some of them may
218 /// keep alive some other documents (like the SVG documents kept alive by
219 /// URL references), and thus we don't want to drop them while locking the
220 /// cache to not deadlock.
221 fn take_unused(&mut self) -> SmallVec<[Arc<Entry>; 3]> {
222 let mut unused = SmallVec::new();
223 self.entries.retain(|_key, value| {
224 // is_unique() returns false for static references, but we never
225 // have static references to UserAgentCascadeDatas. If we did, it
226 // may not make sense to put them in the cache in the first place.
227 if !value.is_unique() {
230 unused.push(value.clone());
236 fn take_all(&mut self) -> FxHashMap<CascadeDataCacheKey, Arc<Entry>> {
237 mem::take(&mut self.entries)
240 #[cfg(feature = "gecko")]
241 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
242 sizes.mOther += self.entries.shallow_size_of(ops);
243 for (_key, arc) in self.entries.iter() {
244 // These are primary Arc references that can be measured
246 sizes.mOther += arc.unconditional_shallow_size_of(ops);
247 arc.add_size_of(ops, sizes);
252 /// Measure heap usage of UA_CASCADE_DATA_CACHE.
253 #[cfg(feature = "gecko")]
254 pub fn add_size_of_ua_cache(ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
255 UA_CASCADE_DATA_CACHE
258 .add_size_of(ops, sizes);
262 /// A cache of computed user-agent data, to be shared across documents.
263 static ref UA_CASCADE_DATA_CACHE: Mutex<UserAgentCascadeDataCache> =
264 Mutex::new(UserAgentCascadeDataCache::new());
267 impl CascadeDataCacheEntry for UserAgentCascadeData {
268 fn cascade_data(&self) -> &CascadeData {
274 quirks_mode: QuirksMode,
275 collection: SheetCollectionFlusher<S>,
276 guard: &SharedRwLockReadGuard,
278 ) -> Result<Arc<Self>, AllocErr>
280 S: StylesheetInDocument + PartialEq + 'static,
282 // TODO: Maybe we should support incremental rebuilds, though they seem
283 // uncommon and rebuild() doesn't deal with
284 // precomputed_pseudo_element_decls for now so...
285 let mut new_data = Self {
286 cascade_data: CascadeData::new(),
287 precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations::default(),
290 for sheet in collection.sheets() {
291 new_data.cascade_data.add_stylesheet(
296 SheetRebuildKind::Full,
297 Some(&mut new_data.precomputed_pseudo_element_decls),
301 new_data.cascade_data.did_finish_rebuild();
303 Ok(Arc::new(new_data))
306 #[cfg(feature = "gecko")]
307 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
308 self.cascade_data.add_size_of(ops, sizes);
309 sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops);
313 type UserAgentCascadeDataCache = CascadeDataCache<UserAgentCascadeData>;
315 type PrecomputedPseudoElementDeclarations = PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>;
318 struct UserAgentCascadeData {
319 cascade_data: CascadeData,
321 /// Applicable declarations for a given non-eagerly cascaded pseudo-element.
323 /// These are eagerly computed once, and then used to resolve the new
324 /// computed values on the fly on layout.
326 /// These are only filled from UA stylesheets.
327 precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations,
331 /// The empty UA cascade data for un-filled stylists.
332 static ref EMPTY_UA_CASCADE_DATA: Arc<UserAgentCascadeData> = {
333 let arc = Arc::new(UserAgentCascadeData::default());
334 arc.mark_as_intentionally_leaked();
339 /// All the computed information for all the stylesheets that apply to the
341 #[derive(MallocSizeOf)]
342 pub struct DocumentCascadeData {
343 #[ignore_malloc_size_of = "Arc, owned by UserAgentCascadeDataCache or empty"]
344 user_agent: Arc<UserAgentCascadeData>,
347 per_origin: PerOrigin<()>,
350 impl Default for DocumentCascadeData {
351 fn default() -> Self {
353 user_agent: EMPTY_UA_CASCADE_DATA.clone(),
354 user: Default::default(),
355 author: Default::default(),
356 per_origin: Default::default(),
361 /// An iterator over the cascade data of a given document.
362 pub struct DocumentCascadeDataIter<'a> {
363 iter: PerOriginIter<'a, ()>,
364 cascade_data: &'a DocumentCascadeData,
367 impl<'a> Iterator for DocumentCascadeDataIter<'a> {
368 type Item = (&'a CascadeData, Origin);
370 fn next(&mut self) -> Option<Self::Item> {
371 let (_, origin) = self.iter.next()?;
372 Some((self.cascade_data.borrow_for_origin(origin), origin))
376 impl DocumentCascadeData {
377 /// Borrows the cascade data for a given origin.
379 pub fn borrow_for_origin(&self, origin: Origin) -> &CascadeData {
381 Origin::UserAgent => &self.user_agent.cascade_data,
382 Origin::Author => &self.author,
383 Origin::User => &self.user,
387 fn iter_origins(&self) -> DocumentCascadeDataIter {
388 DocumentCascadeDataIter {
389 iter: self.per_origin.iter_origins(),
394 fn iter_origins_rev(&self) -> DocumentCascadeDataIter {
395 DocumentCascadeDataIter {
396 iter: self.per_origin.iter_origins_rev(),
401 /// Rebuild the cascade data for the given document stylesheets, and
402 /// optionally with a set of user agent stylesheets. Returns Err(..)
407 quirks_mode: QuirksMode,
408 mut flusher: DocumentStylesheetFlusher<'a, S>,
409 guards: &StylesheetGuards,
410 ) -> Result<(), AllocErr>
412 S: StylesheetInDocument + PartialEq + 'static,
414 // First do UA sheets.
416 let origin_flusher = flusher.flush_origin(Origin::UserAgent);
417 // Dirty check is just a minor optimization (no need to grab the
418 // lock if nothing has changed).
419 if origin_flusher.dirty() {
420 let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
421 let new_data = ua_cache.lookup(
428 if let Some(new_data) = new_data {
429 self.user_agent = new_data;
431 let _unused_entries = ua_cache.take_unused();
432 // See the comments in take_unused() as for why the following
434 std::mem::drop(ua_cache);
438 // Now do the user sheets.
442 flusher.flush_origin(Origin::User),
446 // And now the author sheets.
450 flusher.flush_origin(Origin::Author),
457 /// Measures heap usage.
458 #[cfg(feature = "gecko")]
459 pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
460 self.user.add_size_of(ops, sizes);
461 self.author.add_size_of(ops, sizes);
465 /// Whether author styles are enabled.
467 /// This is used to support Gecko.
468 #[allow(missing_docs)]
469 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
470 pub enum AuthorStylesEnabled {
475 /// A wrapper over a DocumentStylesheetSet that can be `Sync`, since it's only
476 /// used and exposed via mutable methods in the `Stylist`.
477 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
478 struct StylistStylesheetSet(DocumentStylesheetSet<StylistSheet>);
479 // Read above to see why this is fine.
480 unsafe impl Sync for StylistStylesheetSet {}
482 impl StylistStylesheetSet {
484 StylistStylesheetSet(DocumentStylesheetSet::new())
488 impl ops::Deref for StylistStylesheetSet {
489 type Target = DocumentStylesheetSet<StylistSheet>;
491 fn deref(&self) -> &Self::Target {
496 impl ops::DerefMut for StylistStylesheetSet {
497 fn deref_mut(&mut self) -> &mut Self::Target {
502 /// This structure holds all the selectors and device characteristics
503 /// for a given document. The selectors are converted into `Rule`s
504 /// and sorted into `SelectorMap`s keyed off stylesheet origin and
505 /// pseudo-element (see `CascadeData`).
507 /// This structure is effectively created once per pipeline, in the
508 /// LayoutThread corresponding to that pipeline.
509 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
511 /// Device that the stylist is currently evaluating against.
513 /// This field deserves a bigger comment due to the different use that Gecko
514 /// and Servo give to it (that we should eventually unify).
516 /// With Gecko, the device is never changed. Gecko manually tracks whether
517 /// the device data should be reconstructed, and "resets" the state of the
520 /// On Servo, on the other hand, the device is a really cheap representation
521 /// that is recreated each time some constraint changes and calling
525 /// The list of stylesheets.
526 stylesheets: StylistStylesheetSet,
528 /// A cache of CascadeDatas for AuthorStylesheetSets (i.e., shadow DOM).
529 author_data_cache: CascadeDataCache<CascadeData>,
531 /// If true, the quirks-mode stylesheet is applied.
532 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "defined in selectors")]
533 quirks_mode: QuirksMode,
535 /// Selector maps for all of the style sheets in the stylist, after
536 /// evalutaing media rules against the current device, split out per
538 cascade_data: DocumentCascadeData,
540 /// Whether author styles are enabled.
541 author_styles_enabled: AuthorStylesEnabled,
543 /// The rule tree, that stores the results of selector matching.
546 /// The set of registered custom properties from script.
547 /// <https://drafts.css-houdini.org/css-properties-values-api-1/#dom-window-registeredpropertyset-slot>
548 script_custom_properties: CustomPropertyScriptRegistry,
550 /// The total number of times the stylist has been rebuilt.
554 /// What cascade levels to include when styling elements.
555 #[derive(Clone, Copy, PartialEq)]
556 pub enum RuleInclusion {
557 /// Include rules for style sheets at all cascade levels. This is the
558 /// normal rule inclusion mode.
560 /// Only include rules from UA and user level sheets. Used to implement
561 /// `getDefaultComputedStyle`.
565 #[cfg(feature = "gecko")]
566 impl From<StyleRuleInclusion> for RuleInclusion {
567 fn from(value: StyleRuleInclusion) -> Self {
569 StyleRuleInclusion::All => RuleInclusion::All,
570 StyleRuleInclusion::DefaultOnly => RuleInclusion::DefaultOnly,
575 enum AncestorSelectorList<'a> {
576 Borrowed(&'a SelectorList<SelectorImpl>),
577 Shared(ArcSelectorList<SelectorImpl>),
580 impl<'a> AncestorSelectorList<'a> {
581 fn into_shared(&mut self) -> &ArcSelectorList<SelectorImpl> {
582 if let Self::Borrowed(ref b) = *self {
583 let shared = b.to_shared();
584 *self = Self::Shared(shared);
587 Self::Shared(ref shared) => return shared,
588 Self::Borrowed(..) => unsafe { debug_unreachable!() },
593 /// A struct containing state from ancestor rules like @layer / @import /
594 /// @container / nesting.
595 struct ContainingRuleState<'a> {
596 layer_name: LayerName,
598 container_condition_id: ContainerConditionId,
599 ancestor_selector_lists: SmallVec<[AncestorSelectorList<'a>; 2]>,
602 impl<'a> Default for ContainingRuleState<'a> {
603 fn default() -> Self {
605 layer_name: LayerName::new_empty(),
606 layer_id: LayerId::root(),
607 container_condition_id: ContainerConditionId::none(),
608 ancestor_selector_lists: Default::default(),
613 struct SavedContainingRuleState {
614 ancestor_selector_lists_len: usize,
615 layer_name_len: usize,
617 container_condition_id: ContainerConditionId,
620 impl<'a> ContainingRuleState<'a> {
621 fn save(&self) -> SavedContainingRuleState {
622 SavedContainingRuleState {
623 ancestor_selector_lists_len: self.ancestor_selector_lists.len(),
624 layer_name_len: self.layer_name.0.len(),
625 layer_id: self.layer_id,
626 container_condition_id: self.container_condition_id,
630 fn restore(&mut self, saved: &SavedContainingRuleState) {
631 debug_assert!(self.layer_name.0.len() >= saved.layer_name_len);
632 debug_assert!(self.ancestor_selector_lists.len() >= saved.ancestor_selector_lists_len);
633 self.ancestor_selector_lists
634 .truncate(saved.ancestor_selector_lists_len);
635 self.layer_name.0.truncate(saved.layer_name_len);
636 self.layer_id = saved.layer_id;
637 self.container_condition_id = saved.container_condition_id;
642 /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
643 /// If more members are added here, think about whether they should
644 /// be reset in clear().
646 pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
650 stylesheets: StylistStylesheetSet::new(),
651 author_data_cache: CascadeDataCache::new(),
652 cascade_data: Default::default(),
653 author_styles_enabled: AuthorStylesEnabled::Yes,
654 rule_tree: RuleTree::new(),
655 script_custom_properties: Default::default(),
660 /// Returns the document cascade data.
662 pub fn cascade_data(&self) -> &DocumentCascadeData {
666 /// Returns whether author styles are enabled or not.
668 pub fn author_styles_enabled(&self) -> AuthorStylesEnabled {
669 self.author_styles_enabled
672 /// Iterate through all the cascade datas from the document.
674 pub fn iter_origins(&self) -> DocumentCascadeDataIter {
675 self.cascade_data.iter_origins()
678 /// Does what the name says, to prevent author_data_cache to grow without
680 pub fn remove_unique_author_data_cache_entries(&mut self) {
681 self.author_data_cache.take_unused();
684 /// Returns the custom property registration for this property's name.
685 /// https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration
686 pub fn get_custom_property_registration(&self, name: &Atom) -> Option<&PropertyRegistration> {
687 if let Some(registration) = self.custom_property_script_registry().get(name) {
688 return Some(registration);
690 for (data, _) in self.iter_origins() {
691 if let Some(registration) = data.custom_property_registrations.get(name) {
692 return Some(registration);
699 /// Rebuilds (if needed) the CascadeData given a sheet collection.
700 pub fn rebuild_author_data<S>(
702 old_data: &CascadeData,
703 collection: SheetCollectionFlusher<S>,
704 guard: &SharedRwLockReadGuard,
705 ) -> Result<Option<Arc<CascadeData>>, AllocErr>
707 S: StylesheetInDocument + PartialEq + 'static,
709 self.author_data_cache
710 .lookup(&self.device, self.quirks_mode, collection, guard, old_data)
713 /// Iterate over the extra data in origin order.
715 pub fn iter_extra_data_origins(&self) -> ExtraStyleDataIterator {
716 ExtraStyleDataIterator(self.cascade_data.iter_origins())
719 /// Iterate over the extra data in reverse origin order.
721 pub fn iter_extra_data_origins_rev(&self) -> ExtraStyleDataIterator {
722 ExtraStyleDataIterator(self.cascade_data.iter_origins_rev())
725 /// Returns the number of selectors.
726 pub fn num_selectors(&self) -> usize {
729 .map(|(d, _)| d.num_selectors)
733 /// Returns the number of declarations.
734 pub fn num_declarations(&self) -> usize {
737 .map(|(d, _)| d.num_declarations)
741 /// Returns the number of times the stylist has been rebuilt.
742 pub fn num_rebuilds(&self) -> usize {
746 /// Returns the number of revalidation_selectors.
747 pub fn num_revalidation_selectors(&self) -> usize {
750 .map(|(data, _)| data.selectors_for_cache_revalidation.len())
754 /// Returns the number of entries in invalidation maps.
755 pub fn num_invalidations(&self) -> usize {
759 data.invalidation_map.len() + data.relative_selector_invalidation_map.len()
764 /// Returns whether the given DocumentState bit is relied upon by a selector
766 pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
769 .any(|(d, _)| d.document_state_dependencies.intersects(state))
772 /// Flush the list of stylesheets if they changed, ensuring the stylist is
776 guards: &StylesheetGuards,
777 document_element: Option<E>,
778 snapshots: Option<&SnapshotMap>,
783 if !self.stylesheets.has_changed() {
787 self.num_rebuilds += 1;
789 let flusher = self.stylesheets.flush(document_element, snapshots);
791 let had_invalidations = flusher.had_invalidations();
794 .rebuild(&self.device, self.quirks_mode, flusher, guards)
795 .unwrap_or_else(|_| warn!("OOM in Stylist::flush"));
800 /// Insert a given stylesheet before another stylesheet in the document.
801 pub fn insert_stylesheet_before(
804 before_sheet: StylistSheet,
805 guard: &SharedRwLockReadGuard,
808 .insert_stylesheet_before(Some(&self.device), sheet, before_sheet, guard)
811 /// Marks a given stylesheet origin as dirty, due to, for example, changes
812 /// in the declarations that affect a given rule.
814 /// FIXME(emilio): Eventually it'd be nice for this to become more
816 pub fn force_stylesheet_origins_dirty(&mut self, origins: OriginSet) {
817 self.stylesheets.force_dirty(origins)
820 /// Sets whether author style is enabled or not.
821 pub fn set_author_styles_enabled(&mut self, enabled: AuthorStylesEnabled) {
822 self.author_styles_enabled = enabled;
825 /// Returns whether we've recorded any stylesheet change so far.
826 pub fn stylesheets_have_changed(&self) -> bool {
827 self.stylesheets.has_changed()
830 /// Appends a new stylesheet to the current set.
831 pub fn append_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
833 .append_stylesheet(Some(&self.device), sheet, guard)
836 /// Remove a given stylesheet to the current set.
837 pub fn remove_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
839 .remove_stylesheet(Some(&self.device), sheet, guard)
842 /// Notify of a change of a given rule.
845 sheet: &StylistSheet,
847 guard: &SharedRwLockReadGuard,
848 change_kind: RuleChangeKind,
851 .rule_changed(Some(&self.device), sheet, rule, guard, change_kind)
854 /// Appends a new stylesheet to the current set.
856 pub fn sheet_count(&self, origin: Origin) -> usize {
857 self.stylesheets.sheet_count(origin)
860 /// Appends a new stylesheet to the current set.
862 pub fn sheet_at(&self, origin: Origin, index: usize) -> Option<&StylistSheet> {
863 self.stylesheets.get(origin, index)
866 /// Returns whether for any of the applicable style rule data a given
867 /// condition is true.
868 pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
871 F: FnMut(&CascadeData) -> bool,
873 if f(&self.cascade_data.user_agent.cascade_data) {
877 let mut maybe = false;
879 let doc_author_rules_apply =
880 element.each_applicable_non_document_style_rule_data(|data, _| {
881 maybe = maybe || f(&*data);
884 if maybe || f(&self.cascade_data.user) {
888 doc_author_rules_apply && f(&self.cascade_data.author)
891 /// Execute callback for all applicable style rule data.
892 pub fn for_each_cascade_data_with_scope<'a, E, F>(&'a self, element: E, mut f: F)
895 F: FnMut(&'a CascadeData, Option<E>),
897 f(&self.cascade_data.user_agent.cascade_data, None);
898 element.each_applicable_non_document_style_rule_data(|data, scope| {
899 f(data, Some(scope));
901 f(&self.cascade_data.user, None);
902 f(&self.cascade_data.author, None);
905 /// Computes the style for a given "precomputed" pseudo-element, taking the
906 /// universal rules and applying them.
907 pub fn precomputed_values_for_pseudo<E>(
909 guards: &StylesheetGuards,
910 pseudo: &PseudoElement,
911 parent: Option<&ComputedValues>,
912 ) -> Arc<ComputedValues>
916 debug_assert!(pseudo.is_precomputed());
918 let rule_node = self.rule_node_for_precomputed_pseudo(guards, pseudo, vec![]);
920 self.precomputed_values_for_pseudo_with_rule_node::<E>(guards, pseudo, parent, rule_node)
923 /// Computes the style for a given "precomputed" pseudo-element with
926 /// TODO(emilio): The type parameter could go away with a void type
927 /// implementing TElement.
928 pub fn precomputed_values_for_pseudo_with_rule_node<E>(
930 guards: &StylesheetGuards,
931 pseudo: &PseudoElement,
932 parent: Option<&ComputedValues>,
933 rules: StrongRuleNode,
934 ) -> Arc<ComputedValues>
938 self.compute_pseudo_element_style_with_inputs::<E>(
942 flags: Default::default(),
946 /* originating_element_style */ None,
952 /// Returns the rule node for a given precomputed pseudo-element.
954 /// If we want to include extra declarations to this precomputed
955 /// pseudo-element, we can provide a vector of ApplicableDeclarationBlocks
956 /// to extra_declarations. This is useful for @page rules.
957 pub fn rule_node_for_precomputed_pseudo(
959 guards: &StylesheetGuards,
960 pseudo: &PseudoElement,
961 mut extra_declarations: Vec<ApplicableDeclarationBlock>,
962 ) -> StrongRuleNode {
963 let mut declarations_with_extra;
964 let declarations = match self
967 .precomputed_pseudo_element_decls
970 Some(declarations) => {
971 if !extra_declarations.is_empty() {
972 declarations_with_extra = declarations.clone();
973 declarations_with_extra.append(&mut extra_declarations);
974 &*declarations_with_extra
982 self.rule_tree.insert_ordered_rules_with_important(
983 declarations.into_iter().map(|a| a.clone().for_rule_tree()),
988 /// Returns the style for an anonymous box of the given type.
990 /// TODO(emilio): The type parameter could go away with a void type
991 /// implementing TElement.
992 #[cfg(feature = "servo")]
993 pub fn style_for_anonymous<E>(
995 guards: &StylesheetGuards,
996 pseudo: &PseudoElement,
997 parent_style: &ComputedValues,
998 ) -> Arc<ComputedValues>
1002 self.precomputed_values_for_pseudo::<E>(guards, &pseudo, Some(parent_style))
1005 /// Computes a pseudo-element style lazily during layout.
1007 /// This can only be done for a certain set of pseudo-elements, like
1010 /// Check the documentation on lazy pseudo-elements in
1011 /// docs/components/style.md
1012 pub fn lazily_compute_pseudo_element_style<E>(
1014 guards: &StylesheetGuards,
1016 pseudo: &PseudoElement,
1017 rule_inclusion: RuleInclusion,
1018 originating_element_style: &ComputedValues,
1019 parent_style: &Arc<ComputedValues>,
1021 matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>,
1022 ) -> Option<Arc<ComputedValues>>
1026 let cascade_inputs = self.lazy_pseudo_rules(
1029 originating_element_style,
1037 Some(self.compute_pseudo_element_style_with_inputs(
1041 Some(originating_element_style),
1047 /// Computes a pseudo-element style lazily using the given CascadeInputs.
1048 /// This can be used for truly lazy pseudo-elements or to avoid redoing
1049 /// selector matching for eager pseudo-elements when we need to recompute
1050 /// their style with a new parent style.
1051 pub fn compute_pseudo_element_style_with_inputs<E>(
1053 inputs: CascadeInputs,
1054 pseudo: &PseudoElement,
1055 guards: &StylesheetGuards,
1056 originating_element_style: Option<&ComputedValues>,
1057 parent_style: Option<&ComputedValues>,
1059 ) -> Arc<ComputedValues>
1063 // FIXME(emilio): The lack of layout_parent_style here could be
1064 // worrying, but we're probably dropping the display fixup for
1065 // pseudos other than before and after, so it's probably ok.
1067 // (Though the flags don't indicate so!)
1069 // It'd be fine to assert that this isn't called with a parent style
1070 // where display contents is in effect, but in practice this is hard to
1071 // do for stuff like :-moz-fieldset-content with a
1072 // <fieldset style="display: contents">. That is, the computed value of
1073 // display for the fieldset is "contents", even though it's not the used
1074 // value, so we don't need to adjust in a different way anyway.
1075 self.cascade_style_and_visited(
1080 originating_element_style,
1083 FirstLineReparenting::No,
1084 /* rule_cache = */ None,
1085 &mut RuleCacheConditions::default(),
1089 /// Computes a style using the given CascadeInputs. This can be used to
1090 /// compute a style any time we know what rules apply and just need to use
1091 /// the given parent styles.
1093 /// parent_style is the style to inherit from for properties affected by
1094 /// first-line ancestors.
1096 /// parent_style_ignoring_first_line is the style to inherit from for
1097 /// properties not affected by first-line ancestors.
1099 /// layout_parent_style is the style used for some property fixups. It's
1100 /// the style of the nearest ancestor with a layout box.
1101 pub fn cascade_style_and_visited<E>(
1104 pseudo: Option<&PseudoElement>,
1105 inputs: CascadeInputs,
1106 guards: &StylesheetGuards,
1107 originating_element_style: Option<&ComputedValues>,
1108 parent_style: Option<&ComputedValues>,
1109 layout_parent_style: Option<&ComputedValues>,
1110 first_line_reparenting: FirstLineReparenting,
1111 rule_cache: Option<&RuleCache>,
1112 rule_cache_conditions: &mut RuleCacheConditions,
1113 ) -> Arc<ComputedValues>
1117 debug_assert!(pseudo.is_some() || element.is_some(), "Huh?");
1119 // We need to compute visited values if we have visited rules or if our
1120 // parent has visited values.
1121 let visited_rules = match inputs.visited_rules.as_ref() {
1122 Some(rules) => Some(rules),
1124 if parent_style.and_then(|s| s.visited_style()).is_some() {
1125 Some(inputs.rules.as_ref().unwrap_or(self.rule_tree.root()))
1132 // Read the comment on `precomputed_values_for_pseudo` to see why it's
1133 // difficult to assert that display: contents nodes never arrive here
1134 // (tl;dr: It doesn't apply for replaced elements and such, but the
1135 // computed value is still "contents").
1137 // FIXME(emilio): We should assert that it holds if pseudo.is_none()!
1138 properties::cascade::<E>(
1141 inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
1143 originating_element_style,
1145 layout_parent_style,
1146 first_line_reparenting,
1150 rule_cache_conditions,
1155 /// Computes the cascade inputs for a lazily-cascaded pseudo-element.
1157 /// See the documentation on lazy pseudo-elements in
1158 /// docs/components/style.md
1159 fn lazy_pseudo_rules<E>(
1161 guards: &StylesheetGuards,
1163 originating_element_style: &ComputedValues,
1164 parent_style: &Arc<ComputedValues>,
1165 pseudo: &PseudoElement,
1167 rule_inclusion: RuleInclusion,
1168 matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>,
1169 ) -> Option<CascadeInputs>
1173 debug_assert!(pseudo.is_lazy());
1175 let mut selector_caches = SelectorCaches::default();
1176 // No need to bother setting the selector flags when we're computing
1178 let needs_selector_flags = if rule_inclusion == RuleInclusion::DefaultOnly {
1179 NeedsSelectorFlags::No
1181 NeedsSelectorFlags::Yes
1184 let mut declarations = ApplicableDeclarationList::new();
1185 let mut matching_context = MatchingContext::<'_, E::Impl>::new(
1186 MatchingMode::ForStatelessPseudoElement,
1188 &mut selector_caches,
1190 needs_selector_flags,
1191 MatchingForInvalidation::No,
1194 matching_context.pseudo_element_matching_fn = matching_fn;
1195 matching_context.extra_data.originating_element_style = Some(originating_element_style);
1197 self.push_applicable_declarations(
1202 /* animation_declarations = */ Default::default(),
1205 &mut matching_context,
1208 if declarations.is_empty() && is_probe {
1212 let rules = self.rule_tree.compute_rule_node(&mut declarations, guards);
1214 let mut visited_rules = None;
1215 if parent_style.visited_style().is_some() {
1216 let mut declarations = ApplicableDeclarationList::new();
1217 let mut selector_caches = SelectorCaches::default();
1219 let mut matching_context = MatchingContext::<'_, E::Impl>::new_for_visited(
1220 MatchingMode::ForStatelessPseudoElement,
1222 &mut selector_caches,
1223 VisitedHandlingMode::RelevantLinkVisited,
1225 needs_selector_flags,
1226 MatchingForInvalidation::No,
1228 matching_context.pseudo_element_matching_fn = matching_fn;
1229 matching_context.extra_data.originating_element_style = Some(originating_element_style);
1231 self.push_applicable_declarations(
1236 /* animation_declarations = */ Default::default(),
1239 &mut matching_context,
1241 if !declarations.is_empty() {
1242 let rule_node = self.rule_tree.insert_ordered_rules_with_important(
1243 declarations.drain(..).map(|a| a.for_rule_tree()),
1246 if rule_node != *self.rule_tree.root() {
1247 visited_rules = Some(rule_node);
1252 Some(CascadeInputs {
1255 flags: matching_context.extra_data.cascade_input_flags,
1259 /// Set a given device, which may change the styles that apply to the
1262 /// Returns the sheet origins that were actually affected.
1264 /// This means that we may need to rebuild style data even if the
1265 /// stylesheets haven't changed.
1267 /// Also, the device that arrives here may need to take the viewport rules
1269 pub fn set_device(&mut self, device: Device, guards: &StylesheetGuards) -> OriginSet {
1270 self.device = device;
1271 self.media_features_change_changed_style(guards, &self.device)
1274 /// Returns whether, given a media feature change, any previously-applicable
1275 /// style has become non-applicable, or vice-versa for each origin, using
1277 pub fn media_features_change_changed_style(
1279 guards: &StylesheetGuards,
1282 debug!("Stylist::media_features_change_changed_style {:?}", device);
1284 let mut origins = OriginSet::empty();
1285 let stylesheets = self.stylesheets.iter();
1287 for (stylesheet, origin) in stylesheets {
1288 if origins.contains(origin.into()) {
1292 let guard = guards.for_origin(origin);
1293 let origin_cascade_data = self.cascade_data.borrow_for_origin(origin);
1295 let affected_changed = !origin_cascade_data.media_feature_affected_matches(
1302 if affected_changed {
1310 /// Returns the Quirks Mode of the document.
1311 pub fn quirks_mode(&self) -> QuirksMode {
1315 /// Sets the quirks mode of the document.
1316 pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
1317 if self.quirks_mode == quirks_mode {
1320 self.quirks_mode = quirks_mode;
1321 self.force_stylesheet_origins_dirty(OriginSet::all());
1324 /// Returns the applicable CSS declarations for the given element.
1325 pub fn push_applicable_declarations<E>(
1328 pseudo_element: Option<&PseudoElement>,
1329 style_attribute: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
1330 smil_override: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
1331 animation_declarations: AnimationDeclarations,
1332 rule_inclusion: RuleInclusion,
1333 applicable_declarations: &mut ApplicableDeclarationList,
1334 context: &mut MatchingContext<E::Impl>,
1344 animation_declarations,
1346 applicable_declarations,
1352 /// Given an id, returns whether there might be any rules for that id in any
1353 /// of our rule maps.
1355 pub fn may_have_rules_for_id<E>(&self, id: &WeakAtom, element: E) -> bool
1359 // If id needs to be compared case-insensitively, the logic below
1360 // wouldn't work. Just conservatively assume it may have such rules.
1361 match self.quirks_mode().classes_and_ids_case_sensitivity() {
1362 CaseSensitivity::AsciiCaseInsensitive => return true,
1363 CaseSensitivity::CaseSensitive => {},
1366 self.any_applicable_rule_data(element, |data| data.mapped_ids.contains(id))
1369 /// Returns the registered `@keyframes` animation for the specified name.
1371 pub fn get_animation<'a, E>(&'a self, name: &Atom, element: E) -> Option<&'a KeyframesAnimation>
1375 macro_rules! try_find_in {
1377 if let Some(animation) = $data.animations.get(name) {
1378 return Some(animation);
1383 // NOTE(emilio): This is a best-effort thing, the right fix is a bit TBD because it
1384 // involves "recording" which tree the name came from, see [1][2].
1386 // [1]: https://github.com/w3c/csswg-drafts/issues/1995
1387 // [2]: https://bugzil.la/1458189
1388 let mut animation = None;
1389 let doc_rules_apply = element.each_applicable_non_document_style_rule_data(|data, _host| {
1390 if animation.is_none() {
1391 animation = data.animations.get(name);
1395 if animation.is_some() {
1399 if doc_rules_apply {
1400 try_find_in!(self.cascade_data.author);
1402 try_find_in!(self.cascade_data.user);
1403 try_find_in!(self.cascade_data.user_agent.cascade_data);
1408 /// Computes the match results of a given element against the set of
1409 /// revalidation selectors.
1410 pub fn match_revalidation_selectors<E>(
1413 bloom: Option<&BloomFilter>,
1414 selector_caches: &mut SelectorCaches,
1415 needs_selector_flags: NeedsSelectorFlags,
1420 // NB: `MatchingMode` doesn't really matter, given we don't share style
1422 let mut matching_context = MatchingContext::new(
1423 MatchingMode::Normal,
1427 needs_selector_flags,
1428 MatchingForInvalidation::No,
1431 // Note that, by the time we're revalidating, we're guaranteed that the
1432 // candidate and the entry have the same id, classes, and local name.
1433 // This means we're guaranteed to get the same rulehash buckets for all
1434 // the lookups, which means that the bitvecs are comparable. We verify
1435 // this in the caller by asserting that the bitvecs are same-length.
1436 let mut results = SmallBitVec::new();
1438 let matches_document_rules =
1439 element.each_applicable_non_document_style_rule_data(|data, host| {
1440 matching_context.with_shadow_host(Some(host), |matching_context| {
1441 data.selectors_for_cache_revalidation.lookup(
1444 |selector_and_hashes| {
1445 results.push(matches_selector(
1446 &selector_and_hashes.selector,
1447 selector_and_hashes.selector_offset,
1448 Some(&selector_and_hashes.hashes),
1458 for (data, origin) in self.cascade_data.iter_origins() {
1459 if origin == Origin::Author && !matches_document_rules {
1463 data.selectors_for_cache_revalidation.lookup(
1466 |selector_and_hashes| {
1467 results.push(matches_selector(
1468 &selector_and_hashes.selector,
1469 selector_and_hashes.selector_offset,
1470 Some(&selector_and_hashes.hashes),
1472 &mut matching_context,
1482 /// Computes styles for a given declaration with parent_style.
1484 /// FIXME(emilio): the lack of pseudo / cascade flags look quite dubious,
1485 /// hopefully this is only used for some canvas font stuff.
1487 /// TODO(emilio): The type parameter can go away when
1488 /// https://github.com/rust-lang/rust/issues/35121 is fixed.
1489 pub fn compute_for_declarations<E>(
1491 guards: &StylesheetGuards,
1492 parent_style: &ComputedValues,
1493 declarations: Arc<Locked<PropertyDeclarationBlock>>,
1494 ) -> Arc<ComputedValues>
1498 let block = declarations.read_with(guards.author);
1500 // We don't bother inserting these declarations in the rule tree, since
1501 // it'd be quite useless and slow.
1503 // TODO(emilio): Now that we fixed bug 1493420, we should consider
1504 // reversing this as it shouldn't be slow anymore, and should avoid
1505 // generating two instantiations of apply_declarations.
1506 properties::apply_declarations::<E, _>(
1508 /* pseudo = */ None,
1509 self.rule_tree.root(),
1511 block.declaration_importance_iter().map(|(declaration, _)| {
1514 CascadePriority::new(
1515 CascadeLevel::same_tree_author_normal(),
1520 /* originating_element_style */ None,
1523 FirstLineReparenting::No,
1524 CascadeMode::Unvisited {
1525 visited_rules: None,
1528 /* rule_cache = */ None,
1529 &mut Default::default(),
1530 /* element = */ None,
1534 /// Accessor for a shared reference to the device.
1536 pub fn device(&self) -> &Device {
1540 /// Accessor for a mutable reference to the device.
1542 pub fn device_mut(&mut self) -> &mut Device {
1546 /// Accessor for a shared reference to the rule tree.
1548 pub fn rule_tree(&self) -> &RuleTree {
1552 /// Returns the script-registered custom property registry.
1554 pub fn custom_property_script_registry(&self) -> &CustomPropertyScriptRegistry {
1555 &self.script_custom_properties
1558 /// Returns the script-registered custom property registry, as a mutable ref.
1560 pub fn custom_property_script_registry_mut(&mut self) -> &mut CustomPropertyScriptRegistry {
1561 &mut self.script_custom_properties
1564 /// Measures heap usage.
1565 #[cfg(feature = "gecko")]
1566 pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
1567 self.cascade_data.add_size_of(ops, sizes);
1568 self.author_data_cache.add_size_of(ops, sizes);
1569 sizes.mRuleTree += self.rule_tree.size_of(ops);
1571 // We may measure other fields in the future if DMD says it's worth it.
1574 /// Shutdown the static data that this module stores.
1576 let _entries = UA_CASCADE_DATA_CACHE.lock().unwrap().take_all();
1580 /// A vector that is sorted in layer order.
1581 #[derive(Clone, Debug, Deref, MallocSizeOf)]
1582 pub struct LayerOrderedVec<T>(Vec<(T, LayerId)>);
1583 impl<T> Default for LayerOrderedVec<T> {
1584 fn default() -> Self {
1585 Self(Default::default())
1589 /// A map that is sorted in layer order.
1590 #[derive(Clone, Debug, Deref, MallocSizeOf)]
1591 pub struct LayerOrderedMap<T>(PrecomputedHashMap<Atom, SmallVec<[(T, LayerId); 1]>>);
1592 impl<T> Default for LayerOrderedMap<T> {
1593 fn default() -> Self {
1594 Self(Default::default())
1598 impl<T: 'static> LayerOrderedVec<T> {
1599 fn clear(&mut self) {
1602 fn push(&mut self, v: T, id: LayerId) {
1603 self.0.push((v, id));
1605 fn sort(&mut self, layers: &[CascadeLayer]) {
1607 .sort_by_key(|&(_, ref id)| layers[id.0 as usize].order)
1611 impl<T: 'static> LayerOrderedMap<T> {
1612 fn shrink_if_needed(&mut self) {
1613 self.0.shrink_if_needed();
1615 fn clear(&mut self) {
1618 fn try_insert(&mut self, name: Atom, v: T, id: LayerId) -> Result<(), AllocErr> {
1619 self.try_insert_with(name, v, id, |_, _| Ordering::Equal)
1626 cmp: impl Fn(&T, &T) -> Ordering,
1627 ) -> Result<(), AllocErr> {
1628 self.0.try_reserve(1)?;
1629 let vec = self.0.entry(name).or_default();
1630 if let Some(&mut (ref mut val, ref last_id)) = vec.last_mut() {
1632 if cmp(&val, &v) != Ordering::Greater {
1641 fn sort(&mut self, layers: &[CascadeLayer]) {
1642 self.sort_with(layers, |_, _| Ordering::Equal)
1644 fn sort_with(&mut self, layers: &[CascadeLayer], cmp: impl Fn(&T, &T) -> Ordering) {
1645 for (_, v) in self.0.iter_mut() {
1646 v.sort_by(|&(ref v1, ref id1), &(ref v2, ref id2)| {
1647 let order1 = layers[id1.0 as usize].order;
1648 let order2 = layers[id2.0 as usize].order;
1649 order1.cmp(&order2).then_with(|| cmp(v1, v2))
1653 /// Get an entry on the LayerOrderedMap by name.
1654 pub fn get(&self, name: &Atom) -> Option<&T> {
1655 let vec = self.0.get(name)?;
1656 Some(&vec.last()?.0)
1660 /// Wrapper to allow better tracking of memory usage by page rule lists.
1662 /// This includes the layer ID for use with the named page table.
1663 #[derive(Clone, Debug, MallocSizeOf)]
1664 pub struct PageRuleData {
1665 /// Layer ID for sorting page rules after matching.
1668 #[ignore_malloc_size_of = "Arc, stylesheet measures as primary ref"]
1669 pub rule: Arc<Locked<PageRule>>,
1672 /// Stores page rules indexed by page names.
1673 #[derive(Clone, Debug, Default, MallocSizeOf)]
1674 pub struct PageRuleMap {
1675 /// Page rules, indexed by page name. An empty atom indicates no page name.
1676 pub rules: PrecomputedHashMap<Atom, SmallVec<[PageRuleData; 1]>>,
1681 fn clear(&mut self) {
1685 /// Uses page-name and pseudo-classes to match all applicable
1686 /// page-rules and append them to the matched_rules vec.
1687 /// This will ensure correct rule order for cascading.
1688 pub fn match_and_append_rules(
1690 matched_rules: &mut Vec<ApplicableDeclarationBlock>,
1692 guards: &StylesheetGuards,
1693 cascade_data: &DocumentCascadeData,
1694 name: &Option<Atom>,
1695 pseudos: PagePseudoClassFlags,
1697 let level = match origin {
1698 Origin::UserAgent => CascadeLevel::UANormal,
1699 Origin::User => CascadeLevel::UserNormal,
1700 Origin::Author => CascadeLevel::same_tree_author_normal(),
1702 let cascade_data = cascade_data.borrow_for_origin(origin);
1703 let start = matched_rules.len();
1705 self.match_and_add_rules(matched_rules, level, guards, cascade_data, &atom!(""), pseudos);
1706 if let Some(name) = name {
1707 self.match_and_add_rules(matched_rules, level, guards, cascade_data, name, pseudos);
1710 // Because page-rules do not have source location information stored,
1711 // use stable sort to ensure source locations are preserved.
1712 matched_rules[start..].sort_by_key(|block| {
1713 (block.layer_order(), block.specificity, block.source_order())
1717 fn match_and_add_rules(
1719 extra_declarations: &mut Vec<ApplicableDeclarationBlock>,
1720 level: CascadeLevel,
1721 guards: &StylesheetGuards,
1722 cascade_data: &CascadeData,
1724 pseudos: PagePseudoClassFlags,
1726 let rules = match self.rules.get(name) {
1727 Some(rules) => rules,
1730 for data in rules.iter() {
1731 let rule = data.rule.read_with(level.guard(&guards));
1732 let specificity = match rule.match_specificity(pseudos) {
1733 Some(specificity) => specificity,
1736 let block = rule.block.clone();
1737 extra_declarations.push(ApplicableDeclarationBlock::new(
1738 StyleSource::from_declarations(block),
1742 cascade_data.layer_order_for(data.layer),
1748 impl MallocShallowSizeOf for PageRuleMap {
1749 fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1750 self.rules.shallow_size_of(ops)
1754 /// This struct holds data which users of Stylist may want to extract
1755 /// from stylesheets which can be done at the same time as updating.
1756 #[derive(Clone, Debug, Default)]
1757 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
1758 pub struct ExtraStyleData {
1759 /// A list of effective font-face rules and their origin.
1760 #[cfg(feature = "gecko")]
1761 pub font_faces: LayerOrderedVec<Arc<Locked<FontFaceRule>>>,
1763 /// A list of effective font-feature-values rules.
1764 #[cfg(feature = "gecko")]
1765 pub font_feature_values: LayerOrderedVec<Arc<FontFeatureValuesRule>>,
1767 /// A list of effective font-palette-values rules.
1768 #[cfg(feature = "gecko")]
1769 pub font_palette_values: LayerOrderedVec<Arc<FontPaletteValuesRule>>,
1771 /// A map of effective counter-style rules.
1772 #[cfg(feature = "gecko")]
1773 pub counter_styles: LayerOrderedMap<Arc<Locked<CounterStyleRule>>>,
1775 /// A map of effective page rules.
1776 #[cfg(feature = "gecko")]
1777 pub pages: PageRuleMap,
1780 #[cfg(feature = "gecko")]
1781 impl ExtraStyleData {
1782 /// Add the given @font-face rule.
1783 fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>, layer: LayerId) {
1784 self.font_faces.push(rule.clone(), layer);
1787 /// Add the given @font-feature-values rule.
1788 fn add_font_feature_values(&mut self, rule: &Arc<FontFeatureValuesRule>, layer: LayerId) {
1789 self.font_feature_values.push(rule.clone(), layer);
1792 /// Add the given @font-palette-values rule.
1793 fn add_font_palette_values(&mut self, rule: &Arc<FontPaletteValuesRule>, layer: LayerId) {
1794 self.font_palette_values.push(rule.clone(), layer);
1797 /// Add the given @counter-style rule.
1798 fn add_counter_style(
1800 guard: &SharedRwLockReadGuard,
1801 rule: &Arc<Locked<CounterStyleRule>>,
1803 ) -> Result<(), AllocErr> {
1804 let name = rule.read_with(guard).name().0.clone();
1805 self.counter_styles.try_insert(name, rule.clone(), layer)
1808 /// Add the given @page rule.
1811 guard: &SharedRwLockReadGuard,
1812 rule: &Arc<Locked<PageRule>>,
1814 ) -> Result<(), AllocErr> {
1815 let page_rule = rule.read_with(guard);
1816 let mut add_rule = |name| {
1817 let vec = self.pages.rules.entry(name).or_default();
1818 vec.push(PageRuleData{layer, rule: rule.clone()});
1820 if page_rule.selectors.0.is_empty() {
1821 add_rule(atom!(""));
1823 for selector in page_rule.selectors.as_slice() {
1824 add_rule(selector.name.0.clone());
1830 fn sort_by_layer(&mut self, layers: &[CascadeLayer]) {
1831 self.font_faces.sort(layers);
1832 self.font_feature_values.sort(layers);
1833 self.font_palette_values.sort(layers);
1834 self.counter_styles.sort(layers);
1837 fn clear(&mut self) {
1838 #[cfg(feature = "gecko")]
1840 self.font_faces.clear();
1841 self.font_feature_values.clear();
1842 self.font_palette_values.clear();
1843 self.counter_styles.clear();
1849 // Don't let a prefixed keyframes animation override
1850 // a non-prefixed one.
1851 fn compare_keyframes_in_same_layer(v1: &KeyframesAnimation, v2: &KeyframesAnimation) -> Ordering {
1852 if v1.vendor_prefix.is_some() == v2.vendor_prefix.is_some() {
1854 } else if v2.vendor_prefix.is_some() {
1861 /// An iterator over the different ExtraStyleData.
1862 pub struct ExtraStyleDataIterator<'a>(DocumentCascadeDataIter<'a>);
1864 impl<'a> Iterator for ExtraStyleDataIterator<'a> {
1865 type Item = (&'a ExtraStyleData, Origin);
1867 fn next(&mut self) -> Option<Self::Item> {
1868 self.0.next().map(|d| (&d.0.extra_data, d.1))
1872 #[cfg(feature = "gecko")]
1873 impl MallocSizeOf for ExtraStyleData {
1874 /// Measure heap usage.
1875 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1877 n += self.font_faces.shallow_size_of(ops);
1878 n += self.font_feature_values.shallow_size_of(ops);
1879 n += self.font_palette_values.shallow_size_of(ops);
1880 n += self.counter_styles.shallow_size_of(ops);
1881 n += self.pages.shallow_size_of(ops);
1886 /// SelectorMapEntry implementation for use in our revalidation selector map.
1887 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
1888 #[derive(Clone, Debug)]
1889 struct RevalidationSelectorAndHashes {
1892 ignore_malloc_size_of = "CssRules have primary refs, we measure there"
1894 selector: Selector<SelectorImpl>,
1895 selector_offset: usize,
1896 hashes: AncestorHashes,
1899 impl RevalidationSelectorAndHashes {
1900 fn new(selector: Selector<SelectorImpl>, hashes: AncestorHashes) -> Self {
1901 let selector_offset = {
1902 // We basically want to check whether the first combinator is a
1903 // pseudo-element combinator. If it is, we want to use the offset
1904 // one past it. Otherwise, our offset is 0.
1906 let mut iter = selector.iter();
1908 // First skip over the first ComplexSelector.
1910 // We can't check what sort of what combinator we have until we do
1912 for _ in &mut iter {
1913 index += 1; // Simple selector
1916 match iter.next_sequence() {
1917 Some(Combinator::PseudoElement) => index + 1, // +1 for the combinator
1922 RevalidationSelectorAndHashes {
1930 impl SelectorMapEntry for RevalidationSelectorAndHashes {
1931 fn selector(&self) -> SelectorIter<SelectorImpl> {
1932 self.selector.iter_from(self.selector_offset)
1936 /// A selector visitor implementation that collects all the state the Stylist
1937 /// cares about a selector.
1938 struct StylistSelectorVisitor<'a> {
1939 /// Whether we've past the rightmost compound selector, not counting
1940 /// pseudo-elements.
1941 passed_rightmost_selector: bool,
1943 /// Whether the selector needs revalidation for the style sharing cache.
1944 needs_revalidation: &'a mut bool,
1946 /// Flags for which selector list-containing components the visitor is
1947 /// inside of, if any
1948 in_selector_list_of: SelectorListKind,
1950 /// The filter with all the id's getting referenced from rightmost
1952 mapped_ids: &'a mut PrecomputedHashSet<Atom>,
1954 /// The filter with the IDs getting referenced from the selector list of
1955 /// :nth-child(... of <selector list>) selectors.
1956 nth_of_mapped_ids: &'a mut PrecomputedHashSet<Atom>,
1958 /// The filter with the local names of attributes there are selectors for.
1959 attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>,
1961 /// The filter with the classes getting referenced from the selector list of
1962 /// :nth-child(... of <selector list>) selectors.
1963 nth_of_class_dependencies: &'a mut PrecomputedHashSet<Atom>,
1965 /// The filter with the local names of attributes there are selectors for
1966 /// within the selector list of :nth-child(... of <selector list>)
1968 nth_of_attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>,
1970 /// All the states selectors in the page reference.
1971 state_dependencies: &'a mut ElementState,
1973 /// All the state selectors in the page reference within the selector list
1974 /// of :nth-child(... of <selector list>) selectors.
1975 nth_of_state_dependencies: &'a mut ElementState,
1977 /// All the document states selectors in the page reference.
1978 document_state_dependencies: &'a mut DocumentState,
1981 fn component_needs_revalidation(
1982 c: &Component<SelectorImpl>,
1983 passed_rightmost_selector: bool,
1986 Component::ID(_) => {
1987 // TODO(emilio): This could also check that the ID is not already in
1988 // the rule hash. In that case, we could avoid making this a
1989 // revalidation selector too.
1991 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1369611
1992 passed_rightmost_selector
1994 Component::AttributeInNoNamespaceExists { .. } |
1995 Component::AttributeInNoNamespace { .. } |
1996 Component::AttributeOther(_) |
1999 Component::NthOf(_) => true,
2000 Component::NonTSPseudoClass(ref p) => p.needs_cache_revalidation(),
2005 impl<'a> StylistSelectorVisitor<'a> {
2006 fn visit_nested_selector(
2008 in_selector_list_of: SelectorListKind,
2009 selector: &Selector<SelectorImpl>
2011 let old_passed_rightmost_selector = self.passed_rightmost_selector;
2012 let old_in_selector_list_of = self.in_selector_list_of;
2014 self.passed_rightmost_selector = false;
2015 self.in_selector_list_of = in_selector_list_of;
2016 let _ret = selector.visit(self);
2017 debug_assert!(_ret, "We never return false");
2019 self.passed_rightmost_selector = old_passed_rightmost_selector;
2020 self.in_selector_list_of = old_in_selector_list_of;
2024 impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
2025 type Impl = SelectorImpl;
2027 fn visit_complex_selector(&mut self, combinator: Option<Combinator>) -> bool {
2028 *self.needs_revalidation =
2029 *self.needs_revalidation || combinator.map_or(false, |c| c.is_sibling());
2031 // NOTE(emilio): this call happens before we visit any of the simple
2032 // selectors in the next ComplexSelector, so we can use this to skip
2034 self.passed_rightmost_selector = self.passed_rightmost_selector ||
2035 !matches!(combinator, None | Some(Combinator::PseudoElement));
2040 fn visit_selector_list(
2042 list_kind: SelectorListKind,
2043 list: &[Selector<Self::Impl>],
2045 let in_selector_list_of = self.in_selector_list_of | list_kind;
2046 for selector in list {
2047 self.visit_nested_selector(in_selector_list_of, selector);
2052 fn visit_relative_selector_list(
2054 list: &[selectors::parser::RelativeSelector<Self::Impl>],
2056 let in_selector_list_of = self.in_selector_list_of | SelectorListKind::HAS;
2057 for selector in list {
2058 self.visit_nested_selector(in_selector_list_of, &selector.selector);
2063 fn visit_attribute_selector(
2065 _ns: &NamespaceConstraint<&Namespace>,
2067 lower_name: &LocalName,
2069 if self.in_selector_list_of.relevant_to_nth_of_dependencies() {
2070 self.nth_of_attribute_dependencies.insert(name.clone());
2071 if name != lower_name {
2072 self.nth_of_attribute_dependencies
2073 .insert(lower_name.clone());
2077 self.attribute_dependencies.insert(name.clone());
2078 if name != lower_name {
2079 self.attribute_dependencies.insert(lower_name.clone());
2085 fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
2086 *self.needs_revalidation = *self.needs_revalidation ||
2087 component_needs_revalidation(s, self.passed_rightmost_selector);
2090 Component::NonTSPseudoClass(ref p) => {
2091 self.state_dependencies.insert(p.state_flag());
2092 self.document_state_dependencies
2093 .insert(p.document_state_flag());
2095 if self.in_selector_list_of.relevant_to_nth_of_dependencies() {
2096 self.nth_of_state_dependencies.insert(p.state_flag());
2099 Component::ID(ref id) => {
2100 // We want to stop storing mapped ids as soon as we've moved off
2101 // the rightmost ComplexSelector that is not a pseudo-element.
2103 // That can be detected by a visit_complex_selector call with a
2104 // combinator other than None and PseudoElement.
2106 // Importantly, this call happens before we visit any of the
2107 // simple selectors in that ComplexSelector.
2109 // NOTE(emilio): See the comment regarding on when this may
2110 // break in visit_complex_selector.
2111 if !self.passed_rightmost_selector {
2112 self.mapped_ids.insert(id.0.clone());
2115 if self.in_selector_list_of.relevant_to_nth_of_dependencies() {
2116 self.nth_of_mapped_ids.insert(id.0.clone());
2119 Component::Class(ref class)
2120 if self.in_selector_list_of.relevant_to_nth_of_dependencies() =>
2122 self.nth_of_class_dependencies.insert(class.0.clone());
2131 /// A set of rules for element and pseudo-elements.
2132 #[derive(Clone, Debug, Default, MallocSizeOf)]
2133 struct GenericElementAndPseudoRules<Map> {
2134 /// Rules from stylesheets at this `CascadeData`'s origin.
2137 /// Rules from stylesheets at this `CascadeData`'s origin that correspond
2138 /// to a given pseudo-element.
2140 /// FIXME(emilio): There are a bunch of wasted entries here in practice.
2141 /// Figure out a good way to do a `PerNonAnonBox` and `PerAnonBox` (for
2142 /// `precomputed_values_for_pseudo`) without duplicating a lot of code.
2143 pseudos_map: PerPseudoElementMap<Box<Map>>,
2146 impl<Map: Default + MallocSizeOf> GenericElementAndPseudoRules<Map> {
2148 fn for_insertion(&mut self, pseudo_element: Option<&PseudoElement>) -> &mut Map {
2150 pseudo_element.map_or(true, |pseudo| {
2151 !pseudo.is_precomputed() && !pseudo.is_unknown_webkit_pseudo_element()
2153 "Precomputed pseudos should end up in precomputed_pseudo_element_decls, \
2154 and unknown webkit pseudos should be discarded before getting here"
2157 match pseudo_element {
2158 None => &mut self.element_map,
2159 Some(pseudo) => self
2161 .get_or_insert_with(pseudo, || Box::new(Default::default())),
2166 fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&Map> {
2168 Some(pseudo) => self.pseudos_map.get(pseudo).map(|p| &**p),
2169 None => Some(&self.element_map),
2173 /// Measures heap usage.
2174 #[cfg(feature = "gecko")]
2175 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
2176 sizes.mElementAndPseudosMaps += self.element_map.size_of(ops);
2178 for elem in self.pseudos_map.iter() {
2179 if let Some(ref elem) = *elem {
2180 sizes.mElementAndPseudosMaps += <Box<_> as MallocSizeOf>::size_of(elem, ops);
2186 type ElementAndPseudoRules = GenericElementAndPseudoRules<SelectorMap<Rule>>;
2187 type PartMap = PrecomputedHashMap<Atom, SmallVec<[Rule; 1]>>;
2188 type PartElementAndPseudoRules = GenericElementAndPseudoRules<PartMap>;
2190 impl ElementAndPseudoRules {
2191 // TODO(emilio): Should we retain storage of these?
2192 fn clear(&mut self) {
2193 self.element_map.clear();
2194 self.pseudos_map.clear();
2197 fn shrink_if_needed(&mut self) {
2198 self.element_map.shrink_if_needed();
2199 for pseudo in self.pseudos_map.iter_mut() {
2200 if let Some(ref mut pseudo) = pseudo {
2201 pseudo.shrink_if_needed();
2207 impl PartElementAndPseudoRules {
2208 // TODO(emilio): Should we retain storage of these?
2209 fn clear(&mut self) {
2210 self.element_map.clear();
2211 self.pseudos_map.clear();
2215 /// The id of a given layer, a sequentially-increasing identifier.
2216 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
2217 pub struct LayerId(u16);
2220 /// The id of the root layer.
2221 pub const fn root() -> Self {
2226 #[derive(Clone, Debug, MallocSizeOf)]
2227 struct CascadeLayer {
2230 children: Vec<LayerId>,
2234 const fn root() -> Self {
2236 id: LayerId::root(),
2237 order: LayerOrder::root(),
2243 /// The id of a given container condition, a sequentially-increasing identifier
2244 /// for a given style set.
2245 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
2246 pub struct ContainerConditionId(u16);
2248 impl ContainerConditionId {
2249 /// A special id that represents no container rule all.
2250 pub const fn none() -> Self {
2255 #[derive(Clone, Debug, MallocSizeOf)]
2256 struct ContainerConditionReference {
2257 parent: ContainerConditionId,
2258 #[ignore_malloc_size_of = "Arc"]
2259 condition: Option<Arc<ContainerCondition>>,
2262 impl ContainerConditionReference {
2263 const fn none() -> Self {
2265 parent: ContainerConditionId::none(),
2271 /// Data resulting from performing the CSS cascade that is specific to a given
2274 /// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
2275 /// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
2276 #[derive(Debug, Clone, MallocSizeOf)]
2277 pub struct CascadeData {
2278 /// The data coming from normal style rules that apply to elements at this
2280 normal_rules: ElementAndPseudoRules,
2282 /// The `:host` pseudo rules that are the rightmost selector (without
2283 /// accounting for pseudo-elements).
2284 host_rules: Option<Box<ElementAndPseudoRules>>,
2286 /// The data coming from ::slotted() pseudo-element rules.
2288 /// We need to store them separately because an element needs to match
2289 /// ::slotted() pseudo-element rules in different shadow roots.
2291 /// In particular, we need to go through all the style data in all the
2292 /// containing style scopes starting from the closest assigned slot.
2293 slotted_rules: Option<Box<ElementAndPseudoRules>>,
2295 /// The data coming from ::part() pseudo-element rules.
2297 /// We need to store them separately because an element needs to match
2298 /// ::part() pseudo-element rules in different shadow roots.
2299 part_rules: Option<Box<PartElementAndPseudoRules>>,
2301 /// The invalidation map for these rules.
2302 invalidation_map: InvalidationMap,
2304 /// The relative selector equivalent of the invalidation map.
2305 relative_selector_invalidation_map: RelativeSelectorInvalidationMap,
2307 /// The attribute local names that appear in attribute selectors. Used
2308 /// to avoid taking element snapshots when an irrelevant attribute changes.
2309 /// (We don't bother storing the namespace, since namespaced attributes are
2311 attribute_dependencies: PrecomputedHashSet<LocalName>,
2313 /// The classes that appear in the selector list of
2314 /// :nth-child(... of <selector list>). Used to avoid restyling siblings of
2315 /// an element when an irrelevant class changes.
2316 nth_of_class_dependencies: PrecomputedHashSet<Atom>,
2318 /// The attributes that appear in the selector list of
2319 /// :nth-child(... of <selector list>). Used to avoid restyling siblings of
2320 /// an element when an irrelevant attribute changes.
2321 nth_of_attribute_dependencies: PrecomputedHashSet<LocalName>,
2323 /// The element state bits that are relied on by selectors. Like
2324 /// `attribute_dependencies`, this is used to avoid taking element snapshots
2325 /// when an irrelevant element state bit changes.
2326 state_dependencies: ElementState,
2328 /// The element state bits that are relied on by selectors that appear in
2329 /// the selector list of :nth-child(... of <selector list>).
2330 nth_of_state_dependencies: ElementState,
2332 /// The document state bits that are relied on by selectors. This is used
2333 /// to tell whether we need to restyle the entire document when a document
2334 /// state bit changes.
2335 document_state_dependencies: DocumentState,
2337 /// The ids that appear in the rightmost complex selector of selectors (and
2338 /// hence in our selector maps). Used to determine when sharing styles is
2339 /// safe: we disallow style sharing for elements whose id matches this
2340 /// filter, and hence might be in one of our selector maps.
2341 mapped_ids: PrecomputedHashSet<Atom>,
2343 /// The IDs that appear in the selector list of
2344 /// :nth-child(... of <selector list>). Used to avoid restyling siblings
2345 /// of an element when an irrelevant ID changes.
2346 nth_of_mapped_ids: PrecomputedHashSet<Atom>,
2348 /// Selectors that require explicit cache revalidation (i.e. which depend
2349 /// on state that is not otherwise visible to the cache, like attributes or
2350 /// tree-structural state like child index and pseudos).
2351 #[ignore_malloc_size_of = "Arc"]
2352 selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
2354 /// A map with all the animations at this `CascadeData`'s origin, indexed
2356 animations: LayerOrderedMap<KeyframesAnimation>,
2358 /// A map with all the layer-ordered registrations from style at this `CascadeData`'s origin,
2359 /// indexed by name.
2360 custom_property_registrations: LayerOrderedMap<PropertyRegistration>,
2362 /// A map from cascade layer name to layer order.
2363 layer_id: FxHashMap<LayerName, LayerId>,
2365 /// The list of cascade layers, indexed by their layer id.
2366 layers: SmallVec<[CascadeLayer; 1]>,
2368 /// The list of container conditions, indexed by their id.
2369 container_conditions: SmallVec<[ContainerConditionReference; 1]>,
2371 /// Effective media query results cached from the last rebuild.
2372 effective_media_query_results: EffectiveMediaQueryResults,
2374 /// Extra data, like different kinds of rules, etc.
2375 extra_data: ExtraStyleData,
2377 /// A monotonically increasing counter to represent the order on which a
2378 /// style rule appears in a stylesheet, needed to sort them by source order.
2379 rules_source_order: u32,
2381 /// The total number of selectors.
2382 num_selectors: usize,
2384 /// The total number of declarations.
2385 num_declarations: usize,
2389 /// Creates an empty `CascadeData`.
2390 pub fn new() -> Self {
2392 normal_rules: ElementAndPseudoRules::default(),
2394 slotted_rules: None,
2396 invalidation_map: InvalidationMap::new(),
2397 relative_selector_invalidation_map: RelativeSelectorInvalidationMap::new(),
2398 nth_of_mapped_ids: PrecomputedHashSet::default(),
2399 nth_of_class_dependencies: PrecomputedHashSet::default(),
2400 nth_of_attribute_dependencies: PrecomputedHashSet::default(),
2401 nth_of_state_dependencies: ElementState::empty(),
2402 attribute_dependencies: PrecomputedHashSet::default(),
2403 state_dependencies: ElementState::empty(),
2404 document_state_dependencies: DocumentState::empty(),
2405 mapped_ids: PrecomputedHashSet::default(),
2406 // NOTE: We disable attribute bucketing for revalidation because we
2407 // rely on the buckets to match, but we don't want to just not share
2408 // style across elements with different attributes.
2410 // An alternative to this would be to perform a style sharing check
2411 // like may_match_different_id_rules which would check that the
2412 // attribute buckets match on all scopes. But that seems
2414 selectors_for_cache_revalidation: SelectorMap::new_without_attribute_bucketing(),
2415 animations: Default::default(),
2416 custom_property_registrations: Default::default(),
2417 layer_id: Default::default(),
2418 layers: smallvec::smallvec![CascadeLayer::root()],
2419 container_conditions: smallvec::smallvec![ContainerConditionReference::none()],
2420 extra_data: ExtraStyleData::default(),
2421 effective_media_query_results: EffectiveMediaQueryResults::new(),
2422 rules_source_order: 0,
2424 num_declarations: 0,
2428 /// Rebuild the cascade data from a given SheetCollection, incrementally if
2430 pub fn rebuild<'a, S>(
2433 quirks_mode: QuirksMode,
2434 collection: SheetCollectionFlusher<S>,
2435 guard: &SharedRwLockReadGuard,
2436 ) -> Result<(), AllocErr>
2438 S: StylesheetInDocument + PartialEq + 'static,
2440 if !collection.dirty() {
2444 let validity = collection.data_validity();
2447 DataValidity::Valid => {},
2448 DataValidity::CascadeInvalid => self.clear_cascade_data(),
2449 DataValidity::FullyInvalid => self.clear(),
2452 let mut result = Ok(());
2454 collection.each(|stylesheet, rebuild_kind| {
2455 result = self.add_stylesheet(
2461 /* precomputed_pseudo_element_decls = */ None,
2466 self.did_finish_rebuild();
2471 /// Returns the invalidation map.
2472 pub fn invalidation_map(&self) -> &InvalidationMap {
2473 &self.invalidation_map
2476 /// Returns the relative selector invalidation map.
2477 pub fn relative_selector_invalidation_map(&self) -> &RelativeSelectorInvalidationMap {
2478 &self.relative_selector_invalidation_map
2481 /// Returns whether the given ElementState bit is relied upon by a selector
2484 pub fn has_state_dependency(&self, state: ElementState) -> bool {
2485 self.state_dependencies.intersects(state)
2488 /// Returns whether the given ElementState bit is relied upon by a selector
2489 /// of some rule in the selector list of :nth-child(... of <selector list>).
2491 pub fn has_nth_of_state_dependency(&self, state: ElementState) -> bool {
2492 self.nth_of_state_dependencies.intersects(state)
2495 /// Returns whether the given attribute might appear in an attribute
2496 /// selector of some rule.
2498 pub fn might_have_attribute_dependency(&self, local_name: &LocalName) -> bool {
2499 self.attribute_dependencies.contains(local_name)
2502 /// Returns whether the given ID might appear in an ID selector in the
2503 /// selector list of :nth-child(... of <selector list>).
2505 pub fn might_have_nth_of_id_dependency(&self, id: &Atom) -> bool {
2506 self.nth_of_mapped_ids.contains(id)
2509 /// Returns whether the given class might appear in a class selector in the
2510 /// selector list of :nth-child(... of <selector list>).
2512 pub fn might_have_nth_of_class_dependency(&self, class: &Atom) -> bool {
2513 self.nth_of_class_dependencies.contains(class)
2516 /// Returns whether the given attribute might appear in an attribute
2517 /// selector in the selector list of :nth-child(... of <selector list>).
2519 pub fn might_have_nth_of_attribute_dependency(&self, local_name: &LocalName) -> bool {
2520 self.nth_of_attribute_dependencies.contains(local_name)
2523 /// Returns the normal rule map for a given pseudo-element.
2525 pub fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
2526 self.normal_rules.rules(pseudo)
2529 /// Returns the host pseudo rule map for a given pseudo-element.
2531 pub fn host_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
2532 self.host_rules.as_ref().and_then(|d| d.rules(pseudo))
2535 /// Whether there's any host rule that could match in this scope.
2536 pub fn any_host_rules(&self) -> bool {
2537 self.host_rules.is_some()
2540 /// Returns the slotted rule map for a given pseudo-element.
2542 pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
2543 self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo))
2546 /// Whether there's any ::slotted rule that could match in this scope.
2547 pub fn any_slotted_rule(&self) -> bool {
2548 self.slotted_rules.is_some()
2551 /// Returns the parts rule map for a given pseudo-element.
2553 pub fn part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap> {
2554 self.part_rules.as_ref().and_then(|d| d.rules(pseudo))
2557 /// Whether there's any ::part rule that could match in this scope.
2558 pub fn any_part_rule(&self) -> bool {
2559 self.part_rules.is_some()
2563 fn layer_order_for(&self, id: LayerId) -> LayerOrder {
2564 self.layers[id.0 as usize].order
2567 pub(crate) fn container_condition_matches<E>(
2569 mut id: ContainerConditionId,
2572 context: &mut MatchingContext<E::Impl>,
2578 let condition_ref = &self.container_conditions[id.0 as usize];
2579 let condition = match condition_ref.condition {
2580 None => return true,
2583 let matches = condition
2587 context.extra_data.originating_element_style,
2588 &mut context.extra_data.cascade_input_flags,
2590 .to_bool(/* unknown = */ false);
2594 id = condition_ref.parent;
2598 fn did_finish_rebuild(&mut self) {
2599 self.shrink_maps_if_needed();
2600 self.compute_layer_order();
2603 fn shrink_maps_if_needed(&mut self) {
2604 self.normal_rules.shrink_if_needed();
2605 if let Some(ref mut host_rules) = self.host_rules {
2606 host_rules.shrink_if_needed();
2608 if let Some(ref mut slotted_rules) = self.slotted_rules {
2609 slotted_rules.shrink_if_needed();
2611 self.animations.shrink_if_needed();
2612 self.custom_property_registrations.shrink_if_needed();
2613 self.invalidation_map.shrink_if_needed();
2614 self.relative_selector_invalidation_map.shrink_if_needed();
2615 self.attribute_dependencies.shrink_if_needed();
2616 self.nth_of_attribute_dependencies.shrink_if_needed();
2617 self.nth_of_class_dependencies.shrink_if_needed();
2618 self.nth_of_mapped_ids.shrink_if_needed();
2619 self.mapped_ids.shrink_if_needed();
2620 self.layer_id.shrink_if_needed();
2621 self.selectors_for_cache_revalidation.shrink_if_needed();
2624 fn compute_layer_order(&mut self) {
2628 "There should be at least the root layer!"
2630 if self.layers.len() == 1 {
2631 return; // Nothing to do
2633 let (first, remaining) = self.layers.split_at_mut(1);
2634 let root = &mut first[0];
2635 let mut order = LayerOrder::first();
2636 compute_layer_order_for_subtree(root, remaining, &mut order);
2638 // NOTE(emilio): This is a bit trickier than it should to avoid having
2639 // to clone() around layer indices.
2640 fn compute_layer_order_for_subtree(
2641 parent: &mut CascadeLayer,
2642 remaining_layers: &mut [CascadeLayer],
2643 order: &mut LayerOrder,
2645 for child in parent.children.iter() {
2648 "Children are always registered after parents"
2650 let child_index = (child.0 - parent.id.0 - 1) as usize;
2651 let (first, remaining) = remaining_layers.split_at_mut(child_index + 1);
2652 let child = &mut first[child_index];
2653 compute_layer_order_for_subtree(child, remaining, order);
2656 if parent.id != LayerId::root() {
2657 parent.order = *order;
2661 self.extra_data.sort_by_layer(&self.layers);
2663 .sort_with(&self.layers, compare_keyframes_in_same_layer);
2664 self.custom_property_registrations.sort(&self.layers)
2667 /// Collects all the applicable media query results into `results`.
2669 /// This duplicates part of the logic in `add_stylesheet`, which is
2670 /// a bit unfortunate.
2672 /// FIXME(emilio): With a bit of smartness in
2673 /// `media_feature_affected_matches`, we could convert
2674 /// `EffectiveMediaQueryResults` into a vector without too much effort.
2675 fn collect_applicable_media_query_results_into<S>(
2678 guard: &SharedRwLockReadGuard,
2679 results: &mut Vec<MediaListKey>,
2680 contents_list: &mut StyleSheetContentList,
2682 S: StylesheetInDocument + 'static,
2684 if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
2688 debug!(" + {:?}", stylesheet);
2689 let contents = stylesheet.contents();
2690 results.push(contents.to_media_list_key());
2692 // Safety: StyleSheetContents are reference-counted with Arc.
2693 contents_list.push(StylesheetContentsPtr(unsafe {
2694 Arc::from_raw_addrefed(contents)
2697 for rule in stylesheet.effective_rules(device, guard) {
2699 CssRule::Import(ref lock) => {
2700 let import_rule = lock.read_with(guard);
2701 debug!(" + {:?}", import_rule.stylesheet.media(guard));
2702 results.push(import_rule.to_media_list_key());
2704 CssRule::Media(ref media_rule) => {
2705 debug!(" + {:?}", media_rule.media_queries.read_with(guard));
2706 results.push(media_rule.to_media_list_key());
2713 fn add_rule_list<'a, S>(
2715 rules: std::slice::Iter<'a, CssRule>,
2717 quirks_mode: QuirksMode,
2719 guard: &'a SharedRwLockReadGuard,
2720 rebuild_kind: SheetRebuildKind,
2721 containing_rule_state: &mut ContainingRuleState<'a>,
2722 mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
2723 ) -> Result<(), AllocErr>
2725 S: StylesheetInDocument + 'static,
2728 // Handle leaf rules first, as those are by far the most common
2729 // ones, and are always effective, so we can skip some checks.
2730 let mut handled = true;
2731 let mut selectors_for_nested_rules = None;
2733 CssRule::Style(ref locked) => {
2734 let style_rule = locked.read_with(guard);
2735 self.num_declarations += style_rule.block.read_with(&guard).len();
2737 let has_nested_rules = style_rule.rules.is_some();
2738 let mut ancestor_selectors = containing_rule_state.ancestor_selector_lists.last_mut();
2739 if has_nested_rules {
2740 selectors_for_nested_rules = Some(if ancestor_selectors.is_some() {
2741 Cow::Owned(SelectorList(Default::default()))
2743 Cow::Borrowed(&style_rule.selectors)
2747 for selector in &style_rule.selectors.0 {
2748 self.num_selectors += 1;
2750 let pseudo_element = selector.pseudo_element();
2751 if let Some(pseudo) = pseudo_element {
2752 if pseudo.is_precomputed() {
2753 debug_assert!(selector.is_universal());
2754 debug_assert!(ancestor_selectors.is_none());
2755 debug_assert!(!has_nested_rules);
2756 debug_assert_eq!(stylesheet.contents().origin, Origin::UserAgent);
2757 debug_assert_eq!(containing_rule_state.layer_id, LayerId::root());
2759 precomputed_pseudo_element_decls
2761 .expect("Expected precomputed declarations for the UA level")
2762 .get_or_insert_with(pseudo, Vec::new)
2763 .push(ApplicableDeclarationBlock::new(
2764 StyleSource::from_rule(locked.clone()),
2765 self.rules_source_order,
2766 CascadeLevel::UANormal,
2767 selector.specificity(),
2772 if pseudo.is_unknown_webkit_pseudo_element() {
2777 let selector = match ancestor_selectors {
2778 Some(ref mut s) => selector.replace_parent_selector(&s.into_shared()),
2779 None => selector.clone(),
2782 let hashes = AncestorHashes::new(&selector, quirks_mode);
2784 let rule = Rule::new(
2788 self.rules_source_order,
2789 containing_rule_state.layer_id,
2790 containing_rule_state.container_condition_id,
2793 if let Some(Cow::Owned(ref mut nested_selectors)) =
2794 selectors_for_nested_rules
2796 nested_selectors.0.push(rule.selector.clone())
2799 if rebuild_kind.should_rebuild_invalidation() {
2800 note_selector_for_invalidation(
2803 &mut self.invalidation_map,
2804 &mut self.relative_selector_invalidation_map,
2806 let mut needs_revalidation = false;
2807 let mut visitor = StylistSelectorVisitor {
2808 needs_revalidation: &mut needs_revalidation,
2809 passed_rightmost_selector: false,
2810 in_selector_list_of: SelectorListKind::default(),
2811 mapped_ids: &mut self.mapped_ids,
2812 nth_of_mapped_ids: &mut self.nth_of_mapped_ids,
2813 attribute_dependencies: &mut self.attribute_dependencies,
2814 nth_of_class_dependencies: &mut self.nth_of_class_dependencies,
2815 nth_of_attribute_dependencies: &mut self
2816 .nth_of_attribute_dependencies,
2817 state_dependencies: &mut self.state_dependencies,
2818 nth_of_state_dependencies: &mut self.nth_of_state_dependencies,
2819 document_state_dependencies: &mut self.document_state_dependencies,
2821 rule.selector.visit(&mut visitor);
2823 if needs_revalidation {
2824 self.selectors_for_cache_revalidation.insert(
2825 RevalidationSelectorAndHashes::new(
2826 rule.selector.clone(),
2827 rule.hashes.clone(),
2834 // Part is special, since given it doesn't have any
2835 // selectors inside, it's not worth using a whole
2836 // SelectorMap for it.
2837 if let Some(parts) = rule.selector.parts() {
2838 // ::part() has all semantics, so we just need to
2839 // put any of them in the selector map.
2841 // We choose the last one quite arbitrarily,
2842 // expecting it's slightly more likely to be more
2846 .get_or_insert_with(|| Box::new(Default::default()))
2847 .for_insertion(pseudo_element);
2848 map.try_reserve(1)?;
2849 let vec = map.entry(parts.last().unwrap().clone().0).or_default();
2850 vec.try_reserve(1)?;
2853 // NOTE(emilio): It's fine to look at :host and then at
2854 // ::slotted(..), since :host::slotted(..) could never
2855 // possibly match, as <slot> is not a valid shadow host.
2858 .is_featureless_host_selector_or_pseudo_element()
2861 .get_or_insert_with(|| Box::new(Default::default()))
2862 } else if rule.selector.is_slotted() {
2864 .get_or_insert_with(|| Box::new(Default::default()))
2866 &mut self.normal_rules
2868 .for_insertion(pseudo_element);
2869 rules.insert(rule, quirks_mode)?;
2872 self.rules_source_order += 1;
2873 handled = !has_nested_rules;
2875 CssRule::Keyframes(ref keyframes_rule) => {
2876 debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
2877 let keyframes_rule = keyframes_rule.read_with(guard);
2878 let name = keyframes_rule.name.as_atom().clone();
2879 let animation = KeyframesAnimation::from_keyframes(
2880 &keyframes_rule.keyframes,
2881 keyframes_rule.vendor_prefix.clone(),
2884 self.animations.try_insert_with(
2887 containing_rule_state.layer_id,
2888 compare_keyframes_in_same_layer,
2891 CssRule::Property(ref rule) => {
2892 let url_data = stylesheet.contents().url_data.read();
2893 if let Ok(registration) = rule.to_valid_registration(&url_data) {
2894 self.custom_property_registrations.try_insert(
2895 rule.name.0.clone(),
2897 containing_rule_state.layer_id,
2901 #[cfg(feature = "gecko")]
2902 CssRule::FontFace(ref rule) => {
2903 // NOTE(emilio): We don't care about container_condition_id
2906 // Global, name-defining at-rules such as @keyframes or
2907 // @font-face or @layer that are defined inside container
2908 // queries are not constrained by the container query
2911 // https://drafts.csswg.org/css-contain-3/#container-rule
2914 .add_font_face(rule, containing_rule_state.layer_id);
2916 #[cfg(feature = "gecko")]
2917 CssRule::FontFeatureValues(ref rule) => {
2919 .add_font_feature_values(rule, containing_rule_state.layer_id);
2921 #[cfg(feature = "gecko")]
2922 CssRule::FontPaletteValues(ref rule) => {
2924 .add_font_palette_values(rule, containing_rule_state.layer_id);
2926 #[cfg(feature = "gecko")]
2927 CssRule::CounterStyle(ref rule) => {
2928 self.extra_data.add_counter_style(
2931 containing_rule_state.layer_id,
2934 #[cfg(feature = "gecko")]
2935 CssRule::Page(ref rule) => {
2937 .add_page(guard, rule, containing_rule_state.layer_id)?;
2945 // Assert that there are no children, and that the rule is
2947 if cfg!(debug_assertions) {
2948 let mut effective = false;
2949 let children = EffectiveRulesIterator::children(
2956 debug_assert!(children.is_none());
2957 debug_assert!(effective);
2962 let mut effective = false;
2964 EffectiveRulesIterator::children(rule, device, quirks_mode, guard, &mut effective);
2970 fn maybe_register_layer(data: &mut CascadeData, layer: &LayerName) -> LayerId {
2971 // TODO: Measure what's more common / expensive, if
2972 // layer.clone() or the double hash lookup in the insert
2974 if let Some(id) = data.layer_id.get(layer) {
2977 let id = LayerId(data.layers.len() as u16);
2979 let parent_layer_id = if layer.layer_names().len() > 1 {
2980 let mut parent = layer.clone();
2986 .expect("Parent layers should be registered before child layers")
2991 data.layers[parent_layer_id.0 as usize].children.push(id);
2992 data.layers.push(CascadeLayer {
2994 // NOTE(emilio): Order is evaluated after rebuild in
2995 // compute_layer_order.
2996 order: LayerOrder::first(),
3000 data.layer_id.insert(layer.clone(), id);
3005 fn maybe_register_layers(
3006 data: &mut CascadeData,
3007 name: Option<&LayerName>,
3008 containing_rule_state: &mut ContainingRuleState,
3011 let name = match name {
3014 anon_name = LayerName::new_anonymous();
3018 for name in name.layer_names() {
3019 containing_rule_state.layer_name.0.push(name.clone());
3020 containing_rule_state.layer_id =
3021 maybe_register_layer(data, &containing_rule_state.layer_name);
3023 debug_assert_ne!(containing_rule_state.layer_id, LayerId::root());
3026 let saved_containing_rule_state = containing_rule_state.save();
3028 CssRule::Import(ref lock) => {
3029 let import_rule = lock.read_with(guard);
3030 if rebuild_kind.should_rebuild_invalidation() {
3031 self.effective_media_query_results
3032 .saw_effective(import_rule);
3034 match import_rule.layer {
3035 ImportLayer::Named(ref name) => {
3036 maybe_register_layers(self, Some(name), containing_rule_state)
3038 ImportLayer::Anonymous => {
3039 maybe_register_layers(self, None, containing_rule_state)
3041 ImportLayer::None => {},
3044 CssRule::Media(ref media_rule) => {
3045 if rebuild_kind.should_rebuild_invalidation() {
3046 self.effective_media_query_results
3047 .saw_effective(&**media_rule);
3050 CssRule::LayerBlock(ref rule) => {
3051 maybe_register_layers(self, rule.name.as_ref(), containing_rule_state);
3053 CssRule::LayerStatement(ref rule) => {
3054 for name in &*rule.names {
3055 maybe_register_layers(self, Some(name), containing_rule_state);
3056 // Register each layer individually.
3057 containing_rule_state.restore(&saved_containing_rule_state);
3060 CssRule::Style(..) => {
3061 if let Some(ref mut s) = selectors_for_nested_rules {
3062 containing_rule_state.ancestor_selector_lists.push(match s {
3063 Cow::Owned(ref mut list) => AncestorSelectorList::Shared(list.into_shared()),
3064 Cow::Borrowed(ref b) => AncestorSelectorList::Borrowed(b),
3068 CssRule::Container(ref rule) => {
3069 let id = ContainerConditionId(self.container_conditions.len() as u16);
3070 self.container_conditions.push(ContainerConditionReference {
3071 parent: containing_rule_state.container_condition_id,
3072 condition: Some(rule.condition.clone()),
3074 containing_rule_state.container_condition_id = id;
3076 // We don't care about any other rule.
3080 if let Some(children) = children {
3088 containing_rule_state,
3089 precomputed_pseudo_element_decls.as_deref_mut(),
3093 containing_rule_state.restore(&saved_containing_rule_state);
3099 // Returns Err(..) to signify OOM
3100 fn add_stylesheet<S>(
3103 quirks_mode: QuirksMode,
3105 guard: &SharedRwLockReadGuard,
3106 rebuild_kind: SheetRebuildKind,
3107 mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
3108 ) -> Result<(), AllocErr>
3110 S: StylesheetInDocument + 'static,
3112 if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
3116 let contents = stylesheet.contents();
3118 if rebuild_kind.should_rebuild_invalidation() {
3119 self.effective_media_query_results.saw_effective(contents);
3122 let mut state = ContainingRuleState::default();
3124 contents.rules(guard).iter(),
3131 precomputed_pseudo_element_decls.as_deref_mut(),
3137 /// Returns whether all the media-feature affected values matched before and
3138 /// match now in the given stylesheet.
3139 pub fn media_feature_affected_matches<S>(
3142 guard: &SharedRwLockReadGuard,
3144 quirks_mode: QuirksMode,
3147 S: StylesheetInDocument + 'static,
3149 use crate::invalidation::media_queries::PotentiallyEffectiveMediaRules;
3151 let effective_now = stylesheet.is_effective_for_device(device, guard);
3153 let effective_then = self
3154 .effective_media_query_results
3155 .was_effective(stylesheet.contents());
3157 if effective_now != effective_then {
3159 " > Stylesheet {:?} changed -> {}, {}",
3160 stylesheet.media(guard),
3171 let mut iter = stylesheet.iter_rules::<PotentiallyEffectiveMediaRules>(device, guard);
3173 while let Some(rule) = iter.next() {
3175 CssRule::Style(..) |
3176 CssRule::Namespace(..) |
3177 CssRule::FontFace(..) |
3178 CssRule::Container(..) |
3179 CssRule::CounterStyle(..) |
3180 CssRule::Supports(..) |
3181 CssRule::Keyframes(..) |
3183 CssRule::Property(..) |
3184 CssRule::Document(..) |
3185 CssRule::LayerBlock(..) |
3186 CssRule::LayerStatement(..) |
3187 CssRule::FontPaletteValues(..) |
3188 CssRule::FontFeatureValues(..) => {
3189 // Not affected by device changes.
3192 CssRule::Import(ref lock) => {
3193 let import_rule = lock.read_with(guard);
3194 let effective_now = match import_rule.stylesheet.media(guard) {
3195 Some(m) => m.evaluate(device, quirks_mode),
3198 let effective_then = self
3199 .effective_media_query_results
3200 .was_effective(import_rule);
3201 if effective_now != effective_then {
3203 " > @import rule {:?} changed {} -> {}",
3204 import_rule.stylesheet.media(guard),
3212 iter.skip_children();
3215 CssRule::Media(ref media_rule) => {
3216 let mq = media_rule.media_queries.read_with(guard);
3217 let effective_now = mq.evaluate(device, quirks_mode);
3218 let effective_then = self
3219 .effective_media_query_results
3220 .was_effective(&**media_rule);
3222 if effective_now != effective_then {
3224 " > @media rule {:?} changed {} -> {}",
3225 mq, effective_then, effective_now
3231 iter.skip_children();
3240 /// Returns the custom properties map.
3241 pub fn custom_property_registrations(&self) -> &LayerOrderedMap<PropertyRegistration> {
3242 &self.custom_property_registrations
3245 /// Clears the cascade data, but not the invalidation data.
3246 fn clear_cascade_data(&mut self) {
3247 self.normal_rules.clear();
3248 if let Some(ref mut slotted_rules) = self.slotted_rules {
3249 slotted_rules.clear();
3251 if let Some(ref mut part_rules) = self.part_rules {
3254 if let Some(ref mut host_rules) = self.host_rules {
3257 self.animations.clear();
3258 self.custom_property_registrations.clear();
3259 self.layer_id.clear();
3260 self.layers.clear();
3261 self.layers.push(CascadeLayer::root());
3262 self.container_conditions.clear();
3263 self.container_conditions
3264 .push(ContainerConditionReference::none());
3265 self.extra_data.clear();
3266 self.rules_source_order = 0;
3267 self.num_selectors = 0;
3268 self.num_declarations = 0;
3271 fn clear(&mut self) {
3272 self.clear_cascade_data();
3273 self.invalidation_map.clear();
3274 self.relative_selector_invalidation_map.clear();
3275 self.attribute_dependencies.clear();
3276 self.nth_of_attribute_dependencies.clear();
3277 self.nth_of_class_dependencies.clear();
3278 self.state_dependencies = ElementState::empty();
3279 self.nth_of_state_dependencies = ElementState::empty();
3280 self.document_state_dependencies = DocumentState::empty();
3281 self.mapped_ids.clear();
3282 self.nth_of_mapped_ids.clear();
3283 self.selectors_for_cache_revalidation.clear();
3284 self.effective_media_query_results.clear();
3288 impl CascadeDataCacheEntry for CascadeData {
3289 fn cascade_data(&self) -> &CascadeData {
3295 quirks_mode: QuirksMode,
3296 collection: SheetCollectionFlusher<S>,
3297 guard: &SharedRwLockReadGuard,
3299 ) -> Result<Arc<Self>, AllocErr>
3301 S: StylesheetInDocument + PartialEq + 'static,
3303 debug_assert!(collection.dirty(), "We surely need to do something?");
3304 // If we're doing a full rebuild anyways, don't bother cloning the data.
3305 let mut updatable_entry = match collection.data_validity() {
3306 DataValidity::Valid | DataValidity::CascadeInvalid => old.clone(),
3307 DataValidity::FullyInvalid => Self::new(),
3309 updatable_entry.rebuild(device, quirks_mode, collection, guard)?;
3310 Ok(Arc::new(updatable_entry))
3313 #[cfg(feature = "gecko")]
3314 fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
3315 self.normal_rules.add_size_of(ops, sizes);
3316 if let Some(ref slotted_rules) = self.slotted_rules {
3317 slotted_rules.add_size_of(ops, sizes);
3319 if let Some(ref part_rules) = self.part_rules {
3320 part_rules.add_size_of(ops, sizes);
3322 if let Some(ref host_rules) = self.host_rules {
3323 host_rules.add_size_of(ops, sizes);
3325 sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
3326 sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
3327 sizes.mOther += self.animations.size_of(ops);
3328 sizes.mOther += self.effective_media_query_results.size_of(ops);
3329 sizes.mOther += self.extra_data.size_of(ops);
3333 impl Default for CascadeData {
3334 fn default() -> Self {
3339 /// A rule, that wraps a style rule, but represents a single selector of the
3341 #[derive(Clone, Debug, MallocSizeOf)]
3343 /// The selector this struct represents. We store this and the
3344 /// any_{important,normal} booleans inline in the Rule to avoid
3345 /// pointer-chasing when gathering applicable declarations, which
3346 /// can ruin performance when there are a lot of rules.
3347 #[ignore_malloc_size_of = "CssRules have primary refs, we measure there"]
3348 pub selector: Selector<SelectorImpl>,
3350 /// The ancestor hashes associated with the selector.
3351 pub hashes: AncestorHashes,
3353 /// The source order this style rule appears in. Note that we only use
3354 /// three bytes to store this value in ApplicableDeclarationsBlock, so
3355 /// we could repurpose that storage here if we needed to.
3356 pub source_order: u32,
3358 /// The current layer id of this style rule.
3359 pub layer_id: LayerId,
3361 /// The current @container rule id.
3362 pub container_condition_id: ContainerConditionId,
3364 /// The actual style rule.
3367 ignore_malloc_size_of = "Secondary ref. Primary ref is in StyleRule under Stylesheet."
3369 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
3370 pub style_rule: Arc<Locked<StyleRule>>,
3373 impl SelectorMapEntry for Rule {
3374 fn selector(&self) -> SelectorIter<SelectorImpl> {
3375 self.selector.iter()
3380 /// Returns the specificity of the rule.
3381 pub fn specificity(&self) -> u32 {
3382 self.selector.specificity()
3385 /// Turns this rule into an `ApplicableDeclarationBlock` for the given
3387 pub fn to_applicable_declaration_block(
3389 level: CascadeLevel,
3390 cascade_data: &CascadeData,
3391 ) -> ApplicableDeclarationBlock {
3392 let source = StyleSource::from_rule(self.style_rule.clone());
3393 ApplicableDeclarationBlock::new(
3398 cascade_data.layer_order_for(self.layer_id),
3402 /// Creates a new Rule.
3404 selector: Selector<SelectorImpl>,
3405 hashes: AncestorHashes,
3406 style_rule: Arc<Locked<StyleRule>>,
3409 container_condition_id: ContainerConditionId,
3417 container_condition_id,
3422 // The size of this is critical to performance on the bloom-basic
3424 // When iterating over a large Rule array, we want to be able to fast-reject
3425 // selectors (with the inline hashes) with as few cache misses as possible.
3426 size_of_test!(Rule, 40);
3428 /// A function to be able to test the revalidation stuff.
3429 pub fn needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool {
3430 let mut needs_revalidation = false;
3431 let mut mapped_ids = Default::default();
3432 let mut nth_of_mapped_ids = Default::default();
3433 let mut attribute_dependencies = Default::default();
3434 let mut nth_of_class_dependencies = Default::default();
3435 let mut nth_of_attribute_dependencies = Default::default();
3436 let mut state_dependencies = ElementState::empty();
3437 let mut nth_of_state_dependencies = ElementState::empty();
3438 let mut document_state_dependencies = DocumentState::empty();
3439 let mut visitor = StylistSelectorVisitor {
3440 passed_rightmost_selector: false,
3441 needs_revalidation: &mut needs_revalidation,
3442 in_selector_list_of: SelectorListKind::default(),
3443 mapped_ids: &mut mapped_ids,
3444 nth_of_mapped_ids: &mut nth_of_mapped_ids,
3445 attribute_dependencies: &mut attribute_dependencies,
3446 nth_of_class_dependencies: &mut nth_of_class_dependencies,
3447 nth_of_attribute_dependencies: &mut nth_of_attribute_dependencies,
3448 state_dependencies: &mut state_dependencies,
3449 nth_of_state_dependencies: &mut nth_of_state_dependencies,
3450 document_state_dependencies: &mut document_state_dependencies,
3452 s.visit(&mut visitor);