Move all *MatchMethods to TElement.

MozReview-Commit-ID: 3V6JIlOVVhw
This commit is contained in:
Bobby Holley 2016-10-26 16:54:36 -07:00
parent 1090abae87
commit 2fce2fbb0c
7 changed files with 98 additions and 163 deletions

View file

@ -631,14 +631,14 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
where N: LayoutNode, where N: LayoutNode,
C: StyleContext<'a> C: StyleContext<'a>
{ {
use style::traversal::ensure_node_styled; use style::traversal::ensure_element_styled;
// This node might have display: none, or it's style might be not up to // This node might have display: none, or it's style might be not up to
// date, so we might need to do style recalc. // date, so we might need to do style recalc.
// //
// FIXME(emilio): Is a bit shame we have to do this instead of in style. // FIXME(emilio): Is a bit shame we have to do this instead of in style.
ensure_node_data_initialized(&requested_node); ensure_node_data_initialized(&requested_node);
ensure_node_styled(requested_node, style_context); ensure_element_styled(requested_node.as_element().unwrap(), style_context);
let layout_node = requested_node.to_threadsafe(); let layout_node = requested_node.to_threadsafe();
let layout_node = match *pseudo { let layout_node = match *pseudo {

View file

@ -99,8 +99,7 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
// //
// The bloom filter stuff is all going to be rewritten, so we just hackily duplicate // The bloom filter stuff is all going to be rewritten, so we just hackily duplicate
// the bloom filter manipulation from recalc_style_at to maintain invariants. // the bloom filter manipulation from recalc_style_at to maintain invariants.
let parent = node.parent_node(); let parent = node.parent_node().unwrap().as_element();
debug_assert!(parent.unwrap().is_element());
let bf = take_thread_local_bloom_filter(parent, self.root, self.context.shared_context()); let bf = take_thread_local_bloom_filter(parent, self.root, self.context.shared_context());
put_thread_local_bloom_filter(bf, &node.to_unsafe(), self.context.shared_context()); put_thread_local_bloom_filter(bf, &node.to_unsafe(), self.context.shared_context());

View file

@ -133,7 +133,6 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
impl<'ln> TNode for ServoLayoutNode<'ln> { impl<'ln> TNode for ServoLayoutNode<'ln> {
type ConcreteElement = ServoLayoutElement<'ln>; type ConcreteElement = ServoLayoutElement<'ln>;
type ConcreteDocument = ServoLayoutDocument<'ln>; type ConcreteDocument = ServoLayoutDocument<'ln>;
type ConcreteRestyleDamage = RestyleDamage;
type ConcreteChildrenIterator = ServoChildrenIterator<'ln>; type ConcreteChildrenIterator = ServoChildrenIterator<'ln>;
fn to_unsafe(&self) -> UnsafeNode { fn to_unsafe(&self) -> UnsafeNode {
@ -470,6 +469,7 @@ impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> {
impl<'le> TElement for ServoLayoutElement<'le> { impl<'le> TElement for ServoLayoutElement<'le> {
type ConcreteNode = ServoLayoutNode<'le>; type ConcreteNode = ServoLayoutNode<'le>;
type ConcreteDocument = ServoLayoutDocument<'le>; type ConcreteDocument = ServoLayoutDocument<'le>;
type ConcreteRestyleDamage = RestyleDamage;
fn as_node(&self) -> ServoLayoutNode<'le> { fn as_node(&self) -> ServoLayoutNode<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast()) ServoLayoutNode::from_layout_js(self.element.upcast())

View file

@ -106,7 +106,6 @@ impl<T, I> Iterator for LayoutIterator<T> where T: Iterator<Item=I>, I: NodeInfo
pub trait TNode : Sized + Copy + Clone + NodeInfo { pub trait TNode : Sized + Copy + Clone + NodeInfo {
type ConcreteElement: TElement<ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>; type ConcreteElement: TElement<ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>; type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
type ConcreteRestyleDamage: TRestyleDamage;
type ConcreteChildrenIterator: Iterator<Item = Self>; type ConcreteChildrenIterator: Iterator<Item = Self>;
fn to_unsafe(&self) -> UnsafeNode; fn to_unsafe(&self) -> UnsafeNode;
@ -249,6 +248,7 @@ pub trait PresentationalHintsSynthetizer {
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>; type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>; type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
type ConcreteRestyleDamage: TRestyleDamage;
fn as_node(&self) -> Self::ConcreteNode; fn as_node(&self) -> Self::ConcreteNode;
@ -260,7 +260,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool; fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool;
/// Set the restyle damage field. /// Set the restyle damage field.
fn set_restyle_damage(self, damage: <Self::ConcreteNode as TNode>::ConcreteRestyleDamage); fn set_restyle_damage(self, damage: Self::ConcreteRestyleDamage);
/// XXX: It's a bit unfortunate we need to pass the current computed values /// XXX: It's a bit unfortunate we need to pass the current computed values
/// as an argument here, but otherwise Servo would crash due to double /// as an argument here, but otherwise Servo would crash due to double
@ -268,8 +268,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
fn existing_style_for_restyle_damage<'a>(&'a self, fn existing_style_for_restyle_damage<'a>(&'a self,
current_computed_values: Option<&'a Arc<ComputedValues>>, current_computed_values: Option<&'a Arc<ComputedValues>>,
pseudo: Option<&PseudoElement>) pseudo: Option<&PseudoElement>)
-> Option<&'a <<Self::ConcreteNode as TNode>::ConcreteRestyleDamage as TRestyleDamage> -> Option<&'a <Self::ConcreteRestyleDamage as TRestyleDamage> ::PreExistingComputedValues>;
::PreExistingComputedValues>;
/// Properly marks nodes as dirty in response to restyle hints. /// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint<C: DomTraversalContext<Self::ConcreteNode>>(&self, hint: RestyleHint) { fn note_restyle_hint<C: DomTraversalContext<Self::ConcreteNode>>(&self, hint: RestyleHint) {

View file

@ -160,7 +160,6 @@ impl<'ln> NodeInfo for GeckoNode<'ln> {
impl<'ln> TNode for GeckoNode<'ln> { impl<'ln> TNode for GeckoNode<'ln> {
type ConcreteDocument = GeckoDocument<'ln>; type ConcreteDocument = GeckoDocument<'ln>;
type ConcreteElement = GeckoElement<'ln>; type ConcreteElement = GeckoElement<'ln>;
type ConcreteRestyleDamage = GeckoRestyleDamage;
type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>; type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>;
fn to_unsafe(&self) -> UnsafeNode { fn to_unsafe(&self) -> UnsafeNode {
@ -399,6 +398,7 @@ lazy_static! {
impl<'le> TElement for GeckoElement<'le> { impl<'le> TElement for GeckoElement<'le> {
type ConcreteNode = GeckoNode<'le>; type ConcreteNode = GeckoNode<'le>;
type ConcreteDocument = GeckoDocument<'le>; type ConcreteDocument = GeckoDocument<'le>;
type ConcreteRestyleDamage = GeckoRestyleDamage;
fn as_node(&self) -> Self::ConcreteNode { fn as_node(&self) -> Self::ConcreteNode {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }

View file

@ -12,12 +12,12 @@ use cache::{LRUCache, SimpleHashCache};
use cascade_info::CascadeInfo; use cascade_info::CascadeInfo;
use context::{SharedStyleContext, StyleContext}; use context::{SharedStyleContext, StyleContext};
use data::{NodeStyles, PseudoStyles}; use data::{NodeStyles, PseudoStyles};
use dom::{NodeInfo, TElement, TNode, TRestyleDamage, UnsafeNode}; use dom::{TElement, TNode, TRestyleDamage, UnsafeNode};
use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade}; use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade};
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
use selector_impl::{PseudoElement, TheSelectorImpl}; use selector_impl::{PseudoElement, TheSelectorImpl};
use selector_matching::{ApplicableDeclarationBlock, Stylist}; use selector_matching::{ApplicableDeclarationBlock, Stylist};
use selectors::{Element, MatchAttr}; use selectors::MatchAttr;
use selectors::bloom::BloomFilter; use selectors::bloom::BloomFilter;
use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, MatchingReason, StyleRelations}; use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, MatchingReason, StyleRelations};
use sink::ForgetfulSink; use sink::ForgetfulSink;
@ -497,7 +497,7 @@ struct CascadeBooleans {
animate: bool, animate: bool,
} }
trait PrivateMatchMethods: TNode { trait PrivateMatchMethods: TElement {
/// Actually cascades style for a node or a pseudo-element of a node. /// Actually cascades style for a node or a pseudo-element of a node.
/// ///
/// Note that animations only apply to nodes or ::before or ::after /// Note that animations only apply to nodes or ::before or ::after
@ -521,7 +521,7 @@ trait PrivateMatchMethods: TNode {
// and the cache would not be effective anyway. // and the cache would not be effective anyway.
// This also works around the test failures at // This also works around the test failures at
// https://github.com/servo/servo/pull/13459#issuecomment-250717584 // https://github.com/servo/servo/pull/13459#issuecomment-250717584
let has_style_attribute = self.as_element().map_or(false, |e| e.style_attribute().is_some()); let has_style_attribute = self.style_attribute().is_some();
cacheable = cacheable && !has_style_attribute; cacheable = cacheable && !has_style_attribute;
let mut cascade_info = CascadeInfo::new(); let mut cascade_info = CascadeInfo::new();
@ -556,7 +556,7 @@ trait PrivateMatchMethods: TNode {
cascade_flags) cascade_flags)
} }
}; };
cascade_info.finish(self); cascade_info.finish(&self.as_node());
cacheable = cacheable && is_cacheable; cacheable = cacheable && is_cacheable;
@ -564,7 +564,7 @@ trait PrivateMatchMethods: TNode {
if booleans.animate { if booleans.animate {
let new_animations_sender = &context.local_context().new_animations_sender; let new_animations_sender = &context.local_context().new_animations_sender;
let this_opaque = self.opaque(); let this_opaque = self.as_node().opaque();
// Trigger any present animations if necessary. // Trigger any present animations if necessary.
let mut animations_started = animation::maybe_start_animations( let mut animations_started = animation::maybe_start_animations(
&shared_context, &shared_context,
@ -579,7 +579,7 @@ trait PrivateMatchMethods: TNode {
animation::start_transitions_if_applicable( animation::start_transitions_if_applicable(
new_animations_sender, new_animations_sender,
this_opaque, this_opaque,
self.to_unsafe(), self.as_node().to_unsafe(),
&**style, &**style,
&mut this_style, &mut this_style,
&shared_context.timer); &shared_context.timer);
@ -601,7 +601,7 @@ trait PrivateMatchMethods: TNode {
context: &SharedStyleContext, context: &SharedStyleContext,
style: &mut Arc<ComputedValues>) -> bool { style: &mut Arc<ComputedValues>) -> bool {
// Finish any expired transitions. // Finish any expired transitions.
let this_opaque = self.opaque(); let this_opaque = self.as_node().opaque();
let had_animations_to_expire = let had_animations_to_expire =
animation::complete_expired_transitions(this_opaque, style, context); animation::complete_expired_transitions(this_opaque, style, context);
@ -636,18 +636,11 @@ trait PrivateMatchMethods: TNode {
had_animations_to_expire || had_running_animations had_animations_to_expire || had_running_animations
} }
}
impl<N: TNode> PrivateMatchMethods for N {}
trait PrivateElementMatchMethods: TElement {
fn share_style_with_candidate_if_possible(&self, fn share_style_with_candidate_if_possible(&self,
parent_node: Self::ConcreteNode,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
candidate: &mut StyleSharingCandidate) candidate: &mut StyleSharingCandidate)
-> Result<Arc<ComputedValues>, CacheMiss> { -> Result<Arc<ComputedValues>, CacheMiss> {
debug_assert!(parent_node.is_element());
let candidate_element = unsafe { let candidate_element = unsafe {
Self::ConcreteNode::from_unsafe(&candidate.node).as_element().unwrap() Self::ConcreteNode::from_unsafe(&candidate.node).as_element().unwrap()
}; };
@ -657,9 +650,9 @@ trait PrivateElementMatchMethods: TElement {
} }
} }
impl<E: TElement> PrivateElementMatchMethods for E {} impl<E: TElement> PrivateMatchMethods for E {}
pub trait ElementMatchMethods : TElement { pub trait MatchMethods : TElement {
fn match_element(&self, fn match_element(&self,
stylist: &Stylist, stylist: &Stylist,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
@ -703,9 +696,8 @@ pub trait ElementMatchMethods : TElement {
unsafe fn share_style_if_possible(&self, unsafe fn share_style_if_possible(&self,
style_sharing_candidate_cache: style_sharing_candidate_cache:
&mut StyleSharingCandidateCache, &mut StyleSharingCandidateCache,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext)
parent: Option<Self::ConcreteNode>) -> StyleSharingResult<Self::ConcreteRestyleDamage> {
-> StyleSharingResult<<Self::ConcreteNode as TNode>::ConcreteRestyleDamage> {
if opts::get().disable_share_style_cache { if opts::get().disable_share_style_cache {
return StyleSharingResult::CannotShare return StyleSharingResult::CannotShare
} }
@ -718,16 +710,9 @@ pub trait ElementMatchMethods : TElement {
return StyleSharingResult::CannotShare return StyleSharingResult::CannotShare
} }
let parent = match parent {
Some(parent) if parent.is_element() => parent,
_ => return StyleSharingResult::CannotShare,
};
let mut should_clear_cache = false; let mut should_clear_cache = false;
for (i, &mut (ref mut candidate, ())) in style_sharing_candidate_cache.iter_mut().enumerate() { for (i, &mut (ref mut candidate, ())) in style_sharing_candidate_cache.iter_mut().enumerate() {
let sharing_result = self.share_style_with_candidate_if_possible(parent, let sharing_result = self.share_style_with_candidate_if_possible(shared_context, candidate);
shared_context,
candidate);
match sharing_result { match sharing_result {
Ok(shared_style) => { Ok(shared_style) => {
// Yay, cache hit. Share the style. // Yay, cache hit. Share the style.
@ -741,12 +726,10 @@ pub trait ElementMatchMethods : TElement {
let damage = let damage =
match self.existing_style_for_restyle_damage(data.previous_styles().map(|x| &x.primary), None) { match self.existing_style_for_restyle_damage(data.previous_styles().map(|x| &x.primary), None) {
Some(ref source) => { Some(ref source) => {
<<Self as TElement>::ConcreteNode as TNode> Self::ConcreteRestyleDamage::compute(source, &shared_style)
::ConcreteRestyleDamage::compute(source, &shared_style)
} }
None => { None => {
<<Self as TElement>::ConcreteNode as TNode> Self::ConcreteRestyleDamage::rebuild_and_reflow()
::ConcreteRestyleDamage::rebuild_and_reflow()
} }
}; };
@ -788,11 +771,7 @@ pub trait ElementMatchMethods : TElement {
StyleSharingResult::CannotShare StyleSharingResult::CannotShare
} }
}
impl<E: TElement> ElementMatchMethods for E {}
pub trait MatchMethods : TNode {
// The below two functions are copy+paste because I can't figure out how to // The below two functions are copy+paste because I can't figure out how to
// write a function which takes a generic function. I don't think it can // write a function which takes a generic function. I don't think it can
// be done. // be done.
@ -816,29 +795,23 @@ pub trait MatchMethods : TNode {
/// Therefore, each node must have its matching selectors inserted _after_ /// Therefore, each node must have its matching selectors inserted _after_
/// its own selector matching and _before_ its children start. /// its own selector matching and _before_ its children start.
fn insert_into_bloom_filter(&self, bf: &mut BloomFilter) { fn insert_into_bloom_filter(&self, bf: &mut BloomFilter) {
// Only elements are interesting. bf.insert(&*self.get_local_name());
if let Some(element) = self.as_element() { bf.insert(&*self.get_namespace());
bf.insert(&*element.get_local_name()); self.get_id().map(|id| bf.insert(&id));
bf.insert(&*element.get_namespace());
element.get_id().map(|id| bf.insert(&id));
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
element.each_class(|class| bf.insert(class)); self.each_class(|class| bf.insert(class));
}
} }
/// After all the children are done css selector matching, this must be /// After all the children are done css selector matching, this must be
/// called to reset the bloom filter after an `insert`. /// called to reset the bloom filter after an `insert`.
fn remove_from_bloom_filter(&self, bf: &mut BloomFilter) { fn remove_from_bloom_filter(&self, bf: &mut BloomFilter) {
// Only elements are interesting. bf.remove(&*self.get_local_name());
if let Some(element) = self.as_element() { bf.remove(&*self.get_namespace());
bf.remove(&*element.get_local_name()); self.get_id().map(|id| bf.remove(&id));
bf.remove(&*element.get_namespace());
element.get_id().map(|id| bf.remove(&id));
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
element.each_class(|class| bf.remove(class)); self.each_class(|class| bf.remove(class));
}
} }
fn compute_restyle_damage(&self, fn compute_restyle_damage(&self,
@ -847,7 +820,7 @@ pub trait MatchMethods : TNode {
pseudo: Option<&PseudoElement>) pseudo: Option<&PseudoElement>)
-> Self::ConcreteRestyleDamage -> Self::ConcreteRestyleDamage
{ {
match self.as_element().unwrap().existing_style_for_restyle_damage(old_style, pseudo) { match self.existing_style_for_restyle_damage(old_style, pseudo) {
Some(ref source) => { Some(ref source) => {
Self::ConcreteRestyleDamage::compute(source, Self::ConcreteRestyleDamage::compute(source,
new_style) new_style)
@ -890,23 +863,12 @@ pub trait MatchMethods : TNode {
where Ctx: StyleContext<'a> where Ctx: StyleContext<'a>
{ {
// Get our parent's style. // Get our parent's style.
let parent_data = parent.as_ref().map(|x| x.borrow_data().unwrap()); let parent_as_node = parent.map(|x| x.as_node());
let parent_data = parent_as_node.as_ref().map(|x| x.borrow_data().unwrap());
let parent_style = parent_data.as_ref().map(|x| &x.current_styles().primary); let parent_style = parent_data.as_ref().map(|x| &x.current_styles().primary);
// In the case we're styling a text node, we don't need to compute the let node = self.as_node();
// restyle damage, since it's a subset of the restyle damage of the let mut data = node.begin_styling();
// parent.
//
// In Gecko, we're done, we don't need anything else from text nodes.
//
// In Servo, this is also true, since text nodes generate UnscannedText
// fragments, which aren't repairable by incremental layout.
if self.is_text_node() {
self.style_text_node(ComputedValues::style_for_child_text_node(parent_style.clone().unwrap()));
return RestyleResult::Continue;
}
let mut data = self.begin_styling();
let mut new_styles; let mut new_styles;
let mut applicable_declarations_cache = let mut applicable_declarations_cache =
@ -944,8 +906,8 @@ pub trait MatchMethods : TNode {
context, applicable_declarations, context, applicable_declarations,
&mut applicable_declarations_cache); &mut applicable_declarations_cache);
self.set_can_be_fragmented(parent.map_or(false, |p| { self.as_node().set_can_be_fragmented(parent.map_or(false, |p| {
p.can_be_fragmented() || p.as_node().can_be_fragmented() ||
parent_style.unwrap().is_multicol() parent_style.unwrap().is_multicol()
})); }));
@ -955,7 +917,7 @@ pub trait MatchMethods : TNode {
data.finish_styling(new_styles); data.finish_styling(new_styles);
// Drop the mutable borrow early, since Servo's set_restyle_damage also borrows. // Drop the mutable borrow early, since Servo's set_restyle_damage also borrows.
mem::drop(data); mem::drop(data);
self.as_element().unwrap().set_restyle_damage(damage); self.set_restyle_damage(damage);
restyle_result restyle_result
} }
@ -1006,7 +968,7 @@ pub trait MatchMethods : TNode {
let no_damage = Self::ConcreteRestyleDamage::empty(); let no_damage = Self::ConcreteRestyleDamage::empty();
debug_assert!(new_pseudos.is_empty()); debug_assert!(new_pseudos.is_empty());
<Self::ConcreteElement as MatchAttr>::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { <Self as MatchAttr>::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
let applicable_declarations_for_this_pseudo = let applicable_declarations_for_this_pseudo =
applicable_declarations.per_pseudo.get(&pseudo).unwrap(); applicable_declarations.per_pseudo.get(&pseudo).unwrap();
@ -1018,8 +980,7 @@ pub trait MatchMethods : TNode {
if has_declarations { if has_declarations {
// We have declarations, so we need to cascade. Compute parameters. // We have declarations, so we need to cascade. Compute parameters.
let animate = <Self::ConcreteElement as MatchAttr>::Impl let animate = <Self as MatchAttr>::Impl::pseudo_is_before_or_after(&pseudo);
::pseudo_is_before_or_after(&pseudo);
let cacheable = if animate && old_pseudo_style.is_some() { let cacheable = if animate && old_pseudo_style.is_some() {
// Update animations before the cascade. This may modify // Update animations before the cascade. This may modify
// the value of old_pseudo_style. // the value of old_pseudo_style.
@ -1064,4 +1025,4 @@ pub trait MatchMethods : TNode {
} }
} }
impl<N: TNode> MatchMethods for N {} impl<E: TElement> MatchMethods for E {}

View file

@ -8,7 +8,7 @@ use atomic_refcell::AtomicRefCell;
use context::{LocalStyleContext, SharedStyleContext, StyleContext}; use context::{LocalStyleContext, SharedStyleContext, StyleContext};
use data::NodeData; use data::NodeData;
use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode, UnsafeNode}; use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult}; use matching::{ApplicableDeclarations, MatchMethods, StyleSharingResult};
use selectors::bloom::BloomFilter; use selectors::bloom::BloomFilter;
use selectors::matching::StyleRelations; use selectors::matching::StyleRelations;
use std::cell::RefCell; use std::cell::RefCell;
@ -62,13 +62,13 @@ thread_local!(
/// ///
/// If one does not exist, a new one will be made for you. If it is out of date, /// If one does not exist, a new one will be made for you. If it is out of date,
/// it will be cleared and reused. /// it will be cleared and reused.
pub fn take_thread_local_bloom_filter<N>(parent_node: Option<N>, pub fn take_thread_local_bloom_filter<E>(parent_element: Option<E>,
root: OpaqueNode, root: OpaqueNode,
context: &SharedStyleContext) context: &SharedStyleContext)
-> Box<BloomFilter> -> Box<BloomFilter>
where N: TNode { where E: TElement {
STYLE_BLOOM.with(|style_bloom| { STYLE_BLOOM.with(|style_bloom| {
match (parent_node, style_bloom.borrow_mut().take()) { match (parent_element, style_bloom.borrow_mut().take()) {
// Root node. Needs new bloom filter. // Root node. Needs new bloom filter.
(None, _ ) => { (None, _ ) => {
debug!("[{}] No parent, but new bloom filter!", tid()); debug!("[{}] No parent, but new bloom filter!", tid());
@ -82,7 +82,7 @@ pub fn take_thread_local_bloom_filter<N>(parent_node: Option<N>,
} }
// Found cached bloom filter. // Found cached bloom filter.
(Some(parent), Some((mut bloom_filter, old_node, old_generation))) => { (Some(parent), Some((mut bloom_filter, old_node, old_generation))) => {
if old_node == parent.to_unsafe() && if old_node == parent.as_node().to_unsafe() &&
old_generation == context.generation { old_generation == context.generation {
// Hey, the cached parent is our parent! We can reuse the bloom filter. // Hey, the cached parent is our parent! We can reuse the bloom filter.
debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0); debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0);
@ -108,17 +108,17 @@ pub fn put_thread_local_bloom_filter(bf: Box<BloomFilter>, unsafe_node: &UnsafeN
} }
/// "Ancestors" in this context is inclusive of ourselves. /// "Ancestors" in this context is inclusive of ourselves.
fn insert_ancestors_into_bloom_filter<N>(bf: &mut Box<BloomFilter>, fn insert_ancestors_into_bloom_filter<E>(bf: &mut Box<BloomFilter>,
mut n: N, mut el: E,
root: OpaqueNode) root: OpaqueNode)
where N: TNode { where E: TElement {
debug!("[{}] Inserting ancestors.", tid()); debug!("[{}] Inserting ancestors.", tid());
let mut ancestors = 0; let mut ancestors = 0;
loop { loop {
ancestors += 1; ancestors += 1;
n.insert_into_bloom_filter(&mut **bf); el.insert_into_bloom_filter(&mut **bf);
n = match n.layout_parent_node(root) { el = match el.as_node().layout_parent_node(root).and_then(|x| x.as_element()) {
None => break, None => break,
Some(p) => p, Some(p) => p,
}; };
@ -149,7 +149,7 @@ pub fn remove_from_bloom_filter<'a, N, C>(context: &C, root: OpaqueNode, node: N
} }
Some(parent) => { Some(parent) => {
// Otherwise, put it back, but remove this node. // Otherwise, put it back, but remove this node.
node.remove_from_bloom_filter(&mut *bf); node.as_element().map(|x| x.remove_from_bloom_filter(&mut *bf));
let unsafe_parent = parent.to_unsafe(); let unsafe_parent = parent.to_unsafe();
put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context()); put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context());
}, },
@ -213,20 +213,20 @@ pub fn relations_are_shareable(relations: &StyleRelations) -> bool {
AFFECTED_BY_PRESENTATIONAL_HINTS) AFFECTED_BY_PRESENTATIONAL_HINTS)
} }
pub fn ensure_node_styled<'a, N, C>(node: N, pub fn ensure_element_styled<'a, E, C>(element: E,
context: &'a C) context: &'a C)
where N: TNode, where E: TElement,
C: StyleContext<'a> C: StyleContext<'a>
{ {
let mut display_none = false; let mut display_none = false;
ensure_node_styled_internal(node, context, &mut display_none); ensure_element_styled_internal(element, context, &mut display_none);
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn ensure_node_styled_internal<'a, N, C>(node: N, fn ensure_element_styled_internal<'a, E, C>(element: E,
context: &'a C, context: &'a C,
parents_had_display_none: &mut bool) parents_had_display_none: &mut bool)
where N: TNode, where E: TElement,
C: StyleContext<'a> C: StyleContext<'a>
{ {
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
@ -238,13 +238,9 @@ fn ensure_node_styled_internal<'a, N, C>(node: N,
// This means potentially a bit of wasted work (usually not much). We could // This means potentially a bit of wasted work (usually not much). We could
// add a flag at the node at which point we stopped the traversal to know // add a flag at the node at which point we stopped the traversal to know
// where should we stop, but let's not add that complication unless needed. // where should we stop, but let's not add that complication unless needed.
let parent = match node.parent_node() { let parent = element.parent_element();
Some(parent) if parent.is_element() => Some(parent),
_ => None,
};
if let Some(parent) = parent { if let Some(parent) = parent {
ensure_node_styled_internal(parent, context, parents_had_display_none); ensure_element_styled_internal(parent, context, parents_had_display_none);
} }
// Common case: our style is already resolved and none of our ancestors had // Common case: our style is already resolved and none of our ancestors had
@ -252,6 +248,7 @@ fn ensure_node_styled_internal<'a, N, C>(node: N,
// //
// We only need to mark whether we have display none, and forget about it, // We only need to mark whether we have display none, and forget about it,
// our style is up to date. // our style is up to date.
let node = element.as_node();
if let Some(data) = node.borrow_data() { if let Some(data) = node.borrow_data() {
if let Some(style) = data.get_current_styles().map(|x| &x.primary) { if let Some(style) = data.get_current_styles().map(|x| &x.primary) {
if !*parents_had_display_none { if !*parents_had_display_none {
@ -268,16 +265,14 @@ fn ensure_node_styled_internal<'a, N, C>(node: N,
// probably not necessary since we're likely to be matching only a few // probably not necessary since we're likely to be matching only a few
// nodes, at best. // nodes, at best.
let mut applicable_declarations = ApplicableDeclarations::new(); let mut applicable_declarations = ApplicableDeclarations::new();
if let Some(element) = node.as_element() {
let stylist = &context.shared_context().stylist; let stylist = &context.shared_context().stylist;
element.match_element(&**stylist, element.match_element(&**stylist,
None, None,
&mut applicable_declarations); &mut applicable_declarations);
}
unsafe { unsafe {
node.cascade_node(context, parent, &applicable_declarations); element.cascade_node(context, parent, &applicable_declarations);
} }
} }
@ -291,34 +286,21 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
C: StyleContext<'a>, C: StyleContext<'a>,
D: DomTraversalContext<E::ConcreteNode> D: DomTraversalContext<E::ConcreteNode>
{ {
let node = element.as_node();
// Get the parent node.
let parent_opt = match node.parent_node() {
Some(parent) if parent.is_element() => Some(parent),
_ => None,
};
// Get the style bloom filter. // Get the style bloom filter.
let mut bf = take_thread_local_bloom_filter(parent_opt, root, context.shared_context()); let mut bf = take_thread_local_bloom_filter(element.parent_element(), root, context.shared_context());
let mut restyle_result = RestyleResult::Continue; let mut restyle_result = RestyleResult::Continue;
let mode = node.styling_mode(); let mode = element.as_node().styling_mode();
debug_assert!(mode != StylingMode::Stop, "Parent should not have enqueued us"); debug_assert!(mode != StylingMode::Stop, "Parent should not have enqueued us");
if mode != StylingMode::Traverse { if mode != StylingMode::Traverse {
// Check to see whether we can share a style with someone. // Check to see whether we can share a style with someone.
let style_sharing_candidate_cache = let style_sharing_candidate_cache =
&mut context.local_context().style_sharing_candidate_cache.borrow_mut(); &mut context.local_context().style_sharing_candidate_cache.borrow_mut();
let sharing_result = match node.as_element() { let sharing_result = if element.parent_element().is_none() {
Some(element) => { StyleSharingResult::CannotShare
unsafe { } else {
element.share_style_if_possible(style_sharing_candidate_cache, unsafe { element.share_style_if_possible(style_sharing_candidate_cache, context.shared_context()) }
context.shared_context(),
parent_opt.clone())
}
},
None => StyleSharingResult::CannotShare,
}; };
// Otherwise, match and cascade selectors. // Otherwise, match and cascade selectors.
@ -327,8 +309,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
let mut applicable_declarations = ApplicableDeclarations::new(); let mut applicable_declarations = ApplicableDeclarations::new();
let relations; let relations;
let shareable_element = match node.as_element() { let shareable_element = {
Some(element) => {
if opts::get().style_sharing_stats { if opts::get().style_sharing_stats {
STYLE_SHARING_CACHE_MISSES.fetch_add(1, Ordering::Relaxed); STYLE_SHARING_CACHE_MISSES.fetch_add(1, Ordering::Relaxed);
} }
@ -347,17 +328,12 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
} else { } else {
None None
} }
},
None => {
relations = StyleRelations::empty();
None
},
}; };
// Perform the CSS cascade. // Perform the CSS cascade.
unsafe { unsafe {
restyle_result = node.cascade_node(context, restyle_result = element.cascade_node(context,
parent_opt, element.parent_element(),
&applicable_declarations); &applicable_declarations);
} }
@ -372,7 +348,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
STYLE_SHARING_CACHE_HITS.fetch_add(1, Ordering::Relaxed); STYLE_SHARING_CACHE_HITS.fetch_add(1, Ordering::Relaxed);
} }
style_sharing_candidate_cache.touch(index); style_sharing_candidate_cache.touch(index);
node.as_element().unwrap().set_restyle_damage(damage); element.set_restyle_damage(damage);
} }
} }
} }
@ -381,7 +357,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
// processing. The eventual algorithm we're designing does this in a more granular // processing. The eventual algorithm we're designing does this in a more granular
// fashion. // fashion.
if mode == StylingMode::Restyle && restyle_result == RestyleResult::Continue { if mode == StylingMode::Restyle && restyle_result == RestyleResult::Continue {
for kid in node.children() { for kid in element.as_node().children() {
let mut data = D::ensure_node_data(&kid).borrow_mut(); let mut data = D::ensure_node_data(&kid).borrow_mut();
if kid.is_text_node() { if kid.is_text_node() {
data.ensure_restyle_data(); data.ensure_restyle_data();
@ -394,12 +370,12 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
} }
} }
let unsafe_layout_node = node.to_unsafe(); let unsafe_layout_node = element.as_node().to_unsafe();
// Before running the children, we need to insert our nodes into the bloom // Before running the children, we need to insert our nodes into the bloom
// filter. // filter.
debug!("[{}] + {:X}", tid(), unsafe_layout_node.0); debug!("[{}] + {:X}", tid(), unsafe_layout_node.0);
node.insert_into_bloom_filter(&mut *bf); element.insert_into_bloom_filter(&mut *bf);
// NB: flow construction updates the bloom filter on the way up. // NB: flow construction updates the bloom filter on the way up.
put_thread_local_bloom_filter(bf, &unsafe_layout_node, context.shared_context()); put_thread_local_bloom_filter(bf, &unsafe_layout_node, context.shared_context());