aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/data.rs11
-rw-r--r--components/style/matching.rs4
-rw-r--r--components/style/sharing/mod.rs71
-rw-r--r--components/style/style_resolver.rs138
-rw-r--r--components/style/traversal.rs8
-rw-r--r--ports/geckolib/glue.rs6
6 files changed, 121 insertions, 117 deletions
diff --git a/components/style/data.rs b/components/style/data.rs
index 575d18e55b0..8d9a982b897 100644
--- a/components/style/data.rs
+++ b/components/style/data.rs
@@ -284,13 +284,18 @@ impl ElementData {
/// Returns this element's primary style as a resolved style to use for sharing.
pub fn share_primary_style(&self) -> PrimaryStyle {
- let primary_is_reused = self.flags.contains(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
- PrimaryStyle(ResolvedStyle::new(self.styles.primary().clone(), primary_is_reused))
+ let reused_via_rule_node =
+ self.flags.contains(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
+
+ PrimaryStyle {
+ style: ResolvedStyle(self.styles.primary().clone()),
+ reused_via_rule_node,
+ }
}
/// Sets a new set of styles, returning the old ones.
pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
- if new_styles.primary.0.reused_via_rule_node {
+ if new_styles.primary.reused_via_rule_node {
self.flags.insert(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
} else {
self.flags.remove(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 62777e70d96..826b5d3bfce 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -158,7 +158,7 @@ trait PrivateMatchMethods: TElement {
StyleResolverForElement::new(*self, context, RuleInclusion::All, PseudoElementResolution::IfApplicable)
.cascade_style_and_visited_with_default_parents(inputs);
- Some(style.into())
+ Some(style.0)
}
#[cfg(feature = "gecko")]
@@ -542,7 +542,7 @@ pub trait MatchMethods : TElement {
self.process_animations(
context,
&mut data.styles.primary,
- &mut new_styles.primary.0.style,
+ &mut new_styles.primary.style.0,
data.hint,
important_rules_changed,
);
diff --git a/components/style/sharing/mod.rs b/components/style/sharing/mod.rs
index a9c6a06181d..83ad650c5e2 100644
--- a/components/style/sharing/mod.rs
+++ b/components/style/sharing/mod.rs
@@ -82,7 +82,7 @@ use smallvec::SmallVec;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
-use style_resolver::PrimaryStyle;
+use style_resolver::{PrimaryStyle, ResolvedElementStyles};
use stylist::Stylist;
mod checks;
@@ -380,7 +380,7 @@ impl<E: TElement> StyleSharingTarget<E> {
pub fn share_style_if_possible(
&mut self,
context: &mut StyleContext<E>,
- ) -> Option<E> {
+ ) -> Option<ResolvedElementStyles> {
let cache = &mut context.thread_local.sharing_cache;
let shared_context = &context.shared;
let selector_flags_map = &mut context.thread_local.selector_flags;
@@ -443,25 +443,25 @@ impl<E: TElement> SharingCache<E> {
self.entries.insert(StyleSharingCandidate { element, validation_data });
}
- fn lookup<F>(&mut self, mut is_match: F) -> Option<E>
+ fn lookup<F, R>(&mut self, mut test_one: F) -> Option<R>
where
- F: FnMut(&mut StyleSharingCandidate<E>) -> bool
+ F: FnMut(&mut StyleSharingCandidate<E>) -> Option<R>
{
- let mut index = None;
+ let mut result = None;
for (i, candidate) in self.entries.iter_mut() {
- if is_match(candidate) {
- index = Some(i);
+ if let Some(r) = test_one(candidate) {
+ result = Some((i, r));
break;
}
};
- match index {
+ match result {
None => None,
- Some(i) => {
+ Some((i, r)) => {
self.entries.touch(i);
let front = self.entries.front_mut().unwrap();
- debug_assert!(is_match(front));
- Some(front.element)
+ debug_assert!(test_one(front).is_some());
+ Some(r)
}
}
}
@@ -620,7 +620,7 @@ impl<E: TElement> StyleSharingCache<E> {
selector_flags_map: &mut SelectorFlagsMap<E>,
bloom_filter: &StyleBloom<E>,
target: &mut StyleSharingTarget<E>,
- ) -> Option<E> {
+ ) -> Option<ResolvedElementStyles> {
if shared_context.options.disable_style_sharing_cache {
debug!("{:?} Cannot share style: style sharing cache disabled",
target.element);
@@ -655,42 +655,42 @@ impl<E: TElement> StyleSharingCache<E> {
shared: &SharedStyleContext,
bloom: &StyleBloom<E>,
selector_flags_map: &mut SelectorFlagsMap<E>
- ) -> bool {
+ ) -> Option<ResolvedElementStyles> {
// Check that we have the same parent, or at least that the parents
// share styles and permit sharing across their children. The latter
// check allows us to share style between cousins if the parents
// shared style.
if !checks::parents_allow_sharing(target, candidate) {
trace!("Miss: Parent");
- return false;
+ return None;
}
if target.is_native_anonymous() {
debug_assert!(!candidate.element.is_native_anonymous(),
"Why inserting NAC into the cache?");
trace!("Miss: Native Anonymous Content");
- return false;
+ return None;
}
if *target.get_local_name() != *candidate.element.get_local_name() {
trace!("Miss: Local Name");
- return false;
+ return None;
}
if *target.get_namespace() != *candidate.element.get_namespace() {
trace!("Miss: Namespace");
- return false;
+ return None;
}
if target.is_link() != candidate.element.is_link() {
trace!("Miss: Link");
- return false;
+ return None;
}
if target.matches_user_and_author_rules() !=
candidate.element.matches_user_and_author_rules() {
trace!("Miss: User and Author Rules");
- return false;
+ return None;
}
// We do not ignore visited state here, because Gecko
@@ -698,7 +698,7 @@ impl<E: TElement> StyleSharingCache<E> {
// so these contexts cannot be shared
if target.element.get_state() != candidate.get_state() {
trace!("Miss: User and Author State");
- return false;
+ return None;
}
let element_id = target.element.get_id();
@@ -708,38 +708,38 @@ impl<E: TElement> StyleSharingCache<E> {
if checks::may_have_rules_for_ids(shared, element_id.as_ref(),
candidate_id.as_ref()) {
trace!("Miss: ID Attr");
- return false;
+ return None;
}
}
if !checks::have_same_style_attribute(target, candidate) {
trace!("Miss: Style Attr");
- return false;
+ return None;
}
if !checks::have_same_class(target, candidate) {
trace!("Miss: Class");
- return false;
+ return None;
}
if !checks::have_same_presentational_hints(target, candidate) {
trace!("Miss: Pres Hints");
- return false;
+ return None;
}
if !checks::revalidate(target, candidate, shared, bloom,
selector_flags_map) {
trace!("Miss: Revalidation");
- return false;
+ return None;
}
debug_assert!(target.has_current_styles_for_traversal(
&candidate.element.borrow_data().unwrap(),
- shared.traversal_flags)
- );
- debug!("Sharing allowed between {:?} and {:?}", target.element, candidate.element);
+ shared.traversal_flags,
+ ));
- true
+ debug!("Sharing allowed between {:?} and {:?}", target.element, candidate.element);
+ Some(candidate.element.borrow_data().unwrap().share_styles())
}
/// Attempts to find an element in the cache with the given primary rule node and parent.
@@ -749,18 +749,19 @@ impl<E: TElement> StyleSharingCache<E> {
rules: &StrongRuleNode,
visited_rules: Option<&StrongRuleNode>,
target: E,
- ) -> Option<E> {
+ ) -> Option<PrimaryStyle> {
self.cache_mut().lookup(|candidate| {
+ debug_assert_ne!(candidate.element, target);
if !candidate.parent_style_identity().eq(inherited) {
- return false;
+ return None;
}
let data = candidate.element.borrow_data().unwrap();
let style = data.styles.primary();
if style.rules.as_ref() != Some(&rules) {
- return false;
+ return None;
}
if style.visited_rules() != visited_rules {
- return false;
+ return None;
}
// Rule nodes and styles are computed independent of the element's
@@ -775,10 +776,10 @@ impl<E: TElement> StyleSharingCache<E> {
// requirements of visited, assuming we get a cache hit on only one
// of unvisited vs. visited.
if target.is_visited_link() != candidate.element.is_visited_link() {
- return false;
+ return None;
}
- true
+ Some(data.share_primary_style())
})
}
}
diff --git a/components/style/style_resolver.rs b/components/style/style_resolver.rs
index 1a993e15662..41b7ed86237 100644
--- a/components/style/style_resolver.rs
+++ b/components/style/style_resolver.rs
@@ -50,16 +50,17 @@ struct MatchingResults {
}
/// A style returned from the resolver machinery.
-pub struct ResolvedStyle {
+pub struct ResolvedStyle(pub Arc<ComputedValues>);
+
+/// The primary style of an element or an element-backed pseudo-element.
+pub struct PrimaryStyle {
/// The style itself.
- pub style: Arc<ComputedValues>,
- /// Whether the style was reused from another element via the rule node.
+ pub style: ResolvedStyle,
+ /// Whether the style was reused from another element via the rule node (see
+ /// `StyleSharingCache::lookup_by_rules`).
pub reused_via_rule_node: bool,
}
-/// The primary style of an element or an element-backed pseudo-element.
-pub struct PrimaryStyle(pub ResolvedStyle);
-
/// A set of style returned from the resolver machinery.
pub struct ResolvedElementStyles {
/// Primary style.
@@ -68,30 +69,17 @@ pub struct ResolvedElementStyles {
pub pseudos: EagerPseudoStyles,
}
-impl ResolvedStyle {
- /// Creates a new ResolvedStyle.
- pub fn new(style: Arc<ComputedValues>, reused_via_rule_node: bool) -> Self {
- ResolvedStyle { style, reused_via_rule_node }
- }
-}
-
impl PrimaryStyle {
/// Convenience accessor for the style.
pub fn style(&self) -> &ComputedValues {
- &*self.0.style
- }
-}
-
-impl From<ResolvedStyle> for Arc<ComputedValues> {
- fn from(r: ResolvedStyle) -> Arc<ComputedValues> {
- r.style
+ &*self.style.0
}
}
impl From<ResolvedElementStyles> for ElementStyles {
fn from(r: ResolvedElementStyles) -> ElementStyles {
ElementStyles {
- primary: Some(r.primary.0.into()),
+ primary: Some(r.primary.style.0),
pseudos: r.pseudos,
}
}
@@ -182,17 +170,54 @@ where
None
};
- PrimaryStyle(
- self.cascade_style_and_visited(
- CascadeInputs {
- rules: Some(primary_results.rule_node),
- visited_rules,
- },
+ self.cascade_primary_style(
+ CascadeInputs {
+ rules: Some(primary_results.rule_node),
+ visited_rules,
+ },
+ parent_style,
+ layout_parent_style,
+ )
+ }
+
+ fn cascade_primary_style(
+ &mut self,
+ inputs: CascadeInputs,
+ parent_style: Option<&ComputedValues>,
+ layout_parent_style: Option<&ComputedValues>,
+ ) -> PrimaryStyle {
+ // Before doing the cascade, check the sharing cache and see if we can
+ // reuse the style via rule node identity.
+ let may_reuse =
+ !self.element.is_native_anonymous() &&
+ parent_style.is_some() &&
+ inputs.rules.is_some();
+
+ if may_reuse {
+ let cached = self.context.thread_local.sharing_cache.lookup_by_rules(
+ parent_style.unwrap(),
+ inputs.rules.as_ref().unwrap(),
+ inputs.visited_rules.as_ref(),
+ self.element,
+ );
+ if let Some(mut primary_style) = cached {
+ self.context.thread_local.statistics.styles_reused += 1;
+ primary_style.reused_via_rule_node |= true;
+ return primary_style;
+ }
+ }
+
+ // No style to reuse. Cascade the style, starting with visited style
+ // if necessary.
+ PrimaryStyle {
+ style: self.cascade_style_and_visited(
+ inputs,
parent_style,
layout_parent_style,
/* pseudo = */ None,
- )
- )
+ ),
+ reused_via_rule_node: false,
+ }
}
/// Resolve the style of a given element, and all its eager pseudo-elements.
@@ -222,10 +247,10 @@ where
if let Some(style) = pseudo_style {
if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &&
- eager_pseudo_is_definitely_not_generated(&pseudo, &style) {
+ eager_pseudo_is_definitely_not_generated(&pseudo, &style.0) {
return;
}
- pseudo_styles.set(&pseudo, style);
+ pseudo_styles.set(&pseudo, style.0);
}
})
}
@@ -266,27 +291,6 @@ where
layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>,
) -> ResolvedStyle {
- // Before doing the cascade, check the sharing cache and see if we can reuse
- // the style via rule node identity.
- let may_reuse = pseudo.is_none() && !self.element.is_native_anonymous() &&
- parent_style.is_some() && inputs.rules.is_some();
- if may_reuse {
- let cached = self.context.thread_local.sharing_cache.lookup_by_rules(
- parent_style.unwrap(),
- inputs.rules.as_ref().unwrap(),
- inputs.visited_rules.as_ref(),
- self.element,
- );
- if let Some(el) = cached {
- self.context.thread_local.statistics.styles_reused += 1;
- let mut style = el.borrow_data().unwrap().share_primary_style().0;
- style.reused_via_rule_node = true;
- return style;
- }
- }
-
- // No style to reuse. Cascade the style, starting with visited style
- // if necessary.
let mut style_if_visited = None;
if parent_style.map_or(false, |s| s.get_visited_style().is_some()) ||
inputs.visited_rules.is_some() {
@@ -300,17 +304,16 @@ where
));
}
- ResolvedStyle {
- style: self.cascade_style(
+ ResolvedStyle(
+ self.cascade_style(
inputs.rules.as_ref(),
style_if_visited,
parent_style,
layout_parent_style,
CascadeVisitedMode::Unvisited,
pseudo,
- ),
- reused_via_rule_node: false,
- }
+ )
+ )
}
/// Cascade the element and pseudo-element styles with the default parents.
@@ -319,13 +322,10 @@ where
inputs: ElementCascadeInputs,
) -> ResolvedElementStyles {
with_default_parent_styles(self.element, move |parent_style, layout_parent_style| {
- let primary_style = PrimaryStyle(
- self.cascade_style_and_visited(
- inputs.primary,
- parent_style,
- layout_parent_style,
- /* pseudo = */ None,
- )
+ let primary_style = self.cascade_primary_style(
+ inputs.primary,
+ parent_style,
+ layout_parent_style,
);
let mut pseudo_styles = EagerPseudoStyles::default();
@@ -344,17 +344,17 @@ where
let style =
self.cascade_style_and_visited(
inputs,
- Some(&*primary_style.style()),
+ Some(primary_style.style()),
layout_parent_style_for_pseudo,
Some(&pseudo),
);
if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &&
- eager_pseudo_is_definitely_not_generated(&pseudo, &style.style) {
+ eager_pseudo_is_definitely_not_generated(&pseudo, &style.0) {
continue;
}
- pseudo_styles.set(&pseudo, style.style);
+ pseudo_styles.set(&pseudo, style.0);
}
}
}
@@ -371,7 +371,7 @@ where
pseudo: &PseudoElement,
originating_element_style: &PrimaryStyle,
layout_parent_style: Option<&ComputedValues>,
- ) -> Option<Arc<ComputedValues>> {
+ ) -> Option<ResolvedStyle> {
let rules = self.match_pseudo(
originating_element_style.style(),
pseudo,
@@ -399,7 +399,7 @@ where
Some(originating_element_style.style()),
layout_parent_style,
Some(pseudo),
- ).style)
+ ))
}
fn match_primary(
diff --git a/components/style/traversal.rs b/components/style/traversal.rs
index 762e28644aa..1982589e985 100644
--- a/components/style/traversal.rs
+++ b/components/style/traversal.rs
@@ -421,7 +421,7 @@ where
let is_display_contents = primary_style.style().is_display_contents();
- style = Some(primary_style.0.into());
+ style = Some(primary_style.style.0);
if !is_display_contents {
layout_parent_style = style.clone();
}
@@ -659,9 +659,9 @@ where
// Now that our bloom filter is set up, try the style sharing
// cache.
match target.share_style_if_possible(context) {
- Some(shareable_element) => {
+ Some(shared_styles) => {
context.thread_local.statistics.styles_shared += 1;
- shareable_element.borrow_data().unwrap().share_styles()
+ shared_styles
}
None => {
context.thread_local.statistics.elements_matched += 1;
@@ -738,7 +738,7 @@ where
// number of eventual styles, but would potentially miss out on various
// opportunities for skipping selector matching, which could hurt
// performance.
- if !new_styles.primary.0.reused_via_rule_node {
+ if !new_styles.primary.reused_via_rule_node {
context.thread_local.sharing_cache.insert_if_possible(
&element,
&new_styles.primary,
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index 049f7496df6..514ea445ae9 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -731,11 +731,9 @@ pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawSe
};
// Actually `PseudoElementResolution` doesn't matter.
- let style: Arc<ComputedValues> =
- StyleResolverForElement::new(element, &mut context, RuleInclusion::All, PseudoElementResolution::IfApplicable)
+ StyleResolverForElement::new(element, &mut context, RuleInclusion::All, PseudoElementResolution::IfApplicable)
.cascade_style_and_visited_with_default_parents(inputs)
- .into();
- style.into()
+ .0.into()
}
#[no_mangle]