From 5a43c7e3cd7997ad09a5abc7d162237a737f331e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 23 Apr 2016 14:08:49 +0200 Subject: [PATCH] style: Allow inheritance when computing anonymous box styles This is used a lot by Gecko, not still for servo though. --- components/layout/wrapper.rs | 30 +++++++++++----- components/style/context.rs | 1 - components/style/data.rs | 4 ++- components/style/selector_matching.rs | 52 ++++++++++++++++----------- 4 files changed, 56 insertions(+), 31 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 1ba991a5d5e..9a92e8b9816 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -738,8 +738,8 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { self.borrow_layout_data().unwrap() .style_data .precomputed - .non_eagerly_cascaded_pseudo_elements - .get(&PseudoElement::DetailsContent) + .computed_values_for(&PseudoElement::DetailsContent, + Some(&*self.style())) .map(|style| { let display = if element.get_attr(&ns!(), &atom!("open")).is_some() { style.get_box().display @@ -768,6 +768,22 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { /// Unlike the version on TNode, this handles pseudo-elements. #[inline] fn style(&self) -> Ref> { + // Precompute anonymous-box pseudo-element style if not cached. + match self.get_pseudo_element_type() { + PseudoElementType::DetailsContent(_) => { + if self.borrow_layout_data().unwrap() + .style_data.per_pseudo.get(&PseudoElement::DetailsContent).is_none() { + let mut data = self.mutate_layout_data().unwrap(); + let new_style = data.style_data + .precomputed + .computed_values_for(&PseudoElement::DetailsContent, + data.style_data.style.as_ref()); + data.style_data.per_pseudo.insert(PseudoElement::DetailsContent, new_style.unwrap()); + } + } + _ => {}, + }; + Ref::map(self.borrow_layout_data().unwrap(), |data| { let style = match self.get_pseudo_element_type() { PseudoElementType::Before(_) @@ -777,10 +793,7 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { PseudoElementType::DetailsSummary(_) => data.style_data.per_pseudo.get(&PseudoElement::DetailsSummary), PseudoElementType::DetailsContent(_) - => data.style_data - .precomputed - .non_eagerly_cascaded_pseudo_elements - .get(&PseudoElement::DetailsContent), + => data.style_data.per_pseudo.get(&PseudoElement::DetailsContent), PseudoElementType::Normal => data.style_data.style.as_ref(), }; @@ -791,7 +804,9 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { #[inline] fn selected_style(&self) -> Ref> { Ref::map(self.borrow_layout_data().unwrap(), |data| { - data.style_data.per_pseudo.get(&PseudoElement::Selection).unwrap_or(data.style_data.style.as_ref().unwrap()) + data.style_data.per_pseudo + .get(&PseudoElement::Selection) + .unwrap_or(data.style_data.style.as_ref().unwrap()) }) } @@ -814,7 +829,6 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { PseudoElementType::DetailsContent(_) => { data.style_data.per_pseudo.remove(&PseudoElement::DetailsContent); } - PseudoElementType::Normal => { data.style_data.style = None; } diff --git a/components/style/context.rs b/components/style/context.rs index 6c8aa4bff19..76c2f1ece0c 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -65,4 +65,3 @@ pub enum ReflowGoal { /// We're reflowing in order to satisfy a script query. No display list will be created. ForScriptQuery, } - diff --git a/components/style/data.rs b/components/style/data.rs index 55e38b99ded..843d6b2448d 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -14,8 +14,10 @@ pub struct PrivateStyleData>, - /// Precomputed data needed to avoid doing the cascade for some + /// Shared rules data needed to avoid doing the cascade for some /// pseudo-elements like "-servo-details-content" + /// + /// TODO: Move to TLS to avoid this extra pointer? pub precomputed: Arc>, /// The results of CSS styling for each pseudo-element (if any). diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 052400333c5..844a060daac 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -86,12 +86,13 @@ lazy_static! { #[derive(HeapSizeOf)] pub struct PrecomputedStyleData { - /// Computed values for a given non-eagerly cascaded pseudo-element. These - /// are eagerly computed once, and then just looked up in the table, - /// since they only appear in rules of the form *|*::pseudo-element - pub non_eagerly_cascaded_pseudo_elements: HashMap, - BuildHasherDefault<::fnv::FnvHasher>>, + /// Applicable declarations for a given non-eagerly cascaded pseudo-element. + /// These are eagerly computed once, and then used to resolve the new + /// computed values on the fly on layout. + non_eagerly_cascaded_pseudo_elements: HashMap, + BuildHasherDefault<::fnv::FnvHasher>>, + _phantom: ::std::marker::PhantomData, } impl PrecomputedStyleData @@ -99,6 +100,22 @@ impl PrecomputedStyleData fn new() -> Self { PrecomputedStyleData { non_eagerly_cascaded_pseudo_elements: HashMap::with_hasher(Default::default()), + _phantom: ::std::marker::PhantomData, + } + } + + pub fn computed_values_for(&self, + pseudo: &Impl::PseudoElement, + parent: Option<&Arc>) -> Option> { + if let Some(declarations) = self.non_eagerly_cascaded_pseudo_elements.get(pseudo) { + let (computed, _) = + properties::cascade::(Size2D::zero(), + &declarations, false, + parent.map(|p| &**p), None, + box StdoutErrorReporter); + Some(Arc::new(computed)) + } else { + parent.map(|p| p.clone()) } } } @@ -256,28 +273,21 @@ impl Stylist { self.rules_source_order = rules_source_order; Impl::each_non_eagerly_cascaded_pseudo_element(|pseudo| { - // TODO: Don't precompute this, and compute it on demand instead + // TODO: Don't precompute this, compute it on demand instead and + // cache it. + // // This is actually kind of hard, because the stylist is shared // between threads. - // - if let Some(map) = self.pseudos_map.get(&pseudo) { + if let Some(map) = self.pseudos_map.remove(&pseudo) { let mut precomputed = Arc::get_mut(&mut self.precomputed) .expect("Stylist was not the single owner of PrecomputedStyleData"); let mut declarations = vec![]; map.user_agent.normal.get_universal_rules(&mut declarations); - map.user_agent.important.get_universal_rules(&mut declarations); - // NB: Viewport size shouldn't matter since these rules should - // be absolute. - let (computed, _) = - properties::cascade::(Size2D::zero(), - &declarations, false, - None, None, - box StdoutErrorReporter); - precomputed.non_eagerly_cascaded_pseudo_elements.insert(pseudo, Arc::new(computed)); + precomputed.non_eagerly_cascaded_pseudo_elements.insert(pseudo, declarations); } }) } @@ -287,11 +297,11 @@ impl Stylist { } pub fn get_non_eagerly_cascaded_pseudo_element_style(&self, - pseudo: &Impl::PseudoElement) -> Option> { + pseudo: &Impl::PseudoElement, + parent: Option<&Arc>) -> Option> { debug_assert!(!Impl::is_eagerly_cascaded_pseudo_element(pseudo)); self.precomputed - .non_eagerly_cascaded_pseudo_elements - .get(pseudo).map(|computed| computed.clone()) + .computed_values_for(pseudo, parent) } pub fn compute_restyle_hint(&self, element: &E,