From b6402a81d0c076b859526d64f191270000addf58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 22 Apr 2016 16:05:41 +0200 Subject: [PATCH] style: Add infrastructure for non-eagerly-cascaded pseudo-elements This commit also removes StylistWrapper and uses Arc::get_mut instead. --- components/layout/context.rs | 2 +- components/layout/data.rs | 12 +-- components/layout/layout_thread.rs | 17 ++--- components/layout/wrapper.rs | 13 ++-- components/style/context.rs | 15 +--- components/style/data.rs | 9 ++- components/style/dom.rs | 14 ++-- components/style/selector_impl.rs | 69 +++++++++++++---- components/style/selector_matching.rs | 102 +++++++++++++++++++++----- components/style/servo.rs | 2 +- components/style/traversal.rs | 11 +-- 11 files changed, 188 insertions(+), 78 deletions(-) diff --git a/components/layout/context.rs b/components/layout/context.rs index 169c2f38082..0a9933d4abd 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -108,7 +108,7 @@ pub struct LayoutContext<'a> { cached_local_layout_context: Rc, } -impl<'a> StyleContext<'a, ServoSelectorImpl, ServoComputedValues> for LayoutContext<'a> { +impl<'a> StyleContext<'a, ServoSelectorImpl> for LayoutContext<'a> { fn shared_context(&self) -> &'a SharedStyleContext { &self.shared.style_context } diff --git a/components/layout/data.rs b/components/layout/data.rs index f582ec71ffb..b7d80d8a0ea 100644 --- a/components/layout/data.rs +++ b/components/layout/data.rs @@ -4,7 +4,8 @@ use construct::ConstructionResult; use incremental::RestyleDamage; -use style::servo::PrivateStyleData; +use std::sync::Arc; +use style::servo::{PrecomputedStyleData, PrivateStyleData}; /// Data that layout associates with a node. pub struct PrivateLayoutData { @@ -17,8 +18,9 @@ pub struct PrivateLayoutData { /// Description of how to account for recent style changes. pub restyle_damage: RestyleDamage, - /// The current results of flow construction for this node. This is either a flow or a - /// `ConstructionItem`. See comments in `construct.rs` for more details. + /// The current results of flow construction for this node. This is either a + /// flow or a `ConstructionItem`. See comments in `construct.rs` for more + /// details. pub flow_construction_result: ConstructionResult, pub before_flow_construction_result: ConstructionResult, @@ -35,9 +37,9 @@ pub struct PrivateLayoutData { impl PrivateLayoutData { /// Creates new layout data. - pub fn new() -> PrivateLayoutData { + pub fn new(precomputed_style_data: Arc) -> PrivateLayoutData { PrivateLayoutData { - style_data: PrivateStyleData::new(), + style_data: PrivateStyleData::new(precomputed_style_data), restyle_damage: RestyleDamage::empty(), flow_construction_result: ConstructionResult::None, before_flow_construction_result: ConstructionResult::None, diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 64779f8e031..bf325b8dbdd 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -67,14 +67,13 @@ use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::{Arc, Mutex, MutexGuard, RwLock}; use style::animation::Animation; use style::computed_values::{filter, mix_blend_mode}; -use style::context::{ReflowGoal, StylistWrapper}; +use style::context::{ReflowGoal}; use style::dom::{TDocument, TElement, TNode}; use style::error_reporting::ParseErrorReporter; use style::logical_geometry::LogicalPoint; use style::media_queries::{Device, MediaType}; use style::parallel::WorkQueueData; use style::properties::ComputedValues; -use style::selector_impl::ServoSelectorImpl; use style::selector_matching::USER_OR_USER_AGENT_STYLESHEETS; use style::servo::{SharedStyleContext, Stylesheet, Stylist}; use style::stylesheets::CSSRuleIteratorExt; @@ -107,7 +106,7 @@ pub struct LayoutThreadData { pub display_list: Option>, /// Performs CSS selector matching and style resolution. - pub stylist: Box, + pub stylist: Arc, /// A queued response for the union of the content boxes of a node. pub content_box_response: Rect, @@ -421,7 +420,7 @@ impl LayoutThread { let font_cache_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_font_cache_receiver); - let stylist = box Stylist::new(device); + let stylist = Arc::new(Stylist::new(device)); let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0)); for stylesheet in &*USER_OR_USER_AGENT_STYLESHEETS { add_font_face_rules(stylesheet, @@ -510,7 +509,7 @@ impl LayoutThread { style_context: SharedStyleContext { viewport_size: self.viewport_size.clone(), screen_size_changed: screen_size_changed, - stylist: StylistWrapper::(&*rw_data.stylist), + stylist: rw_data.stylist.clone(), generation: self.generation, goal: goal, new_animations_sender: Mutex::new(self.new_animations_sender.clone()), @@ -809,7 +808,7 @@ impl LayoutThread { /// Sets quirks mode for the document, causing the quirks mode stylesheet to be used. fn handle_set_quirks_mode<'a, 'b>(&self, possibly_locked_rw_data: &mut RwData<'a, 'b>) { let mut rw_data = possibly_locked_rw_data.lock(); - rw_data.stylist.set_quirks_mode(true); + Arc::get_mut(&mut rw_data.stylist).unwrap().set_quirks_mode(true); possibly_locked_rw_data.block(rw_data); } @@ -1060,7 +1059,7 @@ impl LayoutThread { // Calculate the actual viewport as per DEVICE-ADAPT ยง 6 let device = Device::new(MediaType::Screen, initial_viewport); - rw_data.stylist.set_device(device, &data.document_stylesheets); + Arc::get_mut(&mut rw_data.stylist).unwrap().set_device(device, &data.document_stylesheets); let constraints = rw_data.stylist.viewport_constraints().clone(); self.viewport_size = match constraints { @@ -1092,8 +1091,8 @@ impl LayoutThread { } // If the entire flow tree is invalid, then it will be reflowed anyhow. - needs_dirtying |= rw_data.stylist.update(&data.document_stylesheets, - data.stylesheets_changed); + needs_dirtying |= Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets, + data.stylesheets_changed); let needs_reflow = viewport_size_changed && !needs_dirtying; unsafe { if needs_dirtying { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index a94203cbf21..bbeff75d99d 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -72,7 +72,7 @@ use style::properties::{ComputedValues, ServoComputedValues}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use style::restyle_hints::ElementSnapshot; use style::selector_impl::{NonTSPseudoClass, PseudoElement, ServoSelectorImpl}; -use style::servo::PrivateStyleData; +use style::servo::{PrecomputedStyleData, PrivateStyleData}; use url::Url; use util::str::is_whitespace; @@ -168,11 +168,11 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() }) } - fn initialize_data(self) { + fn initialize_data(self, precomputed: &Arc) { let has_data = unsafe { self.borrow_data_unchecked().is_some() }; if !has_data { let ptr: NonOpaqueStyleAndLayoutData = - Box::into_raw(box RefCell::new(PrivateLayoutData::new())); + Box::into_raw(box RefCell::new(PrivateLayoutData::new(precomputed.clone()))); let opaque = OpaqueStyleAndLayoutData { ptr: unsafe { NonZero::new(ptr as *mut ()) } }; @@ -707,9 +707,10 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { }) } - // TODO(emilio): Since the ::-details-* pseudos are internal, just affecting one element, and - // only changing `display` property when the element `open` attribute changes, this should be - // eligible for not being cascaded eagerly, reading the display property from layout instead. + // TODO(emilio): Since the ::-details-* pseudos are internal, just affecting + // one element, and only changing `display` property when the element `open` + // attribute changes, this should be eligible for not being cascaded + // eagerly, reading the display property from layout instead. #[inline] fn get_details_summary_pseudo(&self) -> Option { if self.is_element() && diff --git a/components/style/context.rs b/components/style/context.rs index f5bf81274ee..6c8aa4bff19 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -16,12 +16,6 @@ use std::collections::HashMap; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex, RwLock}; -pub struct StylistWrapper(pub *const Stylist); - -// FIXME(#6569) This implementation is unsound. -#[allow(unsafe_code)] -unsafe impl Sync for StylistWrapper {} - pub struct SharedStyleContext { /// The current viewport size. pub viewport_size: Size2D, @@ -30,9 +24,7 @@ pub struct SharedStyleContext { pub screen_size_changed: bool, /// The CSS selector stylist. - /// - /// FIXME(#2604): Make this no longer an unsafe pointer once we have fast `RWArc`s. - pub stylist: StylistWrapper, + pub stylist: Arc>, /// Starts at zero, and increased by one every time a layout completes. /// This can be used to easily check for invalid stale data. @@ -60,10 +52,9 @@ pub struct LocalStyleContext { pub style_sharing_candidate_cache: RefCell>, } -pub trait StyleContext<'a, Impl: SelectorImplExt, C: ComputedValues> { - +pub trait StyleContext<'a, Impl: SelectorImplExt> { fn shared_context(&self) -> &'a SharedStyleContext; - fn local_context(&self) -> &LocalStyleContext; + fn local_context(&self) -> &LocalStyleContext; } /// Why we're doing reflow. diff --git a/components/style/data.rs b/components/style/data.rs index 3698eeddf5b..55e38b99ded 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use properties::ComputedValues; +use selector_matching::PrecomputedStyleData; use selectors::parser::SelectorImpl; use std::collections::HashMap; use std::hash::BuildHasherDefault; @@ -13,6 +14,10 @@ pub struct PrivateStyleData>, + /// Precomputed data needed to avoid doing the cascade for some + /// pseudo-elements like "-servo-details-content" + pub precomputed: Arc>, + /// The results of CSS styling for each pseudo-element (if any). pub per_pseudo: HashMap, BuildHasherDefault<::fnv::FnvHasher>>, @@ -23,9 +28,11 @@ pub struct PrivateStyleData PrivateStyleData where Impl: SelectorImpl, ConcreteComputedValues: ComputedValues { - pub fn new() -> PrivateStyleData { + pub fn new(precomputed: Arc>) + -> PrivateStyleData { PrivateStyleData { style: None, + precomputed: precomputed, per_pseudo: HashMap::with_hasher(Default::default()), parallel: DomParallelInfo::new(), } diff --git a/components/style/dom.rs b/components/style/dom.rs index d0ba545798c..a10cc22e30d 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -8,7 +8,8 @@ use data::PrivateStyleData; use element_state::ElementState; use properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock}; use restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; -use selector_impl::ElementExt; +use selector_impl::{ElementExt, SelectorImplExt}; +use selector_matching::PrecomputedStyleData; use selectors::Element; use selectors::matching::DeclarationBlock; use smallvec::VecLike; @@ -89,7 +90,10 @@ pub trait TNode : Sized + Copy + Clone { /// initialized. /// /// FIXME(pcwalton): Do this as part of fragment building instead of in a traversal. - fn initialize_data(self); + fn initialize_data(self, + precomputed: &Arc::Impl, + Self::ConcreteComputedValues>>) + where ::Impl: SelectorImplExt; /// While doing a reflow, the node at the root has no parent, as far as we're /// concerned. This method returns `None` at the reflow root. @@ -137,19 +141,19 @@ pub trait TNode : Sized + Copy + Clone { #[inline(always)] unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData<::Impl, - Self::ConcreteComputedValues>>; + Self::ConcreteComputedValues>>; /// Borrows the PrivateStyleData immutably. Fails on a conflicting borrow. #[inline(always)] fn borrow_data(&self) -> Option::Impl, - Self::ConcreteComputedValues>>>; + Self::ConcreteComputedValues>>>; /// Borrows the PrivateStyleData mutably. Fails on a conflicting borrow. #[inline(always)] fn mutate_data(&self) -> Option::Impl, - Self::ConcreteComputedValues>>>; + Self::ConcreteComputedValues>>>; /// Get the description of how to account for recent style changes. fn restyle_damage(self) -> Self::ConcreteRestyleDamage; diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index d70287f9ddf..34295e63f0e 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -6,15 +6,40 @@ use selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET}; use selectors::Element; use selectors::parser::{ParserContext, SelectorImpl}; use stylesheets::Stylesheet; +use properties::{self, ServoComputedValues}; pub trait ElementExt: Element { fn is_link(&self) -> bool; } pub trait SelectorImplExt : SelectorImpl + Sized { - fn each_eagerly_cascaded_pseudo_element(mut fun: F) + type ComputedValues: properties::ComputedValues; + + fn each_pseudo_element(mut fun: F) where F: FnMut(::PseudoElement); + fn is_eagerly_cascaded_pseudo_element(pseudo: &::PseudoElement) -> bool; + + #[inline] + fn each_eagerly_cascaded_pseudo_element(mut fun: F) + where F: FnMut(::PseudoElement) { + Self::each_pseudo_element(|pseudo| { + if Self::is_eagerly_cascaded_pseudo_element(&pseudo) { + fun(pseudo) + } + }) + } + + #[inline] + fn each_non_eagerly_cascaded_pseudo_element(mut fun: F) + where F: FnMut(::PseudoElement) { + Self::each_pseudo_element(|pseudo| { + if !Self::is_eagerly_cascaded_pseudo_element(&pseudo) { + fun(pseudo) + } + }) + } + fn pseudo_class_state_flag(pc: &Self::NonTSPseudoClass) -> ElementState; fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet]; @@ -112,15 +137,17 @@ impl SelectorImpl for ServoSelectorImpl { "before" => Before, "after" => After, "selection" => Selection, - "-servo-details-summary" => if context.in_user_agent_stylesheet { + "-servo-details-summary" => { + if !context.in_user_agent_stylesheet { + return Err(()) + } DetailsSummary - } else { - return Err(()) }, - "-servo-details-content" => if context.in_user_agent_stylesheet { + "-servo-details-content" => { + if !context.in_user_agent_stylesheet { + return Err(()) + } DetailsContent - } else { - return Err(()) }, _ => return Err(()) }; @@ -129,15 +156,23 @@ impl SelectorImpl for ServoSelectorImpl { } } -impl> ElementExt for E { - fn is_link(&self) -> bool { - self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) - } -} - impl SelectorImplExt for ServoSelectorImpl { + type ComputedValues = ServoComputedValues; + + // TODO: Making details-summary not eagerly cascaded shouldn't be difficult #[inline] - fn each_eagerly_cascaded_pseudo_element(mut fun: F) + fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool { + match *pseudo { + PseudoElement::Before | + PseudoElement::After | + PseudoElement::Selection | + PseudoElement::DetailsContent | + PseudoElement::DetailsSummary => true, + } + } + + #[inline] + fn each_pseudo_element(mut fun: F) where F: FnMut(PseudoElement) { fun(PseudoElement::Before); fun(PseudoElement::After); @@ -161,3 +196,9 @@ impl SelectorImplExt for ServoSelectorImpl { Some(&*QUIRKS_MODE_STYLESHEET) } } + +impl> ElementExt for E { + fn is_link(&self) -> bool { + self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) + } +} diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 167d3277c42..7e4c97b04f5 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -8,8 +8,9 @@ use dom::TElement; use element_state::*; use error_reporting::{ParseErrorReporter, StdoutErrorReporter}; +use euclid::Size2D; use media_queries::{Device, MediaType}; -use properties::{PropertyDeclaration, PropertyDeclarationBlock}; +use properties::{self, ComputedValues, PropertyDeclaration, PropertyDeclarationBlock}; use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet}; use selector_impl::{SelectorImplExt, ServoSelectorImpl}; use selectors::Element; @@ -83,6 +84,25 @@ 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>, +} + +impl PrecomputedStyleData + where Impl: SelectorImpl, Computed: ComputedValues { + fn new() -> Self { + PrecomputedStyleData { + non_eagerly_cascaded_pseudo_elements: HashMap::with_hasher(Default::default()), + } + } +} + /// This structure holds all the selectors and device characteristics /// for a given document. The selectors are converted into `Rule`s /// (defined in rust-selectors), and introduced in a `SelectorMap` @@ -116,11 +136,18 @@ pub struct Stylist { /// The current selector maps, after evaluating media /// rules against the current device. element_map: PerPseudoElementSelectorMap, + /// The selector maps corresponding to a given pseudo-element /// (depending on the implementation) pseudos_map: HashMap, BuildHasherDefault<::fnv::FnvHasher>>, + + /// Precomputed data to be shared to the nodes. + /// Note that this has to be an Arc, since the layout thread needs the + /// stylist mutable. + precomputed: Arc>, + rules_source_order: usize, /// Selector dependencies used to compute restyle hints. @@ -138,6 +165,7 @@ impl Stylist { element_map: PerPseudoElementSelectorMap::new(), pseudos_map: HashMap::with_hasher(Default::default()), + precomputed: Arc::new(PrecomputedStyleData::new()), rules_source_order: 0, state_deps: DependencySet::new(), }; @@ -160,6 +188,7 @@ impl Stylist { self.element_map = PerPseudoElementSelectorMap::new(); self.pseudos_map = HashMap::with_hasher(Default::default()); + self.precomputed = Arc::new(PrecomputedStyleData::new()); self.rules_source_order = 0; self.state_deps.clear(); @@ -182,8 +211,7 @@ impl Stylist { } fn add_stylesheet(&mut self, stylesheet: &Stylesheet) { - let device = &self.device; - if !stylesheet.is_effective_for_device(device) { + if !stylesheet.is_effective_for_device(&self.device) { return; } let mut rules_source_order = self.rules_source_order; @@ -195,20 +223,21 @@ impl Stylist { if !$style_rule.declarations.$priority.is_empty() { for selector in &$style_rule.selectors { let map = if let Some(ref pseudo) = selector.pseudo_element { - self.pseudos_map.entry(pseudo.clone()) - .or_insert_with(PerPseudoElementSelectorMap::new) - .borrow_for_origin(&stylesheet.origin) + self.pseudos_map + .entry(pseudo.clone()) + .or_insert_with(PerPseudoElementSelectorMap::new) + .borrow_for_origin(&stylesheet.origin) } else { self.element_map.borrow_for_origin(&stylesheet.origin) }; map.$priority.insert(Rule { - selector: selector.compound_selectors.clone(), - declarations: DeclarationBlock { - specificity: selector.specificity, - declarations: $style_rule.declarations.$priority.clone(), - source_order: rules_source_order, - }, + selector: selector.compound_selectors.clone(), + declarations: DeclarationBlock { + specificity: selector.specificity, + declarations: $style_rule.declarations.$priority.clone(), + source_order: rules_source_order, + }, }); } } @@ -223,7 +252,46 @@ impl Stylist { self.state_deps.note_selector(selector.compound_selectors.clone()); } } + 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 + // This is actually kind of hard, because the stylist is shared + // between threads. + // + if let Some(map) = self.pseudos_map.get(&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, computed); + } + }) + } + + pub fn get_precomputed_data(&self) -> &Arc> { + &self.precomputed + } + + pub fn get_non_eagerly_cascaded_pseudo_element_style(&self, + pseudo: &Impl::PseudoElement) -> Option { + debug_assert!(!Impl::is_eagerly_cascaded_pseudo_element(pseudo)); + self.precomputed + .non_eagerly_cascaded_pseudo_elements + .get(pseudo).map(|computed| computed.clone()) } pub fn compute_restyle_hint(&self, element: &E, @@ -284,20 +352,16 @@ impl Stylist { assert!(!self.is_device_dirty); assert!(style_attribute.is_none() || pseudo_element.is_none(), "Style attributes do not apply to pseudo-elements"); + debug_assert!(pseudo_element.is_none() || + Impl::is_eagerly_cascaded_pseudo_element(pseudo_element.as_ref().unwrap())); let map = match pseudo_element { - Some(ref pseudo) => match self.pseudos_map.get(pseudo) { - Some(map) => map, - // TODO(emilio): get non eagerly-cascaded pseudo-element rules here. - // Actually assume there are no rules applicable. - None => return true, - }, + Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(), None => &self.element_map, }; let mut shareable = true; - // Step 1: Normal user-agent rules. map.user_agent.normal.get_all_matching_rules(element, parent_bf, diff --git a/components/style/servo.rs b/components/style/servo.rs index ec7044ad4a5..4dbde75ac57 100644 --- a/components/style/servo.rs +++ b/components/style/servo.rs @@ -11,6 +11,6 @@ use stylesheets; /// Concrete types for servo Style implementation pub type Stylesheet = stylesheets::Stylesheet; pub type PrivateStyleData = data::PrivateStyleData; +pub type PrecomputedStyleData = selector_matching::PrecomputedStyleData; pub type Stylist = selector_matching::Stylist; -pub type StylistWrapper = context::StylistWrapper; pub type SharedStyleContext = context::SharedStyleContext; diff --git a/components/style/traversal.rs b/components/style/traversal.rs index f39347e83ab..2cf5220d78f 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -123,13 +123,13 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C, root: OpaqueNode, node: N) where N: TNode, - C: StyleContext<'a, ::Impl, N::ConcreteComputedValues>, - ::Impl: SelectorImplExt + 'a { + C: StyleContext<'a, ::Impl>, + ::Impl: SelectorImplExt + 'a { // Initialize layout data. // // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML // parser. - node.initialize_data(); + node.initialize_data(context.shared_context().stylist.get_precomputed_data()); // Get the parent node. let parent_opt = node.layout_parent_node(root); @@ -167,8 +167,9 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C, let shareable_element = match node.as_element() { Some(element) => { // Perform the CSS selector matching. - let stylist = unsafe { &*context.shared_context().stylist.0 }; - if element.match_element(stylist, + let stylist = &context.shared_context().stylist; + + if element.match_element(&**stylist, Some(&*bf), &mut applicable_declarations) { Some(element)