style: Add infrastructure for non-eagerly-cascaded pseudo-elements

This commit also removes StylistWrapper and uses Arc::get_mut instead.
This commit is contained in:
Emilio Cobos Álvarez 2016-04-22 16:05:41 +02:00
parent 2dacbc6fb3
commit b6402a81d0
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
11 changed files with 188 additions and 78 deletions

View file

@ -108,7 +108,7 @@ pub struct LayoutContext<'a> {
cached_local_layout_context: Rc<LocalLayoutContext>,
}
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
}

View file

@ -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<PrecomputedStyleData>) -> 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,

View file

@ -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<Arc<DisplayList>>,
/// Performs CSS selector matching and style resolution.
pub stylist: Box<Stylist>,
pub stylist: Arc<Stylist>,
/// A queued response for the union of the content boxes of a node.
pub content_box_response: Rect<Au>,
@ -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::<ServoSelectorImpl>(&*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 {

View file

@ -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<PrecomputedStyleData>) {
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<Self> {
if self.is_element() &&

View file

@ -16,12 +16,6 @@ use std::collections::HashMap;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex, RwLock};
pub struct StylistWrapper<Impl: SelectorImplExt>(pub *const Stylist<Impl>);
// FIXME(#6569) This implementation is unsound.
#[allow(unsafe_code)]
unsafe impl<Impl: SelectorImplExt> Sync for StylistWrapper<Impl> {}
pub struct SharedStyleContext<Impl: SelectorImplExt> {
/// The current viewport size.
pub viewport_size: Size2D<Au>,
@ -30,9 +24,7 @@ pub struct SharedStyleContext<Impl: SelectorImplExt> {
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<Impl>,
pub stylist: Arc<Stylist<Impl>>,
/// 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<C: ComputedValues> {
pub style_sharing_candidate_cache: RefCell<StyleSharingCandidateCache<C>>,
}
pub trait StyleContext<'a, Impl: SelectorImplExt, C: ComputedValues> {
pub trait StyleContext<'a, Impl: SelectorImplExt> {
fn shared_context(&self) -> &'a SharedStyleContext<Impl>;
fn local_context(&self) -> &LocalStyleContext<C>;
fn local_context(&self) -> &LocalStyleContext<Impl::ComputedValues>;
}
/// Why we're doing reflow.

View file

@ -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<Impl: SelectorImpl, ConcreteComputedValues: Computed
/// The results of CSS styling for this node.
pub style: Option<Arc<ConcreteComputedValues>>,
/// Precomputed data needed to avoid doing the cascade for some
/// pseudo-elements like "-servo-details-content"
pub precomputed: Arc<PrecomputedStyleData<Impl, ConcreteComputedValues>>,
/// The results of CSS styling for each pseudo-element (if any).
pub per_pseudo: HashMap<Impl::PseudoElement, Arc<ConcreteComputedValues>,
BuildHasherDefault<::fnv::FnvHasher>>,
@ -23,9 +28,11 @@ pub struct PrivateStyleData<Impl: SelectorImpl, ConcreteComputedValues: Computed
impl<Impl, ConcreteComputedValues> PrivateStyleData<Impl, ConcreteComputedValues>
where Impl: SelectorImpl, ConcreteComputedValues: ComputedValues {
pub fn new() -> PrivateStyleData<Impl, ConcreteComputedValues> {
pub fn new(precomputed: Arc<PrecomputedStyleData<Impl, ConcreteComputedValues>>)
-> PrivateStyleData<Impl, ConcreteComputedValues> {
PrivateStyleData {
style: None,
precomputed: precomputed,
per_pseudo: HashMap::with_hasher(Default::default()),
parallel: DomParallelInfo::new(),
}

View file

@ -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<PrecomputedStyleData<<Self::ConcreteElement as Element>::Impl,
Self::ConcreteComputedValues>>)
where <Self::ConcreteElement as Element>::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<<Self::ConcreteElement as Element>::Impl,
Self::ConcreteComputedValues>>;
Self::ConcreteComputedValues>>;
/// Borrows the PrivateStyleData immutably. Fails on a conflicting borrow.
#[inline(always)]
fn borrow_data(&self)
-> Option<Ref<PrivateStyleData<<Self::ConcreteElement as Element>::Impl,
Self::ConcreteComputedValues>>>;
Self::ConcreteComputedValues>>>;
/// Borrows the PrivateStyleData mutably. Fails on a conflicting borrow.
#[inline(always)]
fn mutate_data(&self)
-> Option<RefMut<PrivateStyleData<<Self::ConcreteElement as Element>::Impl,
Self::ConcreteComputedValues>>>;
Self::ConcreteComputedValues>>>;
/// Get the description of how to account for recent style changes.
fn restyle_damage(self) -> Self::ConcreteRestyleDamage;

View file

@ -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<F>(mut fun: F)
type ComputedValues: properties::ComputedValues;
fn each_pseudo_element<F>(mut fun: F)
where F: FnMut(<Self as SelectorImpl>::PseudoElement);
fn is_eagerly_cascaded_pseudo_element(pseudo: &<Self as SelectorImpl>::PseudoElement) -> bool;
#[inline]
fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
Self::each_pseudo_element(|pseudo| {
if Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
fun(pseudo)
}
})
}
#[inline]
fn each_non_eagerly_cascaded_pseudo_element<F>(mut fun: F)
where F: FnMut(<Self as SelectorImpl>::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<Self>];
@ -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<E: Element<Impl=ServoSelectorImpl>> 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<F>(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<F>(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<E: Element<Impl=ServoSelectorImpl>> ElementExt for E {
fn is_link(&self) -> bool {
self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
}
}

View file

@ -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<Impl: SelectorImpl, Computed: ComputedValues> {
/// 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::PseudoElement,
Computed,
BuildHasherDefault<::fnv::FnvHasher>>,
}
impl<Impl, Computed> PrecomputedStyleData<Impl, Computed>
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<Impl: SelectorImplExt> {
/// The current selector maps, after evaluating media
/// rules against the current device.
element_map: PerPseudoElementSelectorMap<Impl>,
/// The selector maps corresponding to a given pseudo-element
/// (depending on the implementation)
pseudos_map: HashMap<Impl::PseudoElement,
PerPseudoElementSelectorMap<Impl>,
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<PrecomputedStyleData<Impl, Impl::ComputedValues>>,
rules_source_order: usize,
/// Selector dependencies used to compute restyle hints.
@ -138,6 +165,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
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<Impl: SelectorImplExt> Stylist<Impl> {
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<Impl: SelectorImplExt> Stylist<Impl> {
}
fn add_stylesheet(&mut self, stylesheet: &Stylesheet<Impl>) {
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<Impl: SelectorImplExt> Stylist<Impl> {
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<Impl: SelectorImplExt> Stylist<Impl> {
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::<Impl::ComputedValues>(Size2D::zero(),
&declarations, false,
None, None,
box StdoutErrorReporter);
precomputed.non_eagerly_cascaded_pseudo_elements.insert(pseudo, computed);
}
})
}
pub fn get_precomputed_data(&self) -> &Arc<PrecomputedStyleData<Impl, Impl::ComputedValues>> {
&self.precomputed
}
pub fn get_non_eagerly_cascaded_pseudo_element_style(&self,
pseudo: &Impl::PseudoElement) -> Option<Impl::ComputedValues> {
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<E>(&self, element: &E,
@ -284,20 +352,16 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
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,

View file

@ -11,6 +11,6 @@ use stylesheets;
/// Concrete types for servo Style implementation
pub type Stylesheet = stylesheets::Stylesheet<ServoSelectorImpl>;
pub type PrivateStyleData = data::PrivateStyleData<ServoSelectorImpl, ServoComputedValues>;
pub type PrecomputedStyleData = selector_matching::PrecomputedStyleData<ServoSelectorImpl, ServoComputedValues>;
pub type Stylist = selector_matching::Stylist<ServoSelectorImpl>;
pub type StylistWrapper = context::StylistWrapper<ServoSelectorImpl>;
pub type SharedStyleContext = context::SharedStyleContext<ServoSelectorImpl>;

View file

@ -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, <N::ConcreteElement as Element>::Impl, N::ConcreteComputedValues>,
<N::ConcreteElement as Element>::Impl: SelectorImplExt + 'a {
C: StyleContext<'a, <N::ConcreteElement as Element>::Impl>,
<N::ConcreteElement as Element>::Impl: SelectorImplExt<ComputedValues=N::ConcreteComputedValues> + '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)