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