aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/gecko/data.rs14
-rw-r--r--components/style/gecko/media_queries.rs5
-rw-r--r--components/style/traversal.rs36
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(&current.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.