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