Refactor style to be completely backend-independent

This commit refactors the style crate to be completely independent of
the actual implementation and pseudo-elements supported.

This also adds a gecko backend which introduces parsing for the
anonymous box pseudo-elements[1], although there's still no way of
querying them.

https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
This commit is contained in:
Emilio Cobos Álvarez 2016-02-08 02:53:22 +01:00
parent a164176876
commit dd503dfacb
41 changed files with 767 additions and 310 deletions

View file

@ -9,13 +9,14 @@ use context::SharedStyleContext;
use data::PrivateStyleData;
use dom::{TElement, TNode, TRestyleDamage};
use properties::{ComputedValues, PropertyDeclaration, cascade};
use selector_impl::{NonTSPseudoClass, PseudoElement};
use selector_impl::SelectorImplExt;
use selector_matching::{DeclarationBlock, Stylist};
use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::{CommonStyleAffectingAttributeMode, CommonStyleAffectingAttributes};
use selectors::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
use smallvec::SmallVec;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::slice::Iter;
use std::sync::mpsc::Sender;
@ -51,23 +52,27 @@ fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>(
flags
}
pub struct ApplicableDeclarations {
pub struct ApplicableDeclarations<Impl: SelectorImplExt> {
pub normal: SmallVec<[DeclarationBlock; 16]>,
pub before: Vec<DeclarationBlock>,
pub after: Vec<DeclarationBlock>,
pub per_pseudo: HashMap<Impl::PseudoElement, Vec<DeclarationBlock>>,
/// Whether the `normal` declarations are shareable with other nodes.
pub normal_shareable: bool,
}
impl ApplicableDeclarations {
pub fn new() -> ApplicableDeclarations {
ApplicableDeclarations {
impl<Impl: SelectorImplExt> ApplicableDeclarations<Impl> {
pub fn new() -> ApplicableDeclarations<Impl> {
let mut applicable_declarations = ApplicableDeclarations {
normal: SmallVec::new(),
before: Vec::new(),
after: Vec::new(),
per_pseudo: HashMap::new(),
normal_shareable: false,
}
};
Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
applicable_declarations.per_pseudo.insert(pseudo, vec![]);
});
applicable_declarations
}
}
@ -246,7 +251,7 @@ impl StyleSharingCandidate {
local_name: element.get_local_name().clone(),
class: element.get_attr(&ns!(), &atom!("class"))
.map(|string| string.to_owned()),
link: element.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink),
link: element.is_link(),
namespace: (*element.get_namespace()).clone(),
common_style_affecting_attributes:
create_common_style_affecting_attributes_from_element::<'le, E>(&element)
@ -314,7 +319,7 @@ impl StyleSharingCandidate {
}
}
if element.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) != self.link {
if element.is_link() != self.link {
return false
}
@ -359,9 +364,10 @@ pub enum StyleSharingResult<ConcreteRestyleDamage: TRestyleDamage> {
StyleWasShared(usize, ConcreteRestyleDamage),
}
trait PrivateMatchMethods<'ln>: TNode<'ln> {
trait PrivateMatchMethods<'ln>: TNode<'ln>
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt {
fn cascade_node_pseudo_element(&self,
context: &SharedStyleContext,
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>,
parent_style: Option<&Arc<ComputedValues>>,
applicable_declarations: &[DeclarationBlock],
style: &mut Option<Arc<ComputedValues>>,
@ -434,7 +440,7 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> {
}
fn update_animations_for_cascade(&self,
context: &SharedStyleContext,
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>,
style: &mut Option<Arc<ComputedValues>>)
-> bool {
let style = match *style {
@ -478,7 +484,8 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> {
}
}
impl<'ln, N: TNode<'ln>> PrivateMatchMethods<'ln> for N {}
impl<'ln, N: TNode<'ln>> PrivateMatchMethods<'ln> for N
where <N::ConcreteElement as Element>::Impl: SelectorImplExt {}
trait PrivateElementMatchMethods<'le>: TElement<'le> {
fn share_style_with_candidate_if_possible(&self,
@ -490,7 +497,7 @@ trait PrivateElementMatchMethods<'le>: TElement<'le> {
Some(_) | None => return None,
};
let parent_data: Option<&PrivateStyleData> = unsafe {
let parent_data: Option<&PrivateStyleData<_>> = unsafe {
parent_node.borrow_data_unchecked().map(|d| &*d)
};
@ -512,11 +519,12 @@ trait PrivateElementMatchMethods<'le>: TElement<'le> {
impl<'le, E: TElement<'le>> PrivateElementMatchMethods<'le> for E {}
pub trait ElementMatchMethods<'le> : TElement<'le> {
pub trait ElementMatchMethods<'le> : TElement<'le>
where Self::Impl: SelectorImplExt {
fn match_element(&self,
stylist: &Stylist,
stylist: &Stylist<Self::Impl>,
parent_bf: Option<&BloomFilter>,
applicable_declarations: &mut ApplicableDeclarations)
applicable_declarations: &mut ApplicableDeclarations<Self::Impl>)
-> bool {
let style_attribute = self.style_attribute().as_ref();
@ -526,20 +534,16 @@ pub trait ElementMatchMethods<'le> : TElement<'le> {
style_attribute,
None,
&mut applicable_declarations.normal);
stylist.push_applicable_declarations(self,
parent_bf,
None,
Some(PseudoElement::Before),
&mut applicable_declarations.before);
stylist.push_applicable_declarations(self,
parent_bf,
None,
Some(PseudoElement::After),
&mut applicable_declarations.after);
Self::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
stylist.push_applicable_declarations(self,
parent_bf,
None,
Some(pseudo.clone()),
applicable_declarations.per_pseudo.entry(pseudo).or_insert(vec![]));
});
applicable_declarations.normal_shareable &&
applicable_declarations.before.is_empty() &&
applicable_declarations.after.is_empty()
applicable_declarations.per_pseudo.values().all(|v| v.is_empty())
}
/// Attempts to share a style with another node. This method is unsafe because it depends on
@ -580,7 +584,8 @@ pub trait ElementMatchMethods<'le> : TElement<'le> {
}
}
impl<'le, E: TElement<'le>> ElementMatchMethods<'le> for E {}
impl<'le, E: TElement<'le>> ElementMatchMethods<'le> for E
where E::Impl: SelectorImplExt {}
pub trait MatchMethods<'ln> : TNode<'ln> {
// The below two functions are copy+paste because I can't figure out how to
@ -632,11 +637,12 @@ pub trait MatchMethods<'ln> : TNode<'ln> {
}
unsafe fn cascade_node(&self,
context: &SharedStyleContext,
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>,
parent: Option<Self>,
applicable_declarations: &ApplicableDeclarations,
applicable_declarations: &ApplicableDeclarations<<Self::ConcreteElement as Element>::Impl>,
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
new_animations_sender: &Mutex<Sender<Animation>>) {
new_animations_sender: &Mutex<Sender<Animation>>)
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt {
// Get our parent's style. This must be unsafe so that we don't touch the parent's
// borrow flags.
//
@ -673,28 +679,24 @@ pub trait MatchMethods<'ln> : TNode<'ln> {
new_animations_sender,
applicable_declarations.normal_shareable,
true);
if !applicable_declarations.before.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
context,
Some(data.style.as_ref().unwrap()),
&*applicable_declarations.before,
&mut data.before_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
if !applicable_declarations.after.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
context,
Some(data.style.as_ref().unwrap()),
&*applicable_declarations.after,
&mut data.after_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
<Self::ConcreteElement as Element>::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
let applicable_declarations_for_this_pseudo =
applicable_declarations.per_pseudo.get(&pseudo).unwrap();
if !applicable_declarations_for_this_pseudo.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
context,
Some(data.style.as_ref().unwrap()),
&*applicable_declarations_for_this_pseudo,
data.per_pseudo.entry(pseudo).or_insert(None),
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
});
}
// This method needs to borrow the data as mutable, so make sure data_ref goes out of