auto merge of #3623 : pcwalton/servo/use-atoms-2, r=jdm

75% improvement in style recalc for Guardians of the Galaxy.
This commit is contained in:
bors-servo 2014-10-14 12:42:35 -06:00
commit 8077edc062
31 changed files with 305 additions and 237 deletions

View file

@ -35,3 +35,4 @@ git = "https://github.com/servo/string-cache"
[dependencies.string_cache_macros]
git = "https://github.com/servo/string-cache"

View file

@ -11,6 +11,7 @@
#![feature(phase)]
#[phase(plugin, link)] extern crate log;
#[phase(plugin)] extern crate string_cache_macros;
extern crate debug;
extern crate collections;

View file

@ -8,7 +8,6 @@
use selectors::AttrSelector;
use string_cache::{Atom, Namespace};
pub trait TNode<'a, E: TElement<'a>> : Clone + Copy {
fn parent_node(self) -> Option<Self>;
fn first_child(self) -> Option<Self>;
@ -28,8 +27,8 @@ pub trait TNode<'a, E: TElement<'a>> : Clone + Copy {
}
pub trait TElement<'a> : Copy {
fn get_attr(self, namespace: &Namespace, attr: &str) -> Option<&'a str>;
fn get_attrs(self, attr: &str) -> Vec<&'a str>;
fn get_attr(self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
fn get_attrs(self, attr: &Atom) -> Vec<&'a str>;
fn get_link(self) -> Option<&'a str>;
fn get_local_name(self) -> &'a Atom;
fn get_namespace(self) -> &'a Namespace;
@ -37,6 +36,13 @@ pub trait TElement<'a> : Copy {
fn get_id(self) -> Option<Atom>;
fn get_disabled_state(self) -> bool;
fn get_enabled_state(self) -> bool;
fn has_class(self, name: &str) -> bool;
fn has_class(self, name: &Atom) -> bool;
// Ordinarily I wouldn't use callbacks like this, but the alternative is
// really messy, since there is a `JSRef` and a `RefCell` involved. Maybe
// in the future when we have associated types and/or a more convenient
// JS GC story... --pcwalton
fn each_class(self, callback: |&Atom|);
}

View file

@ -108,20 +108,14 @@ impl SelectorMap {
None => {}
}
match element.get_attr(&ns!(""), "class") {
Some(ref class_attr) => {
// FIXME: Store classes pre-split as atoms to make the loop below faster.
for class in class_attr.split(SELECTOR_WHITESPACE) {
SelectorMap::get_matching_rules_from_hash(node,
parent_bf,
&self.class_hash,
&Atom::from_slice(class),
matching_rules_list,
shareable);
}
}
None => {}
}
element.each_class(|class| {
SelectorMap::get_matching_rules_from_hash(node,
parent_bf,
&self.class_hash,
class,
matching_rules_list,
shareable);
});
let local_name_hash = if node.is_html_element_in_html_document() {
&self.lower_local_name_hash
@ -699,12 +693,12 @@ fn matches_compound_selector_internal<'a,
/// will almost certainly break as nodes will start mistakenly sharing styles. (See the code in
/// `main/css/matching.rs`.)
#[inline]
pub fn matches_simple_selector<'a, E:TElement<'a>,
N:TNode<'a, E>>(
selector: &SimpleSelector,
element: &N,
shareable: &mut bool)
-> bool {
pub fn matches_simple_selector<'a,E,N>(
selector: &SimpleSelector,
element: &N,
shareable: &mut bool)
-> bool
where E:TElement<'a>, N:TNode<'a,E> {
match *selector {
LocalNameSelector(LocalName { ref name, ref lower_name }) => {
let name = if element.is_html_element_in_html_document() { lower_name } else { name };
@ -718,7 +712,6 @@ pub fn matches_simple_selector<'a, E:TElement<'a>,
element.get_namespace() == namespace
}
// TODO: case-sensitivity depends on the document type and quirks mode
// TODO: cache and intern IDs on elements.
IDSelector(ref id) => {
*shareable = false;
let element = element.as_element();
@ -726,10 +719,9 @@ pub fn matches_simple_selector<'a, E:TElement<'a>,
attr == *id
})
}
// TODO: cache and intern class names on elements.
ClassSelector(ref class) => {
let element = element.as_element();
element.has_class(class.as_slice())
element.has_class(class)
}
AttrExists(ref attr) => {
@ -876,6 +868,7 @@ pub fn matches_simple_selector<'a, E:TElement<'a>,
}
}
#[inline]
fn url_is_visited(_url: &str) -> bool {
// FIXME: implement this.
// This function will probably need to take a "session"
@ -884,15 +877,14 @@ fn url_is_visited(_url: &str) -> bool {
}
#[inline]
fn matches_generic_nth_child<'a,
E:TElement<'a>,
N:TNode<'a, E>>(
fn matches_generic_nth_child<'a,E,N>(
element: &N,
a: i32,
b: i32,
is_of_type: bool,
is_from_end: bool)
-> bool {
-> bool
where E: TElement<'a>, N: TNode<'a,E> {
let mut node = element.clone();
// fail if we can't find a parent or if the node is the root element
// of the document (Cf. Selectors Level 3)

View file

@ -106,8 +106,8 @@ pub struct LocalName {
#[deriving(Eq, PartialEq, Clone, Hash)]
pub struct AttrSelector {
pub name: String,
pub lower_name: String,
pub name: Atom,
pub lower_name: Atom,
pub namespace: NamespaceConstraint,
}
@ -448,8 +448,8 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace
Some((_, None)) => fail!("Implementation error, this should not happen."),
Some((namespace, Some(local_name))) => AttrSelector {
namespace: namespace,
lower_name: local_name.as_slice().to_ascii_lower(),
name: local_name,
lower_name: Atom::from_slice(local_name.as_slice().to_ascii_lower().as_slice()),
name: Atom::from_slice(local_name.as_slice()),
},
};
skip_whitespace(iter);
@ -675,8 +675,8 @@ mod tests {
assert!(parse_ns("[Foo]", &namespaces) == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(AttrExists(AttrSelector {
name: String::from_str("Foo"),
lower_name: String::from_str("foo"),
name: Atom::from_slice("Foo"),
lower_name: Atom::from_slice("foo"),
namespace: SpecificNamespace(ns!("")),
})),
next: None,
@ -690,8 +690,8 @@ mod tests {
assert!(parse_ns("[Foo]", &namespaces) == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(AttrExists(AttrSelector {
name: String::from_str("Foo"),
lower_name: String::from_str("foo"),
name: Atom::from_slice("Foo"),
lower_name: Atom::from_slice("foo"),
namespace: SpecificNamespace(ns!("")),
})),
next: None,