diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2023-08-15 00:02:36 +0200 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2023-08-16 17:46:41 +0200 |
commit | d1aeb3921b46a06ba570f8bcb48a5cb6918748ac (patch) | |
tree | bd4073b45785daf6ed74460455b4f136fb3c927c /components/style/traversal.rs | |
parent | 39ac4840ee7c032239ddcbfa5218e3002b251112 (diff) | |
download | servo-d1aeb3921b46a06ba570f8bcb48a5cb6918748ac.tar.gz servo-d1aeb3921b46a06ba570f8bcb48a5cb6918748ac.zip |
style: Cache computed styles objects display: none subtrees
This reuses our existing undisplayed style generation, but in a
per-document rather than per-nsComputedDOMStyle object, which means that
we can avoid re-resolving styles of elements in display: none subtrees
much more often.
This brings the test-case in the bug to par with other browsers or
better, and is much simpler than the initial approach I tried back in
the day.
Differential Revision: https://phabricator.services.mozilla.com/D147547
Diffstat (limited to 'components/style/traversal.rs')
-rw-r--r-- | components/style/traversal.rs | 36 |
1 files changed, 33 insertions, 3 deletions
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. |