diff options
-rw-r--r-- | components/style/gecko/data.rs | 14 | ||||
-rw-r--r-- | components/style/gecko/media_queries.rs | 5 | ||||
-rw-r--r-- | components/style/traversal.rs | 36 |
3 files changed, 46 insertions, 9 deletions
diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 39f7d7cc8d8..cabae61d563 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -129,6 +129,12 @@ impl StylesheetInDocument for GeckoStyleSheet { pub struct PerDocumentStyleDataImpl { /// Rule processor. pub stylist: Stylist, + + /// A cache from element to resolved style. + pub undisplayed_style_cache: crate::traversal::UndisplayedStyleCache, + + /// The generation for which our cache is valid. + pub undisplayed_style_cache_generation: u64, } /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics @@ -143,6 +149,8 @@ impl PerDocumentStyleData { PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { stylist: Stylist::new(device, quirks_mode.into()), + undisplayed_style_cache: Default::default(), + undisplayed_style_cache_generation: 0, })) } @@ -177,12 +185,6 @@ impl PerDocumentStyleDataImpl { self.stylist.device().default_computed_values_arc() } - /// Returns whether visited styles are enabled. - #[inline] - pub fn visited_styles_enabled(&self) -> bool { - unsafe { bindings::Gecko_VisitedStylesEnabled(self.stylist.device().document()) } - } - /// Measure heap usage. pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { self.stylist.add_size_of(ops, sizes); diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index a54b02a756d..837cc61fffe 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -411,6 +411,11 @@ impl Device { self.used_font_metrics.load(Ordering::Relaxed) } + /// Returns whether visited styles are enabled. + pub fn visited_styles_enabled(&self) -> bool { + unsafe { bindings::Gecko_VisitedStylesEnabled(self.document()) } + } + /// Returns the device pixel ratio. pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> { let pc = match self.pres_context() { diff --git a/components/style/traversal.rs b/components/style/traversal.rs index bf0b963c709..fcaeb6e9c57 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -16,6 +16,13 @@ use crate::stylist::RuleInclusion; use crate::traversal_flags::TraversalFlags; use selectors::NthIndexCache; use smallvec::SmallVec; +use std::collections::HashMap; + +/// A cache from element reference to known-valid computed style. +pub type UndisplayedStyleCache = HashMap< + selectors::OpaqueElement, + servo_arc::Arc<crate::properties::ComputedValues>, +>; /// A per-traversal-level chunk of data. This is sent down by the traversal, and /// currently only holds the dom depth for the bloom filter. @@ -294,6 +301,7 @@ pub fn resolve_style<E>( element: E, rule_inclusion: RuleInclusion, pseudo: Option<&PseudoElement>, + mut undisplayed_style_cache: Option<&mut UndisplayedStyleCache>, ) -> ElementStyles where E: TElement, @@ -304,6 +312,11 @@ where element.borrow_data().map_or(true, |d| !d.has_styles()), "Why are we here?" ); + debug_assert!( + rule_inclusion == RuleInclusion::All || undisplayed_style_cache.is_none(), + "can't use the cache for default styles only" + ); + let mut ancestors_requiring_style_resolution = SmallVec::<[E; 16]>::new(); // Clear the bloom filter, just in case the caller is reusing TLS. @@ -320,6 +333,12 @@ where } } } + if let Some(ref mut cache) = undisplayed_style_cache { + if let Some(s) = cache.get(¤t.opaque()) { + style = Some(s.clone()); + break; + } + } ancestors_requiring_style_resolution.push(current); ancestor = current.traversal_parent(); } @@ -337,7 +356,9 @@ where } ancestor = ancestor.unwrap().traversal_parent(); - layout_parent_style = ancestor.map(|a| a.borrow_data().unwrap().styles.primary().clone()); + layout_parent_style = ancestor.and_then(|a| { + a.borrow_data().map(|data| data.styles.primary().clone()) + }); } for ancestor in ancestors_requiring_style_resolution.iter().rev() { @@ -360,18 +381,27 @@ where layout_parent_style = style.clone(); } + if let Some(ref mut cache) = undisplayed_style_cache { + cache.insert(ancestor.opaque(), style.clone().unwrap()); + } context.thread_local.bloom_filter.push(*ancestor); } context.thread_local.bloom_filter.assert_complete(element); - StyleResolverForElement::new( + let styles: ElementStyles = StyleResolverForElement::new( element, context, rule_inclusion, PseudoElementResolution::Force, ) .resolve_style(style.as_deref(), layout_parent_style.as_deref()) - .into() + .into(); + + if let Some(ref mut cache) = undisplayed_style_cache { + cache.insert(element.opaque(), styles.primary().clone()); + } + + styles } /// Calculates the style for a single node. |