1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 //! Selector matching.
6 
7 use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
8 use crate::context::{CascadeInputs, QuirksMode};
9 use crate::dom::{TElement, TShadowRoot};
10 use crate::element_state::{DocumentState, ElementState};
11 use crate::font_metrics::FontMetricsProvider;
12 #[cfg(feature = "gecko")]
13 use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
14 use crate::invalidation::element::invalidation_map::InvalidationMap;
15 use crate::invalidation::media_queries::{EffectiveMediaQueryResults, MediaListKey, ToMediaListKey};
16 use crate::invalidation::stylesheets::RuleChangeKind;
17 use crate::media_queries::Device;
18 use crate::properties::{self, CascadeMode, ComputedValues};
19 use crate::properties::{AnimationDeclarations, PropertyDeclarationBlock};
20 use crate::rule_cache::{RuleCache, RuleCacheConditions};
21 use crate::rule_collector::{containing_shadow_ignoring_svg_use, RuleCollector};
22 use crate::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
23 use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
24 use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
25 use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
26 use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind};
27 use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher};
28 use crate::stylesheets::keyframes_rule::KeyframesAnimation;
29 use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
30 use crate::stylesheets::{StyleRule, StylesheetInDocument, StylesheetContents};
31 #[cfg(feature = "gecko")]
32 use crate::stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule};
33 use crate::stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter};
34 use crate::thread_state::{self, ThreadState};
35 use crate::{Atom, LocalName, Namespace, WeakAtom};
36 use fallible::FallibleVec;
37 use hashglobe::FailedAllocationError;
38 use malloc_size_of::MallocSizeOf;
39 #[cfg(feature = "gecko")]
40 use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
41 use selectors::attr::{CaseSensitivity, NamespaceConstraint};
42 use selectors::bloom::BloomFilter;
43 use selectors::matching::VisitedHandlingMode;
44 use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode};
45 use selectors::parser::{AncestorHashes, Combinator, Component, Selector, SelectorIter};
46 use selectors::visitor::SelectorVisitor;
47 use selectors::NthIndexCache;
48 use servo_arc::{Arc, ArcBorrow};
49 use smallbitvec::SmallBitVec;
50 use smallvec::SmallVec;
51 use std::sync::Mutex;
52 use std::{mem, ops};
53 use std::hash::{Hash, Hasher};
54 use style_traits::viewport::ViewportConstraints;
55 use fxhash::FxHashMap;
56 
57 /// The type of the stylesheets that the stylist contains.
58 #[cfg(feature = "servo")]
59 pub type StylistSheet = crate::stylesheets::DocumentStyleSheet;
60 
61 /// The type of the stylesheets that the stylist contains.
62 #[cfg(feature = "gecko")]
63 pub type StylistSheet = crate::gecko::data::GeckoStyleSheet;
64 
65 #[derive(Debug, Clone)]
66 struct StylesheetContentsPtr(Arc<StylesheetContents>);
67 
68 impl PartialEq for StylesheetContentsPtr {
69     #[inline]
eq(&self, other: &Self) -> bool70     fn eq(&self, other: &Self) -> bool {
71         Arc::ptr_eq(&self.0, &other.0)
72     }
73 }
74 
75 impl Eq for StylesheetContentsPtr {}
76 
77 impl Hash for StylesheetContentsPtr {
hash<H: Hasher>(&self, state: &mut H)78     fn hash<H: Hasher>(&self, state: &mut H) {
79         let contents: &StylesheetContents = &*self.0;
80         (contents as *const StylesheetContents).hash(state)
81     }
82 }
83 
84 type StyleSheetContentList = Vec<StylesheetContentsPtr>;
85 
86 /// A key in the cascade data cache.
87 #[derive(Debug, Hash, Default, PartialEq, Eq)]
88 struct CascadeDataCacheKey {
89     media_query_results: Vec<MediaListKey>,
90     contents: StyleSheetContentList,
91 }
92 
93 unsafe impl Send for CascadeDataCacheKey {}
94 unsafe impl Sync for CascadeDataCacheKey {}
95 
96 trait CascadeDataCacheEntry : Sized {
97     /// Returns a reference to the cascade data.
cascade_data(&self) -> &CascadeData98     fn cascade_data(&self) -> &CascadeData;
99     /// Rebuilds the cascade data for the new stylesheet collection. The
100     /// collection is guaranteed to be dirty.
rebuild<S>( device: &Device, quirks_mode: QuirksMode, collection: SheetCollectionFlusher<S>, guard: &SharedRwLockReadGuard, old_entry: &Self, ) -> Result<Arc<Self>, FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static101     fn rebuild<S>(
102         device: &Device,
103         quirks_mode: QuirksMode,
104         collection: SheetCollectionFlusher<S>,
105         guard: &SharedRwLockReadGuard,
106         old_entry: &Self,
107     ) -> Result<Arc<Self>, FailedAllocationError>
108     where
109         S: StylesheetInDocument + PartialEq + 'static;
110     /// Measures heap memory usage.
111     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)112     fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes);
113 }
114 
115 struct CascadeDataCache<Entry> {
116     entries: FxHashMap<CascadeDataCacheKey, Arc<Entry>>,
117 }
118 
119 impl<Entry> CascadeDataCache<Entry>
120 where
121     Entry: CascadeDataCacheEntry,
122 {
new() -> Self123     fn new() -> Self {
124         Self { entries: Default::default() }
125     }
126 
len(&self) -> usize127     fn len(&self) -> usize {
128         self.entries.len()
129     }
130 
131     // FIXME(emilio): This may need to be keyed on quirks-mode too, though for
132     // UA sheets there aren't class / id selectors on those sheets, usually, so
133     // it's probably ok... For the other cache the quirks mode shouldn't differ
134     // so also should be fine.
lookup<'a, S>( &'a mut self, device: &Device, quirks_mode: QuirksMode, collection: SheetCollectionFlusher<S>, guard: &SharedRwLockReadGuard, old_entry: &Entry, ) -> Result<Option<Arc<Entry>>, FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static,135     fn lookup<'a, S>(
136         &'a mut self,
137         device: &Device,
138         quirks_mode: QuirksMode,
139         collection: SheetCollectionFlusher<S>,
140         guard: &SharedRwLockReadGuard,
141         old_entry: &Entry,
142     ) -> Result<Option<Arc<Entry>>, FailedAllocationError>
143     where
144         S: StylesheetInDocument + PartialEq + 'static,
145     {
146         use std::collections::hash_map::Entry as HashMapEntry;
147         debug!("StyleSheetCache::lookup({})", self.len());
148 
149         if !collection.dirty() {
150             return Ok(None);
151         }
152 
153         let mut key = CascadeDataCacheKey::default();
154         for sheet in collection.sheets() {
155             CascadeData::collect_applicable_media_query_results_into(
156                 device,
157                 sheet,
158                 guard,
159                 &mut key.media_query_results,
160                 &mut key.contents,
161             )
162         }
163 
164         let new_entry;
165         match self.entries.entry(key) {
166             HashMapEntry::Vacant(e) => {
167                 debug!("> Picking the slow path (not in the cache)");
168                 new_entry = Entry::rebuild(
169                     device,
170                     quirks_mode,
171                     collection,
172                     guard,
173                     old_entry,
174                 )?;
175                 e.insert(new_entry.clone());
176             }
177             HashMapEntry::Occupied(mut e) => {
178                 // Avoid reusing our old entry (this can happen if we get
179                 // invalidated due to CSSOM mutations and our old stylesheet
180                 // contents were already unique, for example).
181                 if !std::ptr::eq(&**e.get(), old_entry) {
182                     if log_enabled!(log::Level::Debug) {
183                         debug!("cache hit for:");
184                         for sheet in collection.sheets() {
185                             debug!(" > {:?}", sheet);
186                         }
187                     }
188                     // The line below ensures the "committed" bit is updated
189                     // properly.
190                     collection.each(|_, _| true);
191                     return Ok(Some(e.get().clone()));
192                 }
193 
194                 debug!("> Picking the slow path due to same entry as old");
195                 new_entry = Entry::rebuild(
196                     device,
197                     quirks_mode,
198                     collection,
199                     guard,
200                     old_entry,
201                 )?;
202                 e.insert(new_entry.clone());
203             }
204         }
205 
206         Ok(Some(new_entry))
207     }
208 
209     /// Returns all the cascade datas that are not being used (that is, that are
210     /// held alive just by this cache).
211     ///
212     /// We return them instead of dropping in place because some of them may
213     /// keep alive some other documents (like the SVG documents kept alive by
214     /// URL references), and thus we don't want to drop them while locking the
215     /// cache to not deadlock.
take_unused(&mut self) -> SmallVec<[Arc<Entry>; 3]>216     fn take_unused(&mut self) -> SmallVec<[Arc<Entry>; 3]> {
217         let mut unused = SmallVec::new();
218         self.entries.retain(|_key, value| {
219             // is_unique() returns false for static references, but we never
220             // have static references to UserAgentCascadeDatas.  If we did, it
221             // may not make sense to put them in the cache in the first place.
222             if !value.is_unique() {
223                 return true;
224             }
225             unused.push(value.clone());
226             false
227         });
228         unused
229     }
230 
take_all(&mut self) -> FxHashMap<CascadeDataCacheKey, Arc<Entry>>231     fn take_all(&mut self) -> FxHashMap<CascadeDataCacheKey, Arc<Entry>> {
232         mem::take(&mut self.entries)
233     }
234 
235     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)236     fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
237         sizes.mOther += self.entries.shallow_size_of(ops);
238         for (_key, arc) in self.entries.iter() {
239             // These are primary Arc references that can be measured
240             // unconditionally.
241             sizes.mOther += arc.unconditional_shallow_size_of(ops);
242             arc.add_size_of(ops, sizes);
243         }
244     }
245 }
246 
247 /// Measure heap usage of UA_CASCADE_DATA_CACHE.
248 #[cfg(feature = "gecko")]
add_size_of_ua_cache(ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)249 pub fn add_size_of_ua_cache(ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
250     UA_CASCADE_DATA_CACHE
251         .lock()
252         .unwrap()
253         .add_size_of(ops, sizes);
254 }
255 
256 lazy_static! {
257     /// A cache of computed user-agent data, to be shared across documents.
258     static ref UA_CASCADE_DATA_CACHE: Mutex<UserAgentCascadeDataCache> =
259         Mutex::new(UserAgentCascadeDataCache::new());
260 }
261 
262 impl CascadeDataCacheEntry for UserAgentCascadeData {
cascade_data(&self) -> &CascadeData263     fn cascade_data(&self) -> &CascadeData {
264         &self.cascade_data
265     }
266 
rebuild<S>( device: &Device, quirks_mode: QuirksMode, collection: SheetCollectionFlusher<S>, guard: &SharedRwLockReadGuard, _old: &Self, ) -> Result<Arc<Self>, FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static267     fn rebuild<S>(
268         device: &Device,
269         quirks_mode: QuirksMode,
270         collection: SheetCollectionFlusher<S>,
271         guard: &SharedRwLockReadGuard,
272         _old: &Self,
273     ) -> Result<Arc<Self>, FailedAllocationError>
274     where
275         S: StylesheetInDocument + PartialEq + 'static
276     {
277         // TODO: Maybe we should support incremental rebuilds, though they seem
278         // uncommon and rebuild() doesn't deal with
279         // precomputed_pseudo_element_decls for now so...
280         let mut new_data = Self {
281             cascade_data: CascadeData::new(),
282             precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations::default(),
283         };
284 
285         for sheet in collection.sheets() {
286             new_data.cascade_data.add_stylesheet(
287                 device,
288                 quirks_mode,
289                 sheet,
290                 guard,
291                 SheetRebuildKind::Full,
292                 Some(&mut new_data.precomputed_pseudo_element_decls),
293             )?;
294         }
295 
296         Ok(Arc::new(new_data))
297     }
298 
299     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)300     fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
301         self.cascade_data.add_size_of(ops, sizes);
302         sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops);
303     }
304 }
305 
306 type UserAgentCascadeDataCache = CascadeDataCache<UserAgentCascadeData>;
307 
308 type PrecomputedPseudoElementDeclarations = PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>;
309 
310 #[derive(Default)]
311 struct UserAgentCascadeData {
312     cascade_data: CascadeData,
313 
314     /// Applicable declarations for a given non-eagerly cascaded pseudo-element.
315     ///
316     /// These are eagerly computed once, and then used to resolve the new
317     /// computed values on the fly on layout.
318     ///
319     /// These are only filled from UA stylesheets.
320     precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations,
321 }
322 
323 /// All the computed information for all the stylesheets that apply to the
324 /// document.
325 #[derive(Default)]
326 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
327 pub struct DocumentCascadeData {
328     #[cfg_attr(
329         feature = "servo",
330         ignore_malloc_size_of = "Arc, owned by UserAgentCascadeDataCache"
331     )]
332     user_agent: Arc<UserAgentCascadeData>,
333     user: CascadeData,
334     author: CascadeData,
335     per_origin: PerOrigin<()>,
336 }
337 
338 /// An iterator over the cascade data of a given document.
339 pub struct DocumentCascadeDataIter<'a> {
340     iter: PerOriginIter<'a, ()>,
341     cascade_data: &'a DocumentCascadeData,
342 }
343 
344 impl<'a> Iterator for DocumentCascadeDataIter<'a> {
345     type Item = (&'a CascadeData, Origin);
346 
next(&mut self) -> Option<Self::Item>347     fn next(&mut self) -> Option<Self::Item> {
348         let (_, origin) = self.iter.next()?;
349         Some((self.cascade_data.borrow_for_origin(origin), origin))
350     }
351 }
352 
353 impl DocumentCascadeData {
354     /// Borrows the cascade data for a given origin.
355     #[inline]
borrow_for_origin(&self, origin: Origin) -> &CascadeData356     pub fn borrow_for_origin(&self, origin: Origin) -> &CascadeData {
357         match origin {
358             Origin::UserAgent => &self.user_agent.cascade_data,
359             Origin::Author => &self.author,
360             Origin::User => &self.user,
361         }
362     }
363 
iter_origins(&self) -> DocumentCascadeDataIter364     fn iter_origins(&self) -> DocumentCascadeDataIter {
365         DocumentCascadeDataIter {
366             iter: self.per_origin.iter_origins(),
367             cascade_data: self,
368         }
369     }
370 
iter_origins_rev(&self) -> DocumentCascadeDataIter371     fn iter_origins_rev(&self) -> DocumentCascadeDataIter {
372         DocumentCascadeDataIter {
373             iter: self.per_origin.iter_origins_rev(),
374             cascade_data: self,
375         }
376     }
377 
378     /// Rebuild the cascade data for the given document stylesheets, and
379     /// optionally with a set of user agent stylesheets.  Returns Err(..)
380     /// to signify OOM.
rebuild<'a, S>( &mut self, device: &Device, quirks_mode: QuirksMode, mut flusher: DocumentStylesheetFlusher<'a, S>, guards: &StylesheetGuards, ) -> Result<(), FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static,381     fn rebuild<'a, S>(
382         &mut self,
383         device: &Device,
384         quirks_mode: QuirksMode,
385         mut flusher: DocumentStylesheetFlusher<'a, S>,
386         guards: &StylesheetGuards,
387     ) -> Result<(), FailedAllocationError>
388     where
389         S: StylesheetInDocument + PartialEq + 'static,
390     {
391         // First do UA sheets.
392         {
393             let origin_flusher = flusher.flush_origin(Origin::UserAgent);
394             // Dirty check is just a minor optimization (no need to grab the
395             // lock if nothing has changed).
396             if origin_flusher.dirty() {
397                 let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
398                 let new_data = ua_cache.lookup(
399                     device,
400                     quirks_mode,
401                     origin_flusher,
402                     guards.ua_or_user,
403                     &self.user_agent,
404                 )?;
405                 if let Some(new_data) = new_data {
406                     self.user_agent = new_data;
407                 }
408                 let _unused_entries = ua_cache.take_unused();
409                 // See the comments in take_unused() as for why the following
410                 // line.
411                 std::mem::drop(ua_cache);
412             }
413         }
414 
415         // Now do the user sheets.
416         self.user.rebuild(
417             device,
418             quirks_mode,
419             flusher.flush_origin(Origin::User),
420             guards.ua_or_user,
421         )?;
422 
423         // And now the author sheets.
424         self.author.rebuild(
425             device,
426             quirks_mode,
427             flusher.flush_origin(Origin::Author),
428             guards.author,
429         )?;
430 
431         Ok(())
432     }
433 
434     /// Measures heap usage.
435     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)436     pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
437         self.user.add_size_of(ops, sizes);
438         self.author.add_size_of(ops, sizes);
439     }
440 }
441 
442 /// Whether author styles are enabled.
443 ///
444 /// This is used to support Gecko.
445 #[allow(missing_docs)]
446 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
447 pub enum AuthorStylesEnabled {
448     Yes,
449     No,
450 }
451 
452 /// A wrapper over a DocumentStylesheetSet that can be `Sync`, since it's only
453 /// used and exposed via mutable methods in the `Stylist`.
454 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
455 struct StylistStylesheetSet(DocumentStylesheetSet<StylistSheet>);
456 // Read above to see why this is fine.
457 unsafe impl Sync for StylistStylesheetSet {}
458 
459 impl StylistStylesheetSet {
new() -> Self460     fn new() -> Self {
461         StylistStylesheetSet(DocumentStylesheetSet::new())
462     }
463 }
464 
465 impl ops::Deref for StylistStylesheetSet {
466     type Target = DocumentStylesheetSet<StylistSheet>;
467 
deref(&self) -> &Self::Target468     fn deref(&self) -> &Self::Target {
469         &self.0
470     }
471 }
472 
473 impl ops::DerefMut for StylistStylesheetSet {
deref_mut(&mut self) -> &mut Self::Target474     fn deref_mut(&mut self) -> &mut Self::Target {
475         &mut self.0
476     }
477 }
478 
479 /// This structure holds all the selectors and device characteristics
480 /// for a given document. The selectors are converted into `Rule`s
481 /// and sorted into `SelectorMap`s keyed off stylesheet origin and
482 /// pseudo-element (see `CascadeData`).
483 ///
484 /// This structure is effectively created once per pipeline, in the
485 /// LayoutThread corresponding to that pipeline.
486 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
487 pub struct Stylist {
488     /// Device that the stylist is currently evaluating against.
489     ///
490     /// This field deserves a bigger comment due to the different use that Gecko
491     /// and Servo give to it (that we should eventually unify).
492     ///
493     /// With Gecko, the device is never changed. Gecko manually tracks whether
494     /// the device data should be reconstructed, and "resets" the state of the
495     /// device.
496     ///
497     /// On Servo, on the other hand, the device is a really cheap representation
498     /// that is recreated each time some constraint changes and calling
499     /// `set_device`.
500     device: Device,
501 
502     /// Viewport constraints based on the current device.
503     viewport_constraints: Option<ViewportConstraints>,
504 
505     /// The list of stylesheets.
506     stylesheets: StylistStylesheetSet,
507 
508     /// A cache of CascadeDatas for AuthorStylesheetSets (i.e., shadow DOM).
509     author_data_cache: CascadeDataCache<CascadeData>,
510 
511     /// If true, the quirks-mode stylesheet is applied.
512     #[cfg_attr(feature = "servo", ignore_malloc_size_of = "defined in selectors")]
513     quirks_mode: QuirksMode,
514 
515     /// Selector maps for all of the style sheets in the stylist, after
516     /// evalutaing media rules against the current device, split out per
517     /// cascade level.
518     cascade_data: DocumentCascadeData,
519 
520     /// Whether author styles are enabled.
521     author_styles_enabled: AuthorStylesEnabled,
522 
523     /// The rule tree, that stores the results of selector matching.
524     rule_tree: RuleTree,
525 
526     /// The total number of times the stylist has been rebuilt.
527     num_rebuilds: usize,
528 }
529 
530 /// What cascade levels to include when styling elements.
531 #[derive(Clone, Copy, PartialEq)]
532 pub enum RuleInclusion {
533     /// Include rules for style sheets at all cascade levels.  This is the
534     /// normal rule inclusion mode.
535     All,
536     /// Only include rules from UA and user level sheets.  Used to implement
537     /// `getDefaultComputedStyle`.
538     DefaultOnly,
539 }
540 
541 #[cfg(feature = "gecko")]
542 impl From<StyleRuleInclusion> for RuleInclusion {
from(value: StyleRuleInclusion) -> Self543     fn from(value: StyleRuleInclusion) -> Self {
544         match value {
545             StyleRuleInclusion::All => RuleInclusion::All,
546             StyleRuleInclusion::DefaultOnly => RuleInclusion::DefaultOnly,
547         }
548     }
549 }
550 
551 impl Stylist {
552     /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
553     /// If more members are added here, think about whether they should
554     /// be reset in clear().
555     #[inline]
new(device: Device, quirks_mode: QuirksMode) -> Self556     pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
557         Self {
558             viewport_constraints: None,
559             device,
560             quirks_mode,
561             stylesheets: StylistStylesheetSet::new(),
562             author_data_cache: CascadeDataCache::new(),
563             cascade_data: Default::default(),
564             author_styles_enabled: AuthorStylesEnabled::Yes,
565             rule_tree: RuleTree::new(),
566             num_rebuilds: 0,
567         }
568     }
569 
570     /// Returns the document cascade data.
571     #[inline]
cascade_data(&self) -> &DocumentCascadeData572     pub fn cascade_data(&self) -> &DocumentCascadeData {
573         &self.cascade_data
574     }
575 
576     /// Returns whether author styles are enabled or not.
577     #[inline]
author_styles_enabled(&self) -> AuthorStylesEnabled578     pub fn author_styles_enabled(&self) -> AuthorStylesEnabled {
579         self.author_styles_enabled
580     }
581 
582     /// Iterate through all the cascade datas from the document.
583     #[inline]
iter_origins(&self) -> DocumentCascadeDataIter584     pub fn iter_origins(&self) -> DocumentCascadeDataIter {
585         self.cascade_data.iter_origins()
586     }
587 
588     /// Does what the name says, to prevent author_data_cache to grow without
589     /// bound.
remove_unique_author_data_cache_entries(&mut self)590     pub fn remove_unique_author_data_cache_entries(&mut self) {
591         self.author_data_cache.take_unused();
592     }
593 
594     /// Rebuilds (if needed) the CascadeData given a sheet collection.
rebuild_author_data<S>( &mut self, old_data: &CascadeData, collection: SheetCollectionFlusher<S>, guard: &SharedRwLockReadGuard, ) -> Result<Option<Arc<CascadeData>>, FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static,595     pub fn rebuild_author_data<S>(
596         &mut self,
597         old_data: &CascadeData,
598         collection: SheetCollectionFlusher<S>,
599         guard: &SharedRwLockReadGuard,
600     ) -> Result<Option<Arc<CascadeData>>, FailedAllocationError>
601     where
602         S: StylesheetInDocument + PartialEq + 'static,
603     {
604         self.author_data_cache.lookup(
605             &self.device,
606             self.quirks_mode,
607             collection,
608             guard,
609             old_data,
610         )
611     }
612 
613     /// Iterate over the extra data in origin order.
614     #[inline]
iter_extra_data_origins(&self) -> ExtraStyleDataIterator615     pub fn iter_extra_data_origins(&self) -> ExtraStyleDataIterator {
616         ExtraStyleDataIterator(self.cascade_data.iter_origins())
617     }
618 
619     /// Iterate over the extra data in reverse origin order.
620     #[inline]
iter_extra_data_origins_rev(&self) -> ExtraStyleDataIterator621     pub fn iter_extra_data_origins_rev(&self) -> ExtraStyleDataIterator {
622         ExtraStyleDataIterator(self.cascade_data.iter_origins_rev())
623     }
624 
625     /// Returns the number of selectors.
num_selectors(&self) -> usize626     pub fn num_selectors(&self) -> usize {
627         self.cascade_data
628             .iter_origins()
629             .map(|(d, _)| d.num_selectors)
630             .sum()
631     }
632 
633     /// Returns the number of declarations.
num_declarations(&self) -> usize634     pub fn num_declarations(&self) -> usize {
635         self.cascade_data
636             .iter_origins()
637             .map(|(d, _)| d.num_declarations)
638             .sum()
639     }
640 
641     /// Returns the number of times the stylist has been rebuilt.
num_rebuilds(&self) -> usize642     pub fn num_rebuilds(&self) -> usize {
643         self.num_rebuilds
644     }
645 
646     /// Returns the number of revalidation_selectors.
num_revalidation_selectors(&self) -> usize647     pub fn num_revalidation_selectors(&self) -> usize {
648         self.cascade_data
649             .iter_origins()
650             .map(|(data, _)| data.selectors_for_cache_revalidation.len())
651             .sum()
652     }
653 
654     /// Returns the number of entries in invalidation maps.
num_invalidations(&self) -> usize655     pub fn num_invalidations(&self) -> usize {
656         self.cascade_data
657             .iter_origins()
658             .map(|(data, _)| data.invalidation_map.len())
659             .sum()
660     }
661 
662     /// Returns whether the given DocumentState bit is relied upon by a selector
663     /// of some rule.
has_document_state_dependency(&self, state: DocumentState) -> bool664     pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
665         self.cascade_data
666             .iter_origins()
667             .any(|(d, _)| d.document_state_dependencies.intersects(state))
668     }
669 
670     /// Flush the list of stylesheets if they changed, ensuring the stylist is
671     /// up-to-date.
flush<E>( &mut self, guards: &StylesheetGuards, document_element: Option<E>, snapshots: Option<&SnapshotMap>, ) -> bool where E: TElement,672     pub fn flush<E>(
673         &mut self,
674         guards: &StylesheetGuards,
675         document_element: Option<E>,
676         snapshots: Option<&SnapshotMap>,
677     ) -> bool
678     where
679         E: TElement,
680     {
681         if !self.stylesheets.has_changed() {
682             return false;
683         }
684 
685         self.num_rebuilds += 1;
686 
687         // Update viewport_constraints regardless of which origins'
688         // `CascadeData` we're updating.
689         self.viewport_constraints = None;
690         if viewport_rule::enabled() {
691             // TODO(emilio): This doesn't look so efficient.
692             //
693             // Presumably when we properly implement this we can at least have a
694             // bit on the stylesheet that says whether it contains viewport
695             // rules to skip it entirely?
696             //
697             // Processing it with the rest of rules seems tricky since it
698             // overrides the viewport size which may change the evaluation of
699             // media queries (or may not? how are viewport units in media
700             // queries defined?)
701             let cascaded_rule = ViewportRule {
702                 declarations: viewport_rule::Cascade::from_stylesheets(
703                     self.stylesheets.iter(),
704                     guards,
705                     &self.device,
706                 )
707                 .finish(),
708             };
709 
710             self.viewport_constraints =
711                 ViewportConstraints::maybe_new(&self.device, &cascaded_rule, self.quirks_mode);
712 
713             if let Some(ref constraints) = self.viewport_constraints {
714                 self.device.account_for_viewport_rule(constraints);
715             }
716         }
717 
718         let flusher = self.stylesheets.flush(document_element, snapshots);
719 
720         let had_invalidations = flusher.had_invalidations();
721 
722         self.cascade_data
723             .rebuild(&self.device, self.quirks_mode, flusher, guards)
724             .unwrap_or_else(|_| warn!("OOM in Stylist::flush"));
725 
726         had_invalidations
727     }
728 
729     /// Insert a given stylesheet before another stylesheet in the document.
insert_stylesheet_before( &mut self, sheet: StylistSheet, before_sheet: StylistSheet, guard: &SharedRwLockReadGuard, )730     pub fn insert_stylesheet_before(
731         &mut self,
732         sheet: StylistSheet,
733         before_sheet: StylistSheet,
734         guard: &SharedRwLockReadGuard,
735     ) {
736         self.stylesheets
737             .insert_stylesheet_before(Some(&self.device), sheet, before_sheet, guard)
738     }
739 
740     /// Marks a given stylesheet origin as dirty, due to, for example, changes
741     /// in the declarations that affect a given rule.
742     ///
743     /// FIXME(emilio): Eventually it'd be nice for this to become more
744     /// fine-grained.
force_stylesheet_origins_dirty(&mut self, origins: OriginSet)745     pub fn force_stylesheet_origins_dirty(&mut self, origins: OriginSet) {
746         self.stylesheets.force_dirty(origins)
747     }
748 
749     /// Sets whether author style is enabled or not.
set_author_styles_enabled(&mut self, enabled: AuthorStylesEnabled)750     pub fn set_author_styles_enabled(&mut self, enabled: AuthorStylesEnabled) {
751         self.author_styles_enabled = enabled;
752     }
753 
754     /// Returns whether we've recorded any stylesheet change so far.
stylesheets_have_changed(&self) -> bool755     pub fn stylesheets_have_changed(&self) -> bool {
756         self.stylesheets.has_changed()
757     }
758 
759     /// Appends a new stylesheet to the current set.
append_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard)760     pub fn append_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
761         self.stylesheets
762             .append_stylesheet(Some(&self.device), sheet, guard)
763     }
764 
765     /// Remove a given stylesheet to the current set.
remove_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard)766     pub fn remove_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
767         self.stylesheets
768             .remove_stylesheet(Some(&self.device), sheet, guard)
769     }
770 
771     /// Notify of a change of a given rule.
rule_changed( &mut self, sheet: &StylistSheet, rule: &CssRule, guard: &SharedRwLockReadGuard, change_kind: RuleChangeKind, )772     pub fn rule_changed(
773         &mut self,
774         sheet: &StylistSheet,
775         rule: &CssRule,
776         guard: &SharedRwLockReadGuard,
777         change_kind: RuleChangeKind,
778     ) {
779         self.stylesheets
780             .rule_changed(Some(&self.device), sheet, rule, guard, change_kind)
781     }
782 
783     /// Appends a new stylesheet to the current set.
784     #[inline]
sheet_count(&self, origin: Origin) -> usize785     pub fn sheet_count(&self, origin: Origin) -> usize {
786         self.stylesheets.sheet_count(origin)
787     }
788 
789     /// Appends a new stylesheet to the current set.
790     #[inline]
sheet_at(&self, origin: Origin, index: usize) -> Option<&StylistSheet>791     pub fn sheet_at(&self, origin: Origin, index: usize) -> Option<&StylistSheet> {
792         self.stylesheets.get(origin, index)
793     }
794 
795     /// Returns whether for any of the applicable style rule data a given
796     /// condition is true.
any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool where E: TElement, F: FnMut(&CascadeData) -> bool,797     pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
798     where
799         E: TElement,
800         F: FnMut(&CascadeData) -> bool,
801     {
802         if f(&self.cascade_data.user_agent.cascade_data) {
803             return true;
804         }
805 
806         let mut maybe = false;
807 
808         let doc_author_rules_apply =
809             element.each_applicable_non_document_style_rule_data(|data, _| {
810                 maybe = maybe || f(&*data);
811             });
812 
813         if maybe || f(&self.cascade_data.user) {
814             return true;
815         }
816 
817         doc_author_rules_apply && f(&self.cascade_data.author)
818     }
819 
820     /// Computes the style for a given "precomputed" pseudo-element, taking the
821     /// universal rules and applying them.
precomputed_values_for_pseudo<E>( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, parent: Option<&ComputedValues>, font_metrics: &dyn FontMetricsProvider, ) -> Arc<ComputedValues> where E: TElement,822     pub fn precomputed_values_for_pseudo<E>(
823         &self,
824         guards: &StylesheetGuards,
825         pseudo: &PseudoElement,
826         parent: Option<&ComputedValues>,
827         font_metrics: &dyn FontMetricsProvider,
828     ) -> Arc<ComputedValues>
829     where
830         E: TElement,
831     {
832         debug_assert!(pseudo.is_precomputed());
833 
834         let rule_node = self.rule_node_for_precomputed_pseudo(guards, pseudo, vec![]);
835 
836         self.precomputed_values_for_pseudo_with_rule_node::<E>(
837             guards,
838             pseudo,
839             parent,
840             font_metrics,
841             rule_node,
842         )
843     }
844 
845     /// Computes the style for a given "precomputed" pseudo-element with
846     /// given rule node.
847     ///
848     /// TODO(emilio): The type parameter could go away with a void type
849     /// implementing TElement.
precomputed_values_for_pseudo_with_rule_node<E>( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, parent: Option<&ComputedValues>, font_metrics: &dyn FontMetricsProvider, rules: StrongRuleNode, ) -> Arc<ComputedValues> where E: TElement,850     pub fn precomputed_values_for_pseudo_with_rule_node<E>(
851         &self,
852         guards: &StylesheetGuards,
853         pseudo: &PseudoElement,
854         parent: Option<&ComputedValues>,
855         font_metrics: &dyn FontMetricsProvider,
856         rules: StrongRuleNode,
857     ) -> Arc<ComputedValues>
858     where
859         E: TElement,
860     {
861         self.compute_pseudo_element_style_with_inputs::<E>(
862             CascadeInputs {
863                 rules: Some(rules),
864                 visited_rules: None,
865             },
866             pseudo,
867             guards,
868             parent,
869             font_metrics,
870             None,
871         )
872     }
873 
874     /// Returns the rule node for a given precomputed pseudo-element.
875     ///
876     /// If we want to include extra declarations to this precomputed
877     /// pseudo-element, we can provide a vector of ApplicableDeclarationBlocks
878     /// to extra_declarations. This is useful for @page rules.
rule_node_for_precomputed_pseudo( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, mut extra_declarations: Vec<ApplicableDeclarationBlock>, ) -> StrongRuleNode879     pub fn rule_node_for_precomputed_pseudo(
880         &self,
881         guards: &StylesheetGuards,
882         pseudo: &PseudoElement,
883         mut extra_declarations: Vec<ApplicableDeclarationBlock>,
884     ) -> StrongRuleNode {
885         let mut declarations_with_extra;
886         let declarations = match self
887             .cascade_data
888             .user_agent
889             .precomputed_pseudo_element_decls
890             .get(pseudo)
891         {
892             Some(declarations) => {
893                 if !extra_declarations.is_empty() {
894                     declarations_with_extra = declarations.clone();
895                     declarations_with_extra.append(&mut extra_declarations);
896                     &*declarations_with_extra
897                 } else {
898                     &**declarations
899                 }
900             },
901             None => &[],
902         };
903 
904         self.rule_tree.insert_ordered_rules_with_important(
905             declarations.into_iter().map(|a| a.clone().for_rule_tree()),
906             guards,
907         )
908     }
909 
910     /// Returns the style for an anonymous box of the given type.
911     ///
912     /// TODO(emilio): The type parameter could go away with a void type
913     /// implementing TElement.
914     #[cfg(feature = "servo")]
style_for_anonymous<E>( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, parent_style: &ComputedValues, ) -> Arc<ComputedValues> where E: TElement,915     pub fn style_for_anonymous<E>(
916         &self,
917         guards: &StylesheetGuards,
918         pseudo: &PseudoElement,
919         parent_style: &ComputedValues,
920     ) -> Arc<ComputedValues>
921     where
922         E: TElement,
923     {
924         use crate::font_metrics::ServoMetricsProvider;
925         self.precomputed_values_for_pseudo::<E>(
926             guards,
927             &pseudo,
928             Some(parent_style),
929             &ServoMetricsProvider,
930         )
931     }
932 
933     /// Computes a pseudo-element style lazily during layout.
934     ///
935     /// This can only be done for a certain set of pseudo-elements, like
936     /// :selection.
937     ///
938     /// Check the documentation on lazy pseudo-elements in
939     /// docs/components/style.md
lazily_compute_pseudo_element_style<E>( &self, guards: &StylesheetGuards, element: E, pseudo: &PseudoElement, rule_inclusion: RuleInclusion, parent_style: &ComputedValues, is_probe: bool, font_metrics: &dyn FontMetricsProvider, matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>, ) -> Option<Arc<ComputedValues>> where E: TElement,940     pub fn lazily_compute_pseudo_element_style<E>(
941         &self,
942         guards: &StylesheetGuards,
943         element: E,
944         pseudo: &PseudoElement,
945         rule_inclusion: RuleInclusion,
946         parent_style: &ComputedValues,
947         is_probe: bool,
948         font_metrics: &dyn FontMetricsProvider,
949         matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>,
950     ) -> Option<Arc<ComputedValues>>
951     where
952         E: TElement,
953     {
954         let cascade_inputs = self.lazy_pseudo_rules(
955             guards,
956             element,
957             parent_style,
958             pseudo,
959             is_probe,
960             rule_inclusion,
961             matching_fn,
962         )?;
963 
964         Some(self.compute_pseudo_element_style_with_inputs(
965             cascade_inputs,
966             pseudo,
967             guards,
968             Some(parent_style),
969             font_metrics,
970             Some(element),
971         ))
972     }
973 
974     /// Computes a pseudo-element style lazily using the given CascadeInputs.
975     /// This can be used for truly lazy pseudo-elements or to avoid redoing
976     /// selector matching for eager pseudo-elements when we need to recompute
977     /// their style with a new parent style.
compute_pseudo_element_style_with_inputs<E>( &self, inputs: CascadeInputs, pseudo: &PseudoElement, guards: &StylesheetGuards, parent_style: Option<&ComputedValues>, font_metrics: &dyn FontMetricsProvider, element: Option<E>, ) -> Arc<ComputedValues> where E: TElement,978     pub fn compute_pseudo_element_style_with_inputs<E>(
979         &self,
980         inputs: CascadeInputs,
981         pseudo: &PseudoElement,
982         guards: &StylesheetGuards,
983         parent_style: Option<&ComputedValues>,
984         font_metrics: &dyn FontMetricsProvider,
985         element: Option<E>,
986     ) -> Arc<ComputedValues>
987     where
988         E: TElement,
989     {
990         // FIXME(emilio): The lack of layout_parent_style here could be
991         // worrying, but we're probably dropping the display fixup for
992         // pseudos other than before and after, so it's probably ok.
993         //
994         // (Though the flags don't indicate so!)
995         //
996         // It'd be fine to assert that this isn't called with a parent style
997         // where display contents is in effect, but in practice this is hard to
998         // do for stuff like :-moz-fieldset-content with a
999         // <fieldset style="display: contents">. That is, the computed value of
1000         // display for the fieldset is "contents", even though it's not the used
1001         // value, so we don't need to adjust in a different way anyway.
1002         self.cascade_style_and_visited(
1003             element,
1004             Some(pseudo),
1005             inputs,
1006             guards,
1007             parent_style,
1008             parent_style,
1009             parent_style,
1010             font_metrics,
1011             /* rule_cache = */ None,
1012             &mut RuleCacheConditions::default(),
1013         )
1014     }
1015 
1016     /// Computes a style using the given CascadeInputs.  This can be used to
1017     /// compute a style any time we know what rules apply and just need to use
1018     /// the given parent styles.
1019     ///
1020     /// parent_style is the style to inherit from for properties affected by
1021     /// first-line ancestors.
1022     ///
1023     /// parent_style_ignoring_first_line is the style to inherit from for
1024     /// properties not affected by first-line ancestors.
1025     ///
1026     /// layout_parent_style is the style used for some property fixups.  It's
1027     /// the style of the nearest ancestor with a layout box.
cascade_style_and_visited<E>( &self, element: Option<E>, pseudo: Option<&PseudoElement>, inputs: CascadeInputs, guards: &StylesheetGuards, parent_style: Option<&ComputedValues>, parent_style_ignoring_first_line: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>, font_metrics: &dyn FontMetricsProvider, rule_cache: Option<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, ) -> Arc<ComputedValues> where E: TElement,1028     pub fn cascade_style_and_visited<E>(
1029         &self,
1030         element: Option<E>,
1031         pseudo: Option<&PseudoElement>,
1032         inputs: CascadeInputs,
1033         guards: &StylesheetGuards,
1034         parent_style: Option<&ComputedValues>,
1035         parent_style_ignoring_first_line: Option<&ComputedValues>,
1036         layout_parent_style: Option<&ComputedValues>,
1037         font_metrics: &dyn FontMetricsProvider,
1038         rule_cache: Option<&RuleCache>,
1039         rule_cache_conditions: &mut RuleCacheConditions,
1040     ) -> Arc<ComputedValues>
1041     where
1042         E: TElement,
1043     {
1044         debug_assert!(pseudo.is_some() || element.is_some(), "Huh?");
1045 
1046         // We need to compute visited values if we have visited rules or if our
1047         // parent has visited values.
1048         let visited_rules = match inputs.visited_rules.as_ref() {
1049             Some(rules) => Some(rules),
1050             None => {
1051                 if parent_style.and_then(|s| s.visited_style()).is_some() {
1052                     Some(inputs.rules.as_ref().unwrap_or(self.rule_tree.root()))
1053                 } else {
1054                     None
1055                 }
1056             },
1057         };
1058 
1059         // Read the comment on `precomputed_values_for_pseudo` to see why it's
1060         // difficult to assert that display: contents nodes never arrive here
1061         // (tl;dr: It doesn't apply for replaced elements and such, but the
1062         // computed value is still "contents").
1063         //
1064         // FIXME(emilio): We should assert that it holds if pseudo.is_none()!
1065         properties::cascade::<E>(
1066             &self.device,
1067             pseudo,
1068             inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
1069             guards,
1070             parent_style,
1071             parent_style_ignoring_first_line,
1072             layout_parent_style,
1073             visited_rules,
1074             font_metrics,
1075             self.quirks_mode,
1076             rule_cache,
1077             rule_cache_conditions,
1078             element,
1079         )
1080     }
1081 
1082     /// Computes the cascade inputs for a lazily-cascaded pseudo-element.
1083     ///
1084     /// See the documentation on lazy pseudo-elements in
1085     /// docs/components/style.md
lazy_pseudo_rules<E>( &self, guards: &StylesheetGuards, element: E, parent_style: &ComputedValues, pseudo: &PseudoElement, is_probe: bool, rule_inclusion: RuleInclusion, matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>, ) -> Option<CascadeInputs> where E: TElement,1086     fn lazy_pseudo_rules<E>(
1087         &self,
1088         guards: &StylesheetGuards,
1089         element: E,
1090         parent_style: &ComputedValues,
1091         pseudo: &PseudoElement,
1092         is_probe: bool,
1093         rule_inclusion: RuleInclusion,
1094         matching_fn: Option<&dyn Fn(&PseudoElement) -> bool>,
1095     ) -> Option<CascadeInputs>
1096     where
1097         E: TElement,
1098     {
1099         debug_assert!(pseudo.is_lazy());
1100 
1101         // Apply the selector flags. We should be in sequential mode
1102         // already, so we can directly apply the parent flags.
1103         let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| {
1104             if cfg!(feature = "servo") {
1105                 // Servo calls this function from the worker, but only for internal
1106                 // pseudos, so we should never generate selector flags here.
1107                 unreachable!("internal pseudo generated slow selector flags?");
1108             }
1109 
1110             // No need to bother setting the selector flags when we're computing
1111             // default styles.
1112             if rule_inclusion == RuleInclusion::DefaultOnly {
1113                 return;
1114             }
1115 
1116             // Gecko calls this from sequential mode, so we can directly apply
1117             // the flags.
1118             debug_assert_eq!(thread_state::get(), ThreadState::LAYOUT);
1119             let self_flags = flags.for_self();
1120             if !self_flags.is_empty() {
1121                 unsafe {
1122                     element.set_selector_flags(self_flags);
1123                 }
1124             }
1125             let parent_flags = flags.for_parent();
1126             if !parent_flags.is_empty() {
1127                 if let Some(p) = element.parent_element() {
1128                     unsafe {
1129                         p.set_selector_flags(parent_flags);
1130                     }
1131                 }
1132             }
1133         };
1134 
1135         let mut declarations = ApplicableDeclarationList::new();
1136         let mut matching_context = MatchingContext::new(
1137             MatchingMode::ForStatelessPseudoElement,
1138             None,
1139             None,
1140             self.quirks_mode,
1141         );
1142 
1143         matching_context.pseudo_element_matching_fn = matching_fn;
1144 
1145         self.push_applicable_declarations(
1146             element,
1147             Some(&pseudo),
1148             None,
1149             None,
1150             /* animation_declarations = */ Default::default(),
1151             rule_inclusion,
1152             &mut declarations,
1153             &mut matching_context,
1154             &mut set_selector_flags,
1155         );
1156 
1157         if declarations.is_empty() && is_probe {
1158             return None;
1159         }
1160 
1161         let rules = self.rule_tree.compute_rule_node(&mut declarations, guards);
1162 
1163         let mut visited_rules = None;
1164         if parent_style.visited_style().is_some() {
1165             let mut declarations = ApplicableDeclarationList::new();
1166             let mut matching_context = MatchingContext::new_for_visited(
1167                 MatchingMode::ForStatelessPseudoElement,
1168                 None,
1169                 None,
1170                 VisitedHandlingMode::RelevantLinkVisited,
1171                 self.quirks_mode,
1172             );
1173             matching_context.pseudo_element_matching_fn = matching_fn;
1174 
1175             self.push_applicable_declarations(
1176                 element,
1177                 Some(&pseudo),
1178                 None,
1179                 None,
1180                 /* animation_declarations = */ Default::default(),
1181                 rule_inclusion,
1182                 &mut declarations,
1183                 &mut matching_context,
1184                 &mut set_selector_flags,
1185             );
1186             if !declarations.is_empty() {
1187                 let rule_node = self.rule_tree.insert_ordered_rules_with_important(
1188                     declarations.drain(..).map(|a| a.for_rule_tree()),
1189                     guards,
1190                 );
1191                 if rule_node != *self.rule_tree.root() {
1192                     visited_rules = Some(rule_node);
1193                 }
1194             }
1195         }
1196 
1197         Some(CascadeInputs {
1198             rules: Some(rules),
1199             visited_rules,
1200         })
1201     }
1202 
1203     /// Set a given device, which may change the styles that apply to the
1204     /// document.
1205     ///
1206     /// Returns the sheet origins that were actually affected.
1207     ///
1208     /// This means that we may need to rebuild style data even if the
1209     /// stylesheets haven't changed.
1210     ///
1211     /// Also, the device that arrives here may need to take the viewport rules
1212     /// into account.
set_device(&mut self, mut device: Device, guards: &StylesheetGuards) -> OriginSet1213     pub fn set_device(&mut self, mut device: Device, guards: &StylesheetGuards) -> OriginSet {
1214         if viewport_rule::enabled() {
1215             let cascaded_rule = {
1216                 let stylesheets = self.stylesheets.iter();
1217 
1218                 ViewportRule {
1219                     declarations: viewport_rule::Cascade::from_stylesheets(
1220                         stylesheets,
1221                         guards,
1222                         &device,
1223                     )
1224                     .finish(),
1225                 }
1226             };
1227 
1228             self.viewport_constraints =
1229                 ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode);
1230 
1231             if let Some(ref constraints) = self.viewport_constraints {
1232                 device.account_for_viewport_rule(constraints);
1233             }
1234         }
1235 
1236         self.device = device;
1237         self.media_features_change_changed_style(guards, &self.device)
1238     }
1239 
1240     /// Returns whether, given a media feature change, any previously-applicable
1241     /// style has become non-applicable, or vice-versa for each origin, using
1242     /// `device`.
media_features_change_changed_style( &self, guards: &StylesheetGuards, device: &Device, ) -> OriginSet1243     pub fn media_features_change_changed_style(
1244         &self,
1245         guards: &StylesheetGuards,
1246         device: &Device,
1247     ) -> OriginSet {
1248         debug!("Stylist::media_features_change_changed_style {:?}", device);
1249 
1250         let mut origins = OriginSet::empty();
1251         let stylesheets = self.stylesheets.iter();
1252 
1253         for (stylesheet, origin) in stylesheets {
1254             if origins.contains(origin.into()) {
1255                 continue;
1256             }
1257 
1258             let guard = guards.for_origin(origin);
1259             let origin_cascade_data = self.cascade_data.borrow_for_origin(origin);
1260 
1261             let affected_changed = !origin_cascade_data.media_feature_affected_matches(
1262                 stylesheet,
1263                 guard,
1264                 device,
1265                 self.quirks_mode,
1266             );
1267 
1268             if affected_changed {
1269                 origins |= origin;
1270             }
1271         }
1272 
1273         origins
1274     }
1275 
1276     /// Returns the viewport constraints that apply to this document because of
1277     /// a @viewport rule.
viewport_constraints(&self) -> Option<&ViewportConstraints>1278     pub fn viewport_constraints(&self) -> Option<&ViewportConstraints> {
1279         self.viewport_constraints.as_ref()
1280     }
1281 
1282     /// Returns the Quirks Mode of the document.
quirks_mode(&self) -> QuirksMode1283     pub fn quirks_mode(&self) -> QuirksMode {
1284         self.quirks_mode
1285     }
1286 
1287     /// Sets the quirks mode of the document.
set_quirks_mode(&mut self, quirks_mode: QuirksMode)1288     pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
1289         if self.quirks_mode == quirks_mode {
1290             return;
1291         }
1292         self.quirks_mode = quirks_mode;
1293         self.force_stylesheet_origins_dirty(OriginSet::all());
1294     }
1295 
1296     /// Returns the applicable CSS declarations for the given element.
push_applicable_declarations<E, F>( &self, element: E, pseudo_element: Option<&PseudoElement>, style_attribute: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>, smil_override: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>, animation_declarations: AnimationDeclarations, rule_inclusion: RuleInclusion, applicable_declarations: &mut ApplicableDeclarationList, context: &mut MatchingContext<E::Impl>, flags_setter: &mut F, ) where E: TElement, F: FnMut(&E, ElementSelectorFlags),1297     pub fn push_applicable_declarations<E, F>(
1298         &self,
1299         element: E,
1300         pseudo_element: Option<&PseudoElement>,
1301         style_attribute: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
1302         smil_override: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
1303         animation_declarations: AnimationDeclarations,
1304         rule_inclusion: RuleInclusion,
1305         applicable_declarations: &mut ApplicableDeclarationList,
1306         context: &mut MatchingContext<E::Impl>,
1307         flags_setter: &mut F,
1308     ) where
1309         E: TElement,
1310         F: FnMut(&E, ElementSelectorFlags),
1311     {
1312         RuleCollector::new(
1313             self,
1314             element,
1315             pseudo_element,
1316             style_attribute,
1317             smil_override,
1318             animation_declarations,
1319             rule_inclusion,
1320             applicable_declarations,
1321             context,
1322             flags_setter,
1323         )
1324         .collect_all();
1325     }
1326 
1327     /// Given an id, returns whether there might be any rules for that id in any
1328     /// of our rule maps.
1329     #[inline]
may_have_rules_for_id<E>(&self, id: &WeakAtom, element: E) -> bool where E: TElement,1330     pub fn may_have_rules_for_id<E>(&self, id: &WeakAtom, element: E) -> bool
1331     where
1332         E: TElement,
1333     {
1334         // If id needs to be compared case-insensitively, the logic below
1335         // wouldn't work. Just conservatively assume it may have such rules.
1336         match self.quirks_mode().classes_and_ids_case_sensitivity() {
1337             CaseSensitivity::AsciiCaseInsensitive => return true,
1338             CaseSensitivity::CaseSensitive => {},
1339         }
1340 
1341         self.any_applicable_rule_data(element, |data| data.mapped_ids.contains(id))
1342     }
1343 
1344     /// Returns the registered `@keyframes` animation for the specified name.
1345     #[inline]
get_animation<'a, E>(&'a self, name: &Atom, element: E) -> Option<&'a KeyframesAnimation> where E: TElement + 'a,1346     pub fn get_animation<'a, E>(&'a self, name: &Atom, element: E) -> Option<&'a KeyframesAnimation>
1347     where
1348         E: TElement + 'a,
1349     {
1350         macro_rules! try_find_in {
1351             ($data:expr) => {
1352                 if let Some(animation) = $data.animations.get(name) {
1353                     return Some(animation);
1354                 }
1355             };
1356         }
1357 
1358         // NOTE(emilio): We implement basically what Blink does for this case,
1359         // which is [1] as of this writing.
1360         //
1361         // See [2] for the spec discussion about what to do about this. WebKit's
1362         // behavior makes a bit more sense off-hand, but it's way more complex
1363         // to implement, and it makes value computation having to thread around
1364         // the cascade level, which is not great. Also, it breaks if you inherit
1365         // animation-name from an element in a different tree.
1366         //
1367         // See [3] for the bug to implement whatever gets resolved, and related
1368         // bugs for a bit more context.
1369         //
1370         // FIXME(emilio): This should probably work for pseudo-elements (i.e.,
1371         // use rule_hash_target().shadow_root() instead of
1372         // element.shadow_root()).
1373         //
1374         // [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/
1375         //        core/css/resolver/style_resolver.cc?l=1267&rcl=90f9f8680ebb4a87d177f3b0833372ae4e0c88d8
1376         // [2]: https://github.com/w3c/csswg-drafts/issues/1995
1377         // [3]: https://bugzil.la/1458189
1378         if let Some(shadow) = element.shadow_root() {
1379             if let Some(data) = shadow.style_data() {
1380                 try_find_in!(data);
1381             }
1382         }
1383 
1384         // Use the same rules to look for the containing host as we do for rule
1385         // collection.
1386         if let Some(shadow) = containing_shadow_ignoring_svg_use(element) {
1387             if let Some(data) = shadow.style_data() {
1388                 try_find_in!(data);
1389             }
1390         } else {
1391             try_find_in!(self.cascade_data.author);
1392         }
1393 
1394         try_find_in!(self.cascade_data.user);
1395         try_find_in!(self.cascade_data.user_agent.cascade_data);
1396 
1397         None
1398     }
1399 
1400     /// Computes the match results of a given element against the set of
1401     /// revalidation selectors.
match_revalidation_selectors<E, F>( &self, element: E, bloom: Option<&BloomFilter>, nth_index_cache: &mut NthIndexCache, flags_setter: &mut F, ) -> SmallBitVec where E: TElement, F: FnMut(&E, ElementSelectorFlags),1402     pub fn match_revalidation_selectors<E, F>(
1403         &self,
1404         element: E,
1405         bloom: Option<&BloomFilter>,
1406         nth_index_cache: &mut NthIndexCache,
1407         flags_setter: &mut F,
1408     ) -> SmallBitVec
1409     where
1410         E: TElement,
1411         F: FnMut(&E, ElementSelectorFlags),
1412     {
1413         // NB: `MatchingMode` doesn't really matter, given we don't share style
1414         // between pseudos.
1415         let mut matching_context = MatchingContext::new(
1416             MatchingMode::Normal,
1417             bloom,
1418             Some(nth_index_cache),
1419             self.quirks_mode,
1420         );
1421 
1422         // Note that, by the time we're revalidating, we're guaranteed that the
1423         // candidate and the entry have the same id, classes, and local name.
1424         // This means we're guaranteed to get the same rulehash buckets for all
1425         // the lookups, which means that the bitvecs are comparable. We verify
1426         // this in the caller by asserting that the bitvecs are same-length.
1427         let mut results = SmallBitVec::new();
1428 
1429         let matches_document_rules =
1430             element.each_applicable_non_document_style_rule_data(|data, host| {
1431                 matching_context.with_shadow_host(Some(host), |matching_context| {
1432                     data.selectors_for_cache_revalidation.lookup(
1433                         element,
1434                         self.quirks_mode,
1435                         |selector_and_hashes| {
1436                             results.push(matches_selector(
1437                                 &selector_and_hashes.selector,
1438                                 selector_and_hashes.selector_offset,
1439                                 Some(&selector_and_hashes.hashes),
1440                                 &element,
1441                                 matching_context,
1442                                 flags_setter,
1443                             ));
1444                             true
1445                         },
1446                     );
1447                 })
1448             });
1449 
1450         for (data, origin) in self.cascade_data.iter_origins() {
1451             if origin == Origin::Author && !matches_document_rules {
1452                 continue;
1453             }
1454 
1455             data.selectors_for_cache_revalidation.lookup(
1456                 element,
1457                 self.quirks_mode,
1458                 |selector_and_hashes| {
1459                     results.push(matches_selector(
1460                         &selector_and_hashes.selector,
1461                         selector_and_hashes.selector_offset,
1462                         Some(&selector_and_hashes.hashes),
1463                         &element,
1464                         &mut matching_context,
1465                         flags_setter,
1466                     ));
1467                     true
1468                 },
1469             );
1470         }
1471 
1472         results
1473     }
1474 
1475     /// Computes styles for a given declaration with parent_style.
1476     ///
1477     /// FIXME(emilio): the lack of pseudo / cascade flags look quite dubious,
1478     /// hopefully this is only used for some canvas font stuff.
1479     ///
1480     /// TODO(emilio): The type parameter can go away when
1481     /// https://github.com/rust-lang/rust/issues/35121 is fixed.
compute_for_declarations<E>( &self, guards: &StylesheetGuards, parent_style: &ComputedValues, declarations: Arc<Locked<PropertyDeclarationBlock>>, ) -> Arc<ComputedValues> where E: TElement,1482     pub fn compute_for_declarations<E>(
1483         &self,
1484         guards: &StylesheetGuards,
1485         parent_style: &ComputedValues,
1486         declarations: Arc<Locked<PropertyDeclarationBlock>>,
1487     ) -> Arc<ComputedValues>
1488     where
1489         E: TElement,
1490     {
1491         use crate::font_metrics::get_metrics_provider_for_product;
1492 
1493         let block = declarations.read_with(guards.author);
1494         let metrics = get_metrics_provider_for_product();
1495 
1496         // We don't bother inserting these declarations in the rule tree, since
1497         // it'd be quite useless and slow.
1498         //
1499         // TODO(emilio): Now that we fixed bug 1493420, we should consider
1500         // reversing this as it shouldn't be slow anymore, and should avoid
1501         // generating two instantiations of apply_declarations.
1502         properties::apply_declarations::<E, _>(
1503             &self.device,
1504             /* pseudo = */ None,
1505             self.rule_tree.root(),
1506             guards,
1507             block
1508                 .declaration_importance_iter()
1509                 .map(|(declaration, _)| (declaration, Origin::Author)),
1510             Some(parent_style),
1511             Some(parent_style),
1512             Some(parent_style),
1513             &metrics,
1514             CascadeMode::Unvisited {
1515                 visited_rules: None,
1516             },
1517             self.quirks_mode,
1518             /* rule_cache = */ None,
1519             &mut Default::default(),
1520             /* element = */ None,
1521         )
1522     }
1523 
1524     /// Accessor for a shared reference to the device.
1525     #[inline]
device(&self) -> &Device1526     pub fn device(&self) -> &Device {
1527         &self.device
1528     }
1529 
1530     /// Accessor for a mutable reference to the device.
1531     #[inline]
device_mut(&mut self) -> &mut Device1532     pub fn device_mut(&mut self) -> &mut Device {
1533         &mut self.device
1534     }
1535 
1536     /// Accessor for a shared reference to the rule tree.
1537     #[inline]
rule_tree(&self) -> &RuleTree1538     pub fn rule_tree(&self) -> &RuleTree {
1539         &self.rule_tree
1540     }
1541 
1542     /// Measures heap usage.
1543     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)1544     pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
1545         self.cascade_data.add_size_of(ops, sizes);
1546         self.author_data_cache.add_size_of(ops, sizes);
1547         sizes.mRuleTree += self.rule_tree.size_of(ops);
1548 
1549         // We may measure other fields in the future if DMD says it's worth it.
1550     }
1551 
1552     /// Shutdown the static data that this module stores.
shutdown()1553     pub fn shutdown() {
1554         let _entries = UA_CASCADE_DATA_CACHE.lock().unwrap().take_all();
1555     }
1556 }
1557 
1558 /// This struct holds data which users of Stylist may want to extract
1559 /// from stylesheets which can be done at the same time as updating.
1560 #[derive(Clone, Debug, Default)]
1561 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
1562 pub struct ExtraStyleData {
1563     /// A list of effective font-face rules and their origin.
1564     #[cfg(feature = "gecko")]
1565     pub font_faces: Vec<Arc<Locked<FontFaceRule>>>,
1566 
1567     /// A list of effective font-feature-values rules.
1568     #[cfg(feature = "gecko")]
1569     pub font_feature_values: Vec<Arc<Locked<FontFeatureValuesRule>>>,
1570 
1571     /// A map of effective counter-style rules.
1572     #[cfg(feature = "gecko")]
1573     pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>,
1574 
1575     /// A map of effective page rules.
1576     #[cfg(feature = "gecko")]
1577     pub pages: Vec<Arc<Locked<PageRule>>>,
1578 }
1579 
1580 #[cfg(feature = "gecko")]
1581 impl ExtraStyleData {
1582     /// Add the given @font-face rule.
add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>)1583     fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>) {
1584         self.font_faces.push(rule.clone());
1585     }
1586 
1587     /// Add the given @font-feature-values rule.
add_font_feature_values(&mut self, rule: &Arc<Locked<FontFeatureValuesRule>>)1588     fn add_font_feature_values(&mut self, rule: &Arc<Locked<FontFeatureValuesRule>>) {
1589         self.font_feature_values.push(rule.clone());
1590     }
1591 
1592     /// Add the given @counter-style rule.
add_counter_style( &mut self, guard: &SharedRwLockReadGuard, rule: &Arc<Locked<CounterStyleRule>>, )1593     fn add_counter_style(
1594         &mut self,
1595         guard: &SharedRwLockReadGuard,
1596         rule: &Arc<Locked<CounterStyleRule>>,
1597     ) {
1598         let name = rule.read_with(guard).name().0.clone();
1599         self.counter_styles.insert(name, rule.clone());
1600     }
1601 
1602     /// Add the given @page rule.
add_page(&mut self, rule: &Arc<Locked<PageRule>>)1603     fn add_page(&mut self, rule: &Arc<Locked<PageRule>>) {
1604         self.pages.push(rule.clone());
1605     }
1606 }
1607 
1608 impl ExtraStyleData {
clear(&mut self)1609     fn clear(&mut self) {
1610         #[cfg(feature = "gecko")]
1611         {
1612             self.font_faces.clear();
1613             self.font_feature_values.clear();
1614             self.counter_styles.clear();
1615             self.pages.clear();
1616         }
1617     }
1618 }
1619 
1620 /// An iterator over the different ExtraStyleData.
1621 pub struct ExtraStyleDataIterator<'a>(DocumentCascadeDataIter<'a>);
1622 
1623 impl<'a> Iterator for ExtraStyleDataIterator<'a> {
1624     type Item = (&'a ExtraStyleData, Origin);
1625 
next(&mut self) -> Option<Self::Item>1626     fn next(&mut self) -> Option<Self::Item> {
1627         self.0.next().map(|d| (&d.0.extra_data, d.1))
1628     }
1629 }
1630 
1631 #[cfg(feature = "gecko")]
1632 impl MallocSizeOf for ExtraStyleData {
1633     /// Measure heap usage.
size_of(&self, ops: &mut MallocSizeOfOps) -> usize1634     fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1635         let mut n = 0;
1636         n += self.font_faces.shallow_size_of(ops);
1637         n += self.font_feature_values.shallow_size_of(ops);
1638         n += self.counter_styles.shallow_size_of(ops);
1639         n += self.pages.shallow_size_of(ops);
1640         n
1641     }
1642 }
1643 
1644 /// SelectorMapEntry implementation for use in our revalidation selector map.
1645 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
1646 #[derive(Clone, Debug)]
1647 struct RevalidationSelectorAndHashes {
1648     #[cfg_attr(
1649         feature = "gecko",
1650         ignore_malloc_size_of = "CssRules have primary refs, we measure there"
1651     )]
1652     selector: Selector<SelectorImpl>,
1653     selector_offset: usize,
1654     hashes: AncestorHashes,
1655 }
1656 
1657 impl RevalidationSelectorAndHashes {
new(selector: Selector<SelectorImpl>, hashes: AncestorHashes) -> Self1658     fn new(selector: Selector<SelectorImpl>, hashes: AncestorHashes) -> Self {
1659         let selector_offset = {
1660             // We basically want to check whether the first combinator is a
1661             // pseudo-element combinator.  If it is, we want to use the offset
1662             // one past it.  Otherwise, our offset is 0.
1663             let mut index = 0;
1664             let mut iter = selector.iter();
1665 
1666             // First skip over the first ComplexSelector.
1667             //
1668             // We can't check what sort of what combinator we have until we do
1669             // that.
1670             for _ in &mut iter {
1671                 index += 1; // Simple selector
1672             }
1673 
1674             match iter.next_sequence() {
1675                 Some(Combinator::PseudoElement) => index + 1, // +1 for the combinator
1676                 _ => 0,
1677             }
1678         };
1679 
1680         RevalidationSelectorAndHashes {
1681             selector,
1682             selector_offset,
1683             hashes,
1684         }
1685     }
1686 }
1687 
1688 impl SelectorMapEntry for RevalidationSelectorAndHashes {
selector(&self) -> SelectorIter<SelectorImpl>1689     fn selector(&self) -> SelectorIter<SelectorImpl> {
1690         self.selector.iter_from(self.selector_offset)
1691     }
1692 }
1693 
1694 /// A selector visitor implementation that collects all the state the Stylist
1695 /// cares about a selector.
1696 struct StylistSelectorVisitor<'a> {
1697     /// Whether we've past the rightmost compound selector, not counting
1698     /// pseudo-elements.
1699     passed_rightmost_selector: bool,
1700     /// Whether the selector needs revalidation for the style sharing cache.
1701     needs_revalidation: &'a mut bool,
1702     /// The filter with all the id's getting referenced from rightmost
1703     /// selectors.
1704     mapped_ids: &'a mut PrecomputedHashSet<Atom>,
1705     /// The filter with the local names of attributes there are selectors for.
1706     attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>,
1707     /// All the states selectors in the page reference.
1708     state_dependencies: &'a mut ElementState,
1709     /// All the document states selectors in the page reference.
1710     document_state_dependencies: &'a mut DocumentState,
1711 }
1712 
component_needs_revalidation( c: &Component<SelectorImpl>, passed_rightmost_selector: bool, ) -> bool1713 fn component_needs_revalidation(
1714     c: &Component<SelectorImpl>,
1715     passed_rightmost_selector: bool,
1716 ) -> bool {
1717     match *c {
1718         Component::ID(_) => {
1719             // TODO(emilio): This could also check that the ID is not already in
1720             // the rule hash. In that case, we could avoid making this a
1721             // revalidation selector too.
1722             //
1723             // See https://bugzilla.mozilla.org/show_bug.cgi?id=1369611
1724             passed_rightmost_selector
1725         },
1726         Component::AttributeInNoNamespaceExists { .. } |
1727         Component::AttributeInNoNamespace { .. } |
1728         Component::AttributeOther(_) |
1729         Component::Empty |
1730         Component::FirstChild |
1731         Component::LastChild |
1732         Component::OnlyChild |
1733         Component::NthChild(..) |
1734         Component::NthLastChild(..) |
1735         Component::NthOfType(..) |
1736         Component::NthLastOfType(..) |
1737         Component::FirstOfType |
1738         Component::LastOfType |
1739         Component::OnlyOfType => true,
1740         Component::NonTSPseudoClass(ref p) => p.needs_cache_revalidation(),
1741         _ => false,
1742     }
1743 }
1744 
1745 impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
1746     type Impl = SelectorImpl;
1747 
visit_complex_selector(&mut self, combinator: Option<Combinator>) -> bool1748     fn visit_complex_selector(&mut self, combinator: Option<Combinator>) -> bool {
1749         *self.needs_revalidation =
1750             *self.needs_revalidation || combinator.map_or(false, |c| c.is_sibling());
1751 
1752         // NOTE(emilio): this call happens before we visit any of the simple
1753         // selectors in the next ComplexSelector, so we can use this to skip
1754         // looking at them.
1755         self.passed_rightmost_selector = self.passed_rightmost_selector ||
1756             !matches!(combinator, None | Some(Combinator::PseudoElement));
1757 
1758         true
1759     }
1760 
visit_selector_list(&mut self, list: &[Selector<Self::Impl>]) -> bool1761     fn visit_selector_list(&mut self, list: &[Selector<Self::Impl>]) -> bool {
1762         for selector in list {
1763             let mut nested = StylistSelectorVisitor {
1764                 passed_rightmost_selector: false,
1765                 needs_revalidation: &mut *self.needs_revalidation,
1766                 attribute_dependencies: &mut *self.attribute_dependencies,
1767                 state_dependencies: &mut *self.state_dependencies,
1768                 document_state_dependencies: &mut *self.document_state_dependencies,
1769                 mapped_ids: &mut *self.mapped_ids,
1770             };
1771             let _ret = selector.visit(&mut nested);
1772             debug_assert!(_ret, "We never return false");
1773         }
1774         true
1775     }
1776 
visit_attribute_selector( &mut self, _ns: &NamespaceConstraint<&Namespace>, name: &LocalName, lower_name: &LocalName, ) -> bool1777     fn visit_attribute_selector(
1778         &mut self,
1779         _ns: &NamespaceConstraint<&Namespace>,
1780         name: &LocalName,
1781         lower_name: &LocalName,
1782     ) -> bool {
1783         self.attribute_dependencies.insert(name.clone());
1784         self.attribute_dependencies.insert(lower_name.clone());
1785         true
1786     }
1787 
visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool1788     fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
1789         *self.needs_revalidation = *self.needs_revalidation ||
1790             component_needs_revalidation(s, self.passed_rightmost_selector);
1791 
1792         match *s {
1793             Component::NonTSPseudoClass(ref p) => {
1794                 self.state_dependencies.insert(p.state_flag());
1795                 self.document_state_dependencies
1796                     .insert(p.document_state_flag());
1797             },
1798             Component::ID(ref id) if !self.passed_rightmost_selector => {
1799                 // We want to stop storing mapped ids as soon as we've moved off
1800                 // the rightmost ComplexSelector that is not a pseudo-element.
1801                 //
1802                 // That can be detected by a visit_complex_selector call with a
1803                 // combinator other than None and PseudoElement.
1804                 //
1805                 // Importantly, this call happens before we visit any of the
1806                 // simple selectors in that ComplexSelector.
1807                 //
1808                 // NOTE(emilio): See the comment regarding on when this may
1809                 // break in visit_complex_selector.
1810                 self.mapped_ids.insert(id.0.clone());
1811             },
1812             _ => {},
1813         }
1814 
1815         true
1816     }
1817 }
1818 
1819 /// A set of rules for element and pseudo-elements.
1820 #[derive(Clone, Debug, Default, MallocSizeOf)]
1821 struct GenericElementAndPseudoRules<Map> {
1822     /// Rules from stylesheets at this `CascadeData`'s origin.
1823     element_map: Map,
1824 
1825     /// Rules from stylesheets at this `CascadeData`'s origin that correspond
1826     /// to a given pseudo-element.
1827     ///
1828     /// FIXME(emilio): There are a bunch of wasted entries here in practice.
1829     /// Figure out a good way to do a `PerNonAnonBox` and `PerAnonBox` (for
1830     /// `precomputed_values_for_pseudo`) without duplicating a lot of code.
1831     pseudos_map: PerPseudoElementMap<Box<Map>>,
1832 }
1833 
1834 impl<Map: Default + MallocSizeOf> GenericElementAndPseudoRules<Map> {
1835     #[inline(always)]
for_insertion(&mut self, pseudo_element: Option<&PseudoElement>) -> &mut Map1836     fn for_insertion(&mut self, pseudo_element: Option<&PseudoElement>) -> &mut Map {
1837         debug_assert!(
1838             pseudo_element.map_or(true, |pseudo| {
1839                 !pseudo.is_precomputed() && !pseudo.is_unknown_webkit_pseudo_element()
1840             }),
1841             "Precomputed pseudos should end up in precomputed_pseudo_element_decls, \
1842              and unknown webkit pseudos should be discarded before getting here"
1843         );
1844 
1845         match pseudo_element {
1846             None => &mut self.element_map,
1847             Some(pseudo) => self
1848                 .pseudos_map
1849                 .get_or_insert_with(pseudo, || Box::new(Default::default())),
1850         }
1851     }
1852 
1853     #[inline]
rules(&self, pseudo: Option<&PseudoElement>) -> Option<&Map>1854     fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&Map> {
1855         match pseudo {
1856             Some(pseudo) => self.pseudos_map.get(pseudo).map(|p| &**p),
1857             None => Some(&self.element_map),
1858         }
1859     }
1860 
1861     /// Measures heap usage.
1862     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)1863     fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
1864         sizes.mElementAndPseudosMaps += self.element_map.size_of(ops);
1865 
1866         for elem in self.pseudos_map.iter() {
1867             if let Some(ref elem) = *elem {
1868                 sizes.mElementAndPseudosMaps += <Box<_> as MallocSizeOf>::size_of(elem, ops);
1869             }
1870         }
1871     }
1872 }
1873 
1874 type ElementAndPseudoRules = GenericElementAndPseudoRules<SelectorMap<Rule>>;
1875 type PartMap = PrecomputedHashMap<Atom, SmallVec<[Rule; 1]>>;
1876 type PartElementAndPseudoRules = GenericElementAndPseudoRules<PartMap>;
1877 
1878 impl ElementAndPseudoRules {
1879     // TODO(emilio): Should we retain storage of these?
clear(&mut self)1880     fn clear(&mut self) {
1881         self.element_map.clear();
1882         self.pseudos_map.clear();
1883     }
1884 }
1885 
1886 impl PartElementAndPseudoRules {
1887     // TODO(emilio): Should we retain storage of these?
clear(&mut self)1888     fn clear(&mut self) {
1889         self.element_map.clear();
1890         self.pseudos_map.clear();
1891     }
1892 }
1893 
1894 /// Data resulting from performing the CSS cascade that is specific to a given
1895 /// origin.
1896 ///
1897 /// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
1898 /// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
1899 #[derive(Debug, Clone, MallocSizeOf)]
1900 pub struct CascadeData {
1901     /// The data coming from normal style rules that apply to elements at this
1902     /// cascade level.
1903     normal_rules: ElementAndPseudoRules,
1904 
1905     /// The `:host` pseudo rules that are the rightmost selector (without
1906     /// accounting for pseudo-elements).
1907     host_rules: Option<Box<ElementAndPseudoRules>>,
1908 
1909     /// The data coming from ::slotted() pseudo-element rules.
1910     ///
1911     /// We need to store them separately because an element needs to match
1912     /// ::slotted() pseudo-element rules in different shadow roots.
1913     ///
1914     /// In particular, we need to go through all the style data in all the
1915     /// containing style scopes starting from the closest assigned slot.
1916     slotted_rules: Option<Box<ElementAndPseudoRules>>,
1917 
1918     /// The data coming from ::part() pseudo-element rules.
1919     ///
1920     /// We need to store them separately because an element needs to match
1921     /// ::part() pseudo-element rules in different shadow roots.
1922     part_rules: Option<Box<PartElementAndPseudoRules>>,
1923 
1924     /// The invalidation map for these rules.
1925     invalidation_map: InvalidationMap,
1926 
1927     /// The attribute local names that appear in attribute selectors.  Used
1928     /// to avoid taking element snapshots when an irrelevant attribute changes.
1929     /// (We don't bother storing the namespace, since namespaced attributes are
1930     /// rare.)
1931     attribute_dependencies: PrecomputedHashSet<LocalName>,
1932 
1933     /// The element state bits that are relied on by selectors.  Like
1934     /// `attribute_dependencies`, this is used to avoid taking element snapshots
1935     /// when an irrelevant element state bit changes.
1936     state_dependencies: ElementState,
1937 
1938     /// The document state bits that are relied on by selectors.  This is used
1939     /// to tell whether we need to restyle the entire document when a document
1940     /// state bit changes.
1941     document_state_dependencies: DocumentState,
1942 
1943     /// The ids that appear in the rightmost complex selector of selectors (and
1944     /// hence in our selector maps).  Used to determine when sharing styles is
1945     /// safe: we disallow style sharing for elements whose id matches this
1946     /// filter, and hence might be in one of our selector maps.
1947     mapped_ids: PrecomputedHashSet<Atom>,
1948 
1949     /// Selectors that require explicit cache revalidation (i.e. which depend
1950     /// on state that is not otherwise visible to the cache, like attributes or
1951     /// tree-structural state like child index and pseudos).
1952     #[ignore_malloc_size_of = "Arc"]
1953     selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
1954 
1955     /// A map with all the animations at this `CascadeData`'s origin, indexed
1956     /// by name.
1957     animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
1958 
1959     /// Effective media query results cached from the last rebuild.
1960     effective_media_query_results: EffectiveMediaQueryResults,
1961 
1962     /// Extra data, like different kinds of rules, etc.
1963     extra_data: ExtraStyleData,
1964 
1965     /// A monotonically increasing counter to represent the order on which a
1966     /// style rule appears in a stylesheet, needed to sort them by source order.
1967     rules_source_order: u32,
1968 
1969     /// The total number of selectors.
1970     num_selectors: usize,
1971 
1972     /// The total number of declarations.
1973     num_declarations: usize,
1974 }
1975 
1976 impl CascadeData {
1977     /// Creates an empty `CascadeData`.
new() -> Self1978     pub fn new() -> Self {
1979         Self {
1980             normal_rules: ElementAndPseudoRules::default(),
1981             host_rules: None,
1982             slotted_rules: None,
1983             part_rules: None,
1984             invalidation_map: InvalidationMap::new(),
1985             attribute_dependencies: PrecomputedHashSet::default(),
1986             state_dependencies: ElementState::empty(),
1987             document_state_dependencies: DocumentState::empty(),
1988             mapped_ids: PrecomputedHashSet::default(),
1989             selectors_for_cache_revalidation: SelectorMap::new(),
1990             animations: Default::default(),
1991             extra_data: ExtraStyleData::default(),
1992             effective_media_query_results: EffectiveMediaQueryResults::new(),
1993             rules_source_order: 0,
1994             num_selectors: 0,
1995             num_declarations: 0,
1996         }
1997     }
1998 
1999     /// Rebuild the cascade data from a given SheetCollection, incrementally if
2000     /// possible.
rebuild<'a, S>( &mut self, device: &Device, quirks_mode: QuirksMode, collection: SheetCollectionFlusher<S>, guard: &SharedRwLockReadGuard, ) -> Result<(), FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static,2001     pub fn rebuild<'a, S>(
2002         &mut self,
2003         device: &Device,
2004         quirks_mode: QuirksMode,
2005         collection: SheetCollectionFlusher<S>,
2006         guard: &SharedRwLockReadGuard,
2007     ) -> Result<(), FailedAllocationError>
2008     where
2009         S: StylesheetInDocument + PartialEq + 'static,
2010     {
2011         if !collection.dirty() {
2012             return Ok(());
2013         }
2014 
2015         let validity = collection.data_validity();
2016 
2017         match validity {
2018             DataValidity::Valid => {},
2019             DataValidity::CascadeInvalid => self.clear_cascade_data(),
2020             DataValidity::FullyInvalid => self.clear(),
2021         }
2022 
2023         let mut result = Ok(());
2024 
2025         collection.each(|stylesheet, rebuild_kind| {
2026             result = self.add_stylesheet(
2027                 device,
2028                 quirks_mode,
2029                 stylesheet,
2030                 guard,
2031                 rebuild_kind,
2032                 /* precomputed_pseudo_element_decls = */ None,
2033             );
2034             result.is_ok()
2035         });
2036 
2037         result
2038     }
2039 
2040     /// Returns the invalidation map.
invalidation_map(&self) -> &InvalidationMap2041     pub fn invalidation_map(&self) -> &InvalidationMap {
2042         &self.invalidation_map
2043     }
2044 
2045     /// Returns whether the given ElementState bit is relied upon by a selector
2046     /// of some rule.
2047     #[inline]
has_state_dependency(&self, state: ElementState) -> bool2048     pub fn has_state_dependency(&self, state: ElementState) -> bool {
2049         self.state_dependencies.intersects(state)
2050     }
2051 
2052     /// Returns whether the given attribute might appear in an attribute
2053     /// selector of some rule.
2054     #[inline]
might_have_attribute_dependency(&self, local_name: &LocalName) -> bool2055     pub fn might_have_attribute_dependency(&self, local_name: &LocalName) -> bool {
2056         self.attribute_dependencies.contains(local_name)
2057     }
2058 
2059     /// Returns the normal rule map for a given pseudo-element.
2060     #[inline]
normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>>2061     pub fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
2062         self.normal_rules.rules(pseudo)
2063     }
2064 
2065     /// Returns the host pseudo rule map for a given pseudo-element.
2066     #[inline]
host_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>>2067     pub fn host_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
2068         self.host_rules.as_ref().and_then(|d| d.rules(pseudo))
2069     }
2070 
2071     /// Whether there's any host rule that could match in this scope.
any_host_rules(&self) -> bool2072     pub fn any_host_rules(&self) -> bool {
2073         self.host_rules.is_some()
2074     }
2075 
2076     /// Returns the slotted rule map for a given pseudo-element.
2077     #[inline]
slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>>2078     pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
2079         self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo))
2080     }
2081 
2082     /// Whether there's any ::slotted rule that could match in this scope.
any_slotted_rule(&self) -> bool2083     pub fn any_slotted_rule(&self) -> bool {
2084         self.slotted_rules.is_some()
2085     }
2086 
2087     /// Returns the parts rule map for a given pseudo-element.
2088     #[inline]
part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap>2089     pub fn part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap> {
2090         self.part_rules.as_ref().and_then(|d| d.rules(pseudo))
2091     }
2092 
2093     /// Whether there's any ::part rule that could match in this scope.
any_part_rule(&self) -> bool2094     pub fn any_part_rule(&self) -> bool {
2095         self.part_rules.is_some()
2096     }
2097 
2098     /// Collects all the applicable media query results into `results`.
2099     ///
2100     /// This duplicates part of the logic in `add_stylesheet`, which is
2101     /// a bit unfortunate.
2102     ///
2103     /// FIXME(emilio): With a bit of smartness in
2104     /// `media_feature_affected_matches`, we could convert
2105     /// `EffectiveMediaQueryResults` into a vector without too much effort.
collect_applicable_media_query_results_into<S>( device: &Device, stylesheet: &S, guard: &SharedRwLockReadGuard, results: &mut Vec<MediaListKey>, contents_list: &mut StyleSheetContentList, ) where S: StylesheetInDocument + 'static,2106     fn collect_applicable_media_query_results_into<S>(
2107         device: &Device,
2108         stylesheet: &S,
2109         guard: &SharedRwLockReadGuard,
2110         results: &mut Vec<MediaListKey>,
2111         contents_list: &mut StyleSheetContentList,
2112     ) where
2113         S: StylesheetInDocument + 'static,
2114     {
2115         if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
2116             return;
2117         }
2118 
2119         debug!(" + {:?}", stylesheet);
2120         let contents = stylesheet.contents();
2121         results.push(contents.to_media_list_key());
2122 
2123         // Safety: StyleSheetContents are reference-counted with Arc.
2124         contents_list.push(StylesheetContentsPtr(unsafe {
2125             Arc::from_raw_addrefed(contents)
2126         }));
2127 
2128         for rule in stylesheet.effective_rules(device, guard) {
2129             match *rule {
2130                 CssRule::Import(ref lock) => {
2131                     let import_rule = lock.read_with(guard);
2132                     debug!(" + {:?}", import_rule.stylesheet.media(guard));
2133                     results.push(import_rule.to_media_list_key());
2134                 },
2135                 CssRule::Media(ref lock) => {
2136                     let media_rule = lock.read_with(guard);
2137                     debug!(" + {:?}", media_rule.media_queries.read_with(guard));
2138                     results.push(media_rule.to_media_list_key());
2139                 },
2140                 _ => {},
2141             }
2142         }
2143     }
2144 
2145     // Returns Err(..) to signify OOM
add_stylesheet<S>( &mut self, device: &Device, quirks_mode: QuirksMode, stylesheet: &S, guard: &SharedRwLockReadGuard, rebuild_kind: SheetRebuildKind, mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>, ) -> Result<(), FailedAllocationError> where S: StylesheetInDocument + 'static,2146     fn add_stylesheet<S>(
2147         &mut self,
2148         device: &Device,
2149         quirks_mode: QuirksMode,
2150         stylesheet: &S,
2151         guard: &SharedRwLockReadGuard,
2152         rebuild_kind: SheetRebuildKind,
2153         mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
2154     ) -> Result<(), FailedAllocationError>
2155     where
2156         S: StylesheetInDocument + 'static,
2157     {
2158         if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
2159             return Ok(());
2160         }
2161 
2162         let contents = stylesheet.contents();
2163         let origin = contents.origin;
2164 
2165         if rebuild_kind.should_rebuild_invalidation() {
2166             self.effective_media_query_results.saw_effective(contents);
2167         }
2168 
2169         for rule in stylesheet.effective_rules(device, guard) {
2170             match *rule {
2171                 CssRule::Style(ref locked) => {
2172                     let style_rule = locked.read_with(&guard);
2173                     self.num_declarations += style_rule.block.read_with(&guard).len();
2174                     for selector in &style_rule.selectors.0 {
2175                         self.num_selectors += 1;
2176 
2177                         let pseudo_element = selector.pseudo_element();
2178 
2179                         if let Some(pseudo) = pseudo_element {
2180                             if pseudo.is_precomputed() {
2181                                 debug_assert!(selector.is_universal());
2182                                 debug_assert!(matches!(origin, Origin::UserAgent));
2183 
2184                                 precomputed_pseudo_element_decls
2185                                     .as_mut()
2186                                     .expect("Expected precomputed declarations for the UA level")
2187                                     .get_or_insert_with(pseudo, Vec::new)
2188                                     .push(ApplicableDeclarationBlock::new(
2189                                         StyleSource::from_rule(locked.clone()),
2190                                         self.rules_source_order,
2191                                         CascadeLevel::UANormal,
2192                                         selector.specificity(),
2193                                     ));
2194                                 continue;
2195                             }
2196                             if pseudo.is_unknown_webkit_pseudo_element() {
2197                                 continue;
2198                             }
2199                         }
2200 
2201                         let hashes = AncestorHashes::new(&selector, quirks_mode);
2202 
2203                         let rule = Rule::new(
2204                             selector.clone(),
2205                             hashes,
2206                             locked.clone(),
2207                             self.rules_source_order,
2208                         );
2209 
2210                         if rebuild_kind.should_rebuild_invalidation() {
2211                             self.invalidation_map.note_selector(selector, quirks_mode)?;
2212                             let mut needs_revalidation = false;
2213                             let mut visitor = StylistSelectorVisitor {
2214                                 needs_revalidation: &mut needs_revalidation,
2215                                 passed_rightmost_selector: false,
2216                                 attribute_dependencies: &mut self.attribute_dependencies,
2217                                 state_dependencies: &mut self.state_dependencies,
2218                                 document_state_dependencies: &mut self.document_state_dependencies,
2219                                 mapped_ids: &mut self.mapped_ids,
2220                             };
2221 
2222                             rule.selector.visit(&mut visitor);
2223 
2224                             if needs_revalidation {
2225                                 self.selectors_for_cache_revalidation.insert(
2226                                     RevalidationSelectorAndHashes::new(
2227                                         rule.selector.clone(),
2228                                         rule.hashes.clone(),
2229                                     ),
2230                                     quirks_mode,
2231                                 )?;
2232                             }
2233                         }
2234 
2235                         // Part is special, since given it doesn't have any
2236                         // selectors inside, it's not worth using a whole
2237                         // SelectorMap for it.
2238                         if let Some(parts) = selector.parts() {
2239                             // ::part() has all semantics, so we just need to
2240                             // put any of them in the selector map.
2241                             //
2242                             // We choose the last one quite arbitrarily,
2243                             // expecting it's slightly more likely to be more
2244                             // specific.
2245                             self.part_rules
2246                                 .get_or_insert_with(|| Box::new(Default::default()))
2247                                 .for_insertion(pseudo_element)
2248                                 .try_entry(parts.last().unwrap().clone().0)?
2249                                 .or_insert_with(SmallVec::new)
2250                                 .try_push(rule)?;
2251                         } else {
2252                             // NOTE(emilio): It's fine to look at :host and then at
2253                             // ::slotted(..), since :host::slotted(..) could never
2254                             // possibly match, as <slot> is not a valid shadow host.
2255                             let rules =
2256                                 if selector.is_featureless_host_selector_or_pseudo_element() {
2257                                     self.host_rules
2258                                         .get_or_insert_with(|| Box::new(Default::default()))
2259                                 } else if selector.is_slotted() {
2260                                     self.slotted_rules
2261                                         .get_or_insert_with(|| Box::new(Default::default()))
2262                                 } else {
2263                                     &mut self.normal_rules
2264                                 }
2265                                 .for_insertion(pseudo_element);
2266                             rules.insert(rule, quirks_mode)?;
2267                         }
2268                     }
2269                     self.rules_source_order += 1;
2270                 },
2271                 CssRule::Import(ref lock) => {
2272                     if rebuild_kind.should_rebuild_invalidation() {
2273                         let import_rule = lock.read_with(guard);
2274                         self.effective_media_query_results
2275                             .saw_effective(import_rule);
2276                     }
2277 
2278                     // NOTE: effective_rules visits the inner stylesheet if
2279                     // appropriate.
2280                 },
2281                 CssRule::Media(ref lock) => {
2282                     if rebuild_kind.should_rebuild_invalidation() {
2283                         let media_rule = lock.read_with(guard);
2284                         self.effective_media_query_results.saw_effective(media_rule);
2285                     }
2286                 },
2287                 CssRule::Keyframes(ref keyframes_rule) => {
2288                     let keyframes_rule = keyframes_rule.read_with(guard);
2289                     debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
2290 
2291                     // Don't let a prefixed keyframes animation override a non-prefixed one.
2292                     let needs_insertion = keyframes_rule.vendor_prefix.is_none() ||
2293                         self.animations
2294                             .get(keyframes_rule.name.as_atom())
2295                             .map_or(true, |rule| rule.vendor_prefix.is_some());
2296                     if needs_insertion {
2297                         let animation = KeyframesAnimation::from_keyframes(
2298                             &keyframes_rule.keyframes,
2299                             keyframes_rule.vendor_prefix.clone(),
2300                             guard,
2301                         );
2302                         debug!("Found valid keyframe animation: {:?}", animation);
2303                         self.animations
2304                             .try_insert(keyframes_rule.name.as_atom().clone(), animation)?;
2305                     }
2306                 },
2307                 #[cfg(feature = "gecko")]
2308                 CssRule::FontFace(ref rule) => {
2309                     self.extra_data.add_font_face(rule);
2310                 },
2311                 #[cfg(feature = "gecko")]
2312                 CssRule::FontFeatureValues(ref rule) => {
2313                     self.extra_data.add_font_feature_values(rule);
2314                 },
2315                 #[cfg(feature = "gecko")]
2316                 CssRule::CounterStyle(ref rule) => {
2317                     self.extra_data.add_counter_style(guard, rule);
2318                 },
2319                 #[cfg(feature = "gecko")]
2320                 CssRule::Page(ref rule) => {
2321                     self.extra_data.add_page(rule);
2322                 },
2323                 // We don't care about any other rule.
2324                 _ => {},
2325             }
2326         }
2327 
2328         Ok(())
2329     }
2330 
2331     /// Returns whether all the media-feature affected values matched before and
2332     /// match now in the given stylesheet.
media_feature_affected_matches<S>( &self, stylesheet: &S, guard: &SharedRwLockReadGuard, device: &Device, quirks_mode: QuirksMode, ) -> bool where S: StylesheetInDocument + 'static,2333     pub fn media_feature_affected_matches<S>(
2334         &self,
2335         stylesheet: &S,
2336         guard: &SharedRwLockReadGuard,
2337         device: &Device,
2338         quirks_mode: QuirksMode,
2339     ) -> bool
2340     where
2341         S: StylesheetInDocument + 'static,
2342     {
2343         use crate::invalidation::media_queries::PotentiallyEffectiveMediaRules;
2344 
2345         let effective_now = stylesheet.is_effective_for_device(device, guard);
2346 
2347         let effective_then = self.effective_media_query_results.was_effective(stylesheet.contents());
2348 
2349         if effective_now != effective_then {
2350             debug!(
2351                 " > Stylesheet {:?} changed -> {}, {}",
2352                 stylesheet.media(guard),
2353                 effective_then,
2354                 effective_now
2355             );
2356             return false;
2357         }
2358 
2359         if !effective_now {
2360             return true;
2361         }
2362 
2363         let mut iter = stylesheet.iter_rules::<PotentiallyEffectiveMediaRules>(device, guard);
2364 
2365         while let Some(rule) = iter.next() {
2366             match *rule {
2367                 CssRule::Style(..) |
2368                 CssRule::Namespace(..) |
2369                 CssRule::FontFace(..) |
2370                 CssRule::CounterStyle(..) |
2371                 CssRule::Supports(..) |
2372                 CssRule::Keyframes(..) |
2373                 CssRule::Page(..) |
2374                 CssRule::Viewport(..) |
2375                 CssRule::Document(..) |
2376                 CssRule::FontFeatureValues(..) => {
2377                     // Not affected by device changes.
2378                     continue;
2379                 },
2380                 CssRule::Import(ref lock) => {
2381                     let import_rule = lock.read_with(guard);
2382                     let effective_now = match import_rule.stylesheet.media(guard) {
2383                         Some(m) => m.evaluate(device, quirks_mode),
2384                         None => true,
2385                     };
2386                     let effective_then = self
2387                         .effective_media_query_results
2388                         .was_effective(import_rule);
2389                     if effective_now != effective_then {
2390                         debug!(
2391                             " > @import rule {:?} changed {} -> {}",
2392                             import_rule.stylesheet.media(guard),
2393                             effective_then,
2394                             effective_now
2395                         );
2396                         return false;
2397                     }
2398 
2399                     if !effective_now {
2400                         iter.skip_children();
2401                     }
2402                 },
2403                 CssRule::Media(ref lock) => {
2404                     let media_rule = lock.read_with(guard);
2405                     let mq = media_rule.media_queries.read_with(guard);
2406                     let effective_now = mq.evaluate(device, quirks_mode);
2407                     let effective_then =
2408                         self.effective_media_query_results.was_effective(media_rule);
2409 
2410                     if effective_now != effective_then {
2411                         debug!(
2412                             " > @media rule {:?} changed {} -> {}",
2413                             mq, effective_then, effective_now
2414                         );
2415                         return false;
2416                     }
2417 
2418                     if !effective_now {
2419                         iter.skip_children();
2420                     }
2421                 },
2422             }
2423         }
2424 
2425         true
2426     }
2427 
2428     /// Clears the cascade data, but not the invalidation data.
clear_cascade_data(&mut self)2429     fn clear_cascade_data(&mut self) {
2430         self.normal_rules.clear();
2431         if let Some(ref mut slotted_rules) = self.slotted_rules {
2432             slotted_rules.clear();
2433         }
2434         if let Some(ref mut part_rules) = self.part_rules {
2435             part_rules.clear();
2436         }
2437         if let Some(ref mut host_rules) = self.host_rules {
2438             host_rules.clear();
2439         }
2440         self.animations.clear();
2441         self.extra_data.clear();
2442         self.rules_source_order = 0;
2443         self.num_selectors = 0;
2444         self.num_declarations = 0;
2445     }
2446 
clear(&mut self)2447     fn clear(&mut self) {
2448         self.clear_cascade_data();
2449         self.invalidation_map.clear();
2450         self.attribute_dependencies.clear();
2451         self.state_dependencies = ElementState::empty();
2452         self.document_state_dependencies = DocumentState::empty();
2453         self.mapped_ids.clear();
2454         self.selectors_for_cache_revalidation.clear();
2455         self.effective_media_query_results.clear();
2456     }
2457 }
2458 
2459 impl CascadeDataCacheEntry for CascadeData {
cascade_data(&self) -> &CascadeData2460     fn cascade_data(&self) -> &CascadeData {
2461         self
2462     }
2463 
rebuild<S>( device: &Device, quirks_mode: QuirksMode, collection: SheetCollectionFlusher<S>, guard: &SharedRwLockReadGuard, old: &Self, ) -> Result<Arc<Self>, FailedAllocationError> where S: StylesheetInDocument + PartialEq + 'static2464     fn rebuild<S>(
2465         device: &Device,
2466         quirks_mode: QuirksMode,
2467         collection: SheetCollectionFlusher<S>,
2468         guard: &SharedRwLockReadGuard,
2469         old: &Self,
2470     ) -> Result<Arc<Self>, FailedAllocationError>
2471     where
2472         S: StylesheetInDocument + PartialEq + 'static
2473     {
2474         debug_assert!(collection.dirty(), "We surely need to do something?");
2475         // If we're doing a full rebuild anyways, don't bother cloning the data.
2476         let mut updatable_entry = match collection.data_validity() {
2477             DataValidity::Valid | DataValidity::CascadeInvalid => old.clone(),
2478             DataValidity::FullyInvalid => Self::new(),
2479         };
2480         updatable_entry.rebuild(device, quirks_mode, collection, guard)?;
2481         Ok(Arc::new(updatable_entry))
2482     }
2483 
2484     #[cfg(feature = "gecko")]
add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes)2485     fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
2486         self.normal_rules.add_size_of(ops, sizes);
2487         if let Some(ref slotted_rules) = self.slotted_rules {
2488             slotted_rules.add_size_of(ops, sizes);
2489         }
2490         if let Some(ref part_rules) = self.part_rules {
2491             part_rules.add_size_of(ops, sizes);
2492         }
2493         if let Some(ref host_rules) = self.host_rules {
2494             host_rules.add_size_of(ops, sizes);
2495         }
2496         sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
2497         sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
2498         sizes.mOther += self.animations.size_of(ops);
2499         sizes.mOther += self.effective_media_query_results.size_of(ops);
2500         sizes.mOther += self.extra_data.size_of(ops);
2501     }
2502 }
2503 
2504 impl Default for CascadeData {
default() -> Self2505     fn default() -> Self {
2506         CascadeData::new()
2507     }
2508 }
2509 
2510 /// A rule, that wraps a style rule, but represents a single selector of the
2511 /// rule.
2512 #[derive(Clone, Debug, MallocSizeOf)]
2513 pub struct Rule {
2514     /// The selector this struct represents. We store this and the
2515     /// any_{important,normal} booleans inline in the Rule to avoid
2516     /// pointer-chasing when gathering applicable declarations, which
2517     /// can ruin performance when there are a lot of rules.
2518     #[ignore_malloc_size_of = "CssRules have primary refs, we measure there"]
2519     pub selector: Selector<SelectorImpl>,
2520 
2521     /// The ancestor hashes associated with the selector.
2522     pub hashes: AncestorHashes,
2523 
2524     /// The source order this style rule appears in. Note that we only use
2525     /// three bytes to store this value in ApplicableDeclarationsBlock, so
2526     /// we could repurpose that storage here if we needed to.
2527     pub source_order: u32,
2528 
2529     /// The actual style rule.
2530     #[cfg_attr(
2531         feature = "gecko",
2532         ignore_malloc_size_of = "Secondary ref. Primary ref is in StyleRule under Stylesheet."
2533     )]
2534     #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
2535     pub style_rule: Arc<Locked<StyleRule>>,
2536 }
2537 
2538 impl SelectorMapEntry for Rule {
selector(&self) -> SelectorIter<SelectorImpl>2539     fn selector(&self) -> SelectorIter<SelectorImpl> {
2540         self.selector.iter()
2541     }
2542 }
2543 
2544 impl Rule {
2545     /// Returns the specificity of the rule.
specificity(&self) -> u322546     pub fn specificity(&self) -> u32 {
2547         self.selector.specificity()
2548     }
2549 
2550     /// Turns this rule into an `ApplicableDeclarationBlock` for the given
2551     /// cascade level.
to_applicable_declaration_block( &self, level: CascadeLevel, ) -> ApplicableDeclarationBlock2552     pub fn to_applicable_declaration_block(
2553         &self,
2554         level: CascadeLevel,
2555     ) -> ApplicableDeclarationBlock {
2556         let source = StyleSource::from_rule(self.style_rule.clone());
2557         ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity())
2558     }
2559 
2560     /// Creates a new Rule.
new( selector: Selector<SelectorImpl>, hashes: AncestorHashes, style_rule: Arc<Locked<StyleRule>>, source_order: u32, ) -> Self2561     pub fn new(
2562         selector: Selector<SelectorImpl>,
2563         hashes: AncestorHashes,
2564         style_rule: Arc<Locked<StyleRule>>,
2565         source_order: u32,
2566     ) -> Self {
2567         Rule {
2568             selector: selector,
2569             hashes: hashes,
2570             style_rule: style_rule,
2571             source_order: source_order,
2572         }
2573     }
2574 }
2575 
2576 /// A function to be able to test the revalidation stuff.
needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool2577 pub fn needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool {
2578     let mut attribute_dependencies = Default::default();
2579     let mut mapped_ids = Default::default();
2580     let mut state_dependencies = ElementState::empty();
2581     let mut document_state_dependencies = DocumentState::empty();
2582     let mut needs_revalidation = false;
2583     let mut visitor = StylistSelectorVisitor {
2584         passed_rightmost_selector: false,
2585         needs_revalidation: &mut needs_revalidation,
2586         attribute_dependencies: &mut attribute_dependencies,
2587         state_dependencies: &mut state_dependencies,
2588         document_state_dependencies: &mut document_state_dependencies,
2589         mapped_ids: &mut mapped_ids,
2590     };
2591     s.visit(&mut visitor);
2592     needs_revalidation
2593 }
2594