Add some wrapper types to propagate styles out of style resolver.

We'll use these next to propagate information about style reuse to the ElementDataFlags.

MozReview-Commit-ID: Dya6vgzydpL
This commit is contained in:
Bobby Holley 2017-09-13 12:22:18 -07:00
parent 9092e6b4c2
commit 7a7070e075
5 changed files with 118 additions and 57 deletions

View file

@ -17,7 +17,9 @@ use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use servo_arc::Arc; use servo_arc::Arc;
use shared_lock::StylesheetGuards; use shared_lock::StylesheetGuards;
use std::fmt; use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use style_resolver::{PrimaryStyle, ResolvedElementStyles, ResolvedStyle};
bitflags! { bitflags! {
#[derive(Default)] #[derive(Default)]
@ -264,6 +266,24 @@ impl ElementData {
self.styles.primary.is_some() self.styles.primary.is_some()
} }
/// Returns this element's styles as resolved styles to use for sharing.
pub fn share_styles(&self) -> ResolvedElementStyles {
ResolvedElementStyles {
primary: self.share_primary_style(),
pseudos: self.styles.pseudos.clone(),
}
}
/// Returns this element's primary style as a resolved style to use for sharing.
pub fn share_primary_style(&self) -> PrimaryStyle {
PrimaryStyle(ResolvedStyle::new(self.styles.primary().clone()))
}
/// Sets a new set of styles, returning the old ones.
pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
mem::replace(&mut self.styles, new_styles.into())
}
/// Returns the kind of restyling that we're going to need to do on this /// Returns the kind of restyling that we're going to need to do on this
/// element, based of the stored restyle hint. /// element, based of the stored restyle hint.
pub fn restyle_kind( pub fn restyle_kind(

View file

@ -8,7 +8,7 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use context::{ElementCascadeInputs, SelectorFlagsMap, SharedStyleContext, StyleContext}; use context::{ElementCascadeInputs, SelectorFlagsMap, SharedStyleContext, StyleContext};
use data::{ElementData, ElementStyles}; use data::ElementData;
use dom::TElement; use dom::TElement;
use invalidation::element::restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS}; use invalidation::element::restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS};
use invalidation::element::restyle_hints::{RESTYLE_SMIL, RESTYLE_STYLE_ATTRIBUTE}; use invalidation::element::restyle_hints::{RESTYLE_SMIL, RESTYLE_STYLE_ATTRIBUTE};
@ -18,6 +18,7 @@ use rule_tree::{CascadeLevel, StrongRuleNode};
use selector_parser::{PseudoElement, RestyleDamage}; use selector_parser::{PseudoElement, RestyleDamage};
use selectors::matching::ElementSelectorFlags; use selectors::matching::ElementSelectorFlags;
use servo_arc::{Arc, ArcBorrow}; use servo_arc::{Arc, ArcBorrow};
use style_resolver::ResolvedElementStyles;
use traversal_flags; use traversal_flags;
/// Represents the result of comparing an element's old and new style. /// Represents the result of comparing an element's old and new style.
@ -156,7 +157,7 @@ trait PrivateMatchMethods: TElement {
StyleResolverForElement::new(*self, context, RuleInclusion::All, PseudoElementResolution::IfApplicable) StyleResolverForElement::new(*self, context, RuleInclusion::All, PseudoElementResolution::IfApplicable)
.cascade_style_and_visited_with_default_parents(inputs); .cascade_style_and_visited_with_default_parents(inputs);
Some(style) Some(style.into())
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -530,26 +531,23 @@ pub trait MatchMethods : TElement {
&self, &self,
context: &mut StyleContext<Self>, context: &mut StyleContext<Self>,
data: &mut ElementData, data: &mut ElementData,
mut new_styles: ElementStyles, mut new_styles: ResolvedElementStyles,
important_rules_changed: bool, important_rules_changed: bool,
) -> ChildCascadeRequirement { ) -> ChildCascadeRequirement {
use app_units::Au; use app_units::Au;
use dom::TNode; use dom::TNode;
use std::cmp; use std::cmp;
use std::mem;
debug_assert!(new_styles.primary.is_some(), "How did that happen?");
self.process_animations( self.process_animations(
context, context,
&mut data.styles.primary, &mut data.styles.primary,
&mut new_styles.primary.as_mut().unwrap(), &mut new_styles.primary.0.style,
data.hint, data.hint,
important_rules_changed, important_rules_changed,
); );
// First of all, update the styles. // First of all, update the styles.
let old_styles = mem::replace(&mut data.styles, new_styles); let old_styles = data.set_styles(new_styles);
// Propagate the "can be fragmented" bit. It would be nice to // Propagate the "can be fragmented" bit. It would be nice to
// encapsulate this better. // encapsulate this better.

View file

@ -49,12 +49,52 @@ struct MatchingResults {
relevant_link_found: bool, relevant_link_found: bool,
} }
/// The primary style of an element or an element-backed pseudo-element. /// A style returned from the resolver machinery.
pub struct PrimaryStyle { pub struct ResolvedStyle {
/// The style per se. /// The style itself.
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
} }
/// 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.
pub primary: PrimaryStyle,
/// Pseudo styles.
pub pseudos: EagerPseudoStyles,
}
impl ResolvedStyle {
/// Creates a new ResolvedStyle.
pub fn new(style: Arc<ComputedValues>) -> Self {
ResolvedStyle { style }
}
}
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
}
}
impl From<ResolvedElementStyles> for ElementStyles {
fn from(r: ResolvedElementStyles) -> ElementStyles {
ElementStyles {
primary: Some(r.primary.0.into()),
pseudos: r.pseudos,
}
}
}
fn with_default_parent_styles<E, F, R>(element: E, f: F) -> R fn with_default_parent_styles<E, F, R>(element: E, f: F) -> R
where where
E: TElement, E: TElement,
@ -140,8 +180,8 @@ where
None None
}; };
PrimaryStyle { PrimaryStyle(
style: self.cascade_style_and_visited( self.cascade_style_and_visited(
CascadeInputs { CascadeInputs {
rules: Some(primary_results.rule_node), rules: Some(primary_results.rule_node),
visited_rules, visited_rules,
@ -149,8 +189,8 @@ where
parent_style, parent_style,
layout_parent_style, layout_parent_style,
/* pseudo = */ None, /* pseudo = */ None,
), )
} )
} }
/// Resolve the style of a given element, and all its eager pseudo-elements. /// Resolve the style of a given element, and all its eager pseudo-elements.
@ -158,7 +198,7 @@ where
&mut self, &mut self,
parent_style: Option<&ComputedValues>, parent_style: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>,
) -> ElementStyles { ) -> ResolvedElementStyles {
let primary_style = let primary_style =
self.resolve_primary_style(parent_style, layout_parent_style); self.resolve_primary_style(parent_style, layout_parent_style);
@ -166,10 +206,10 @@ where
if self.element.implemented_pseudo_element().is_none() { if self.element.implemented_pseudo_element().is_none() {
let layout_parent_style_for_pseudo = let layout_parent_style_for_pseudo =
if primary_style.style.is_display_contents() { if primary_style.style().is_display_contents() {
layout_parent_style layout_parent_style
} else { } else {
Some(&*primary_style.style) Some(primary_style.style())
}; };
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| { SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
let pseudo_style = self.resolve_pseudo_style( let pseudo_style = self.resolve_pseudo_style(
@ -188,16 +228,15 @@ where
}) })
} }
ElementStyles { ResolvedElementStyles {
// FIXME(emilio): Remove the Option<>. primary: primary_style,
primary: Some(primary_style.style),
pseudos: pseudo_styles, pseudos: pseudo_styles,
} }
} }
/// Resolve an element's styles with the default inheritance parent/layout /// Resolve an element's styles with the default inheritance parent/layout
/// parents. /// parents.
pub fn resolve_style_with_default_parents(&mut self) -> ElementStyles { pub fn resolve_style_with_default_parents(&mut self) -> ResolvedElementStyles {
with_default_parent_styles(self.element, |parent_style, layout_parent_style| { with_default_parent_styles(self.element, |parent_style, layout_parent_style| {
self.resolve_style(parent_style, layout_parent_style) self.resolve_style(parent_style, layout_parent_style)
}) })
@ -207,7 +246,7 @@ where
pub fn cascade_style_and_visited_with_default_parents( pub fn cascade_style_and_visited_with_default_parents(
&mut self, &mut self,
inputs: CascadeInputs, inputs: CascadeInputs,
) -> Arc<ComputedValues> { ) -> ResolvedStyle {
with_default_parent_styles(self.element, |parent_style, layout_parent_style| { with_default_parent_styles(self.element, |parent_style, layout_parent_style| {
self.cascade_style_and_visited( self.cascade_style_and_visited(
inputs, inputs,
@ -224,7 +263,7 @@ where
parent_style: Option<&ComputedValues>, parent_style: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>, pseudo: Option<&PseudoElement>,
) -> Arc<ComputedValues> { ) -> ResolvedStyle {
let mut style_if_visited = None; let mut style_if_visited = None;
if parent_style.map_or(false, |s| s.get_visited_style().is_some()) || if parent_style.map_or(false, |s| s.get_visited_style().is_some()) ||
inputs.visited_rules.is_some() { inputs.visited_rules.is_some() {
@ -237,7 +276,9 @@ where
pseudo, pseudo,
)); ));
} }
self.cascade_style(
ResolvedStyle {
style: self.cascade_style(
inputs.rules.as_ref(), inputs.rules.as_ref(),
style_if_visited, style_if_visited,
parent_style, parent_style,
@ -246,29 +287,30 @@ where
pseudo, pseudo,
) )
} }
}
/// Cascade the element and pseudo-element styles with the default parents. /// Cascade the element and pseudo-element styles with the default parents.
pub fn cascade_styles_with_default_parents( pub fn cascade_styles_with_default_parents(
&mut self, &mut self,
inputs: ElementCascadeInputs, inputs: ElementCascadeInputs,
) -> ElementStyles { ) -> ResolvedElementStyles {
with_default_parent_styles(self.element, move |parent_style, layout_parent_style| { with_default_parent_styles(self.element, move |parent_style, layout_parent_style| {
let primary_style = PrimaryStyle { let primary_style = PrimaryStyle(
style: self.cascade_style_and_visited( self.cascade_style_and_visited(
inputs.primary, inputs.primary,
parent_style, parent_style,
layout_parent_style, layout_parent_style,
/* pseudo = */ None, /* pseudo = */ None,
), )
}; );
let mut pseudo_styles = EagerPseudoStyles::default(); let mut pseudo_styles = EagerPseudoStyles::default();
if let Some(mut pseudo_array) = inputs.pseudos.into_array() { if let Some(mut pseudo_array) = inputs.pseudos.into_array() {
let layout_parent_style_for_pseudo = let layout_parent_style_for_pseudo =
if primary_style.style.is_display_contents() { if primary_style.style().is_display_contents() {
layout_parent_style layout_parent_style
} else { } else {
Some(&*primary_style.style) Some(primary_style.style())
}; };
for (i, inputs) in pseudo_array.iter_mut().enumerate() { for (i, inputs) in pseudo_array.iter_mut().enumerate() {
@ -278,23 +320,23 @@ where
let style = let style =
self.cascade_style_and_visited( self.cascade_style_and_visited(
inputs, inputs,
Some(&*primary_style.style), Some(&*primary_style.style()),
layout_parent_style_for_pseudo, layout_parent_style_for_pseudo,
Some(&pseudo), Some(&pseudo),
); );
if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) && if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &&
eager_pseudo_is_definitely_not_generated(&pseudo, &style) { eager_pseudo_is_definitely_not_generated(&pseudo, &style.style) {
continue; continue;
} }
pseudo_styles.set(&pseudo, style); pseudo_styles.set(&pseudo, style.style);
} }
} }
} }
ElementStyles { ResolvedElementStyles {
primary: Some(primary_style.style), primary: primary_style,
pseudos: pseudo_styles, pseudos: pseudo_styles,
} }
}) })
@ -307,7 +349,7 @@ where
layout_parent_style: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>,
) -> Option<Arc<ComputedValues>> { ) -> Option<Arc<ComputedValues>> {
let rules = self.match_pseudo( let rules = self.match_pseudo(
&originating_element_style.style, originating_element_style.style(),
pseudo, pseudo,
VisitedHandlingMode::AllLinksUnvisited VisitedHandlingMode::AllLinksUnvisited
); );
@ -317,9 +359,9 @@ where
}; };
let mut visited_rules = None; let mut visited_rules = None;
if originating_element_style.style.get_visited_style().is_some() { if originating_element_style.style().get_visited_style().is_some() {
visited_rules = self.match_pseudo( visited_rules = self.match_pseudo(
&originating_element_style.style, originating_element_style.style(),
pseudo, pseudo,
VisitedHandlingMode::RelevantLinkVisited, VisitedHandlingMode::RelevantLinkVisited,
); );
@ -330,10 +372,10 @@ where
rules: Some(rules), rules: Some(rules),
visited_rules visited_rules
}, },
Some(&originating_element_style.style), Some(originating_element_style.style()),
layout_parent_style, layout_parent_style,
Some(pseudo), Some(pseudo),
)) ).style)
} }
fn match_primary( fn match_primary(

View file

@ -419,9 +419,9 @@ where
layout_parent_style.as_ref().map(|s| &**s) layout_parent_style.as_ref().map(|s| &**s)
); );
let is_display_contents = primary_style.style.is_display_contents(); let is_display_contents = primary_style.style().is_display_contents();
style = Some(primary_style.style); style = Some(primary_style.0.into());
if !is_display_contents { if !is_display_contents {
layout_parent_style = style.clone(); layout_parent_style = style.clone();
} }
@ -434,7 +434,7 @@ where
.resolve_style( .resolve_style(
style.as_ref().map(|s| &**s), style.as_ref().map(|s| &**s),
layout_parent_style.as_ref().map(|s| &**s) layout_parent_style.as_ref().map(|s| &**s)
) ).into()
} }
/// Calculates the style for a single node. /// Calculates the style for a single node.
@ -657,8 +657,7 @@ where
match target.share_style_if_possible(context) { match target.share_style_if_possible(context) {
Some(shareable_element) => { Some(shareable_element) => {
context.thread_local.statistics.styles_shared += 1; context.thread_local.statistics.styles_shared += 1;
let shareable_data = shareable_element.borrow_data().unwrap(); shareable_element.borrow_data().unwrap().share_styles()
shareable_data.styles.clone()
} }
None => { None => {
context.thread_local.statistics.elements_matched += 1; context.thread_local.statistics.elements_matched += 1;
@ -679,7 +678,7 @@ where
.sharing_cache .sharing_cache
.insert_if_possible( .insert_if_possible(
&element, &element,
new_styles.primary(), new_styles.primary.style(),
&mut target, &mut target,
context.thread_local.bloom_filter.matching_depth(), context.thread_local.bloom_filter.matching_depth(),
); );

View file

@ -727,9 +727,11 @@ pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawSe
}; };
// Actually `PseudoElementResolution` doesn't matter. // 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) .cascade_style_and_visited_with_default_parents(inputs)
.into() .into();
style.into()
} }
#[no_mangle] #[no_mangle]