diff options
Diffstat (limited to 'components')
30 files changed, 288 insertions, 147 deletions
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index ed1ba4a5740..1ecc9ea98f7 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -39,3 +39,12 @@ git = "https://github.com/servo/rust-geom" [dependencies.url] git = "https://github.com/servo/rust-url" + +[dependencies.string_cache] +git = "https://github.com/servo/string-cache" +branch = "pre-rustup" + +[dependencies.string_cache_macros] +git = "https://github.com/servo/string-cache" +branch = "pre-rustup" + diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 05231a091e4..163aa338b47 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -57,6 +57,7 @@ use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNo use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId}; use script::dom::node::{TextNodeTypeId}; use script::dom::htmlobjectelement::is_image_data; +use servo_util::atom::Atom; use servo_util::namespace; use std::mem; use std::sync::atomics::Relaxed; @@ -1047,7 +1048,8 @@ trait ObjectElement { impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> { fn get_type_and_data(&self) -> (Option<&'static str>, Option<&'static str>) { let elem = self.as_element(); - (elem.get_attr(&namespace::Null, "type"), elem.get_attr(&namespace::Null, "data")) + (elem.get_attr(&namespace::Null, &satom!("type")), + elem.get_attr(&namespace::Null, &satom!("data"))) } fn has_object_data(&self) -> bool { diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index 7abc683f4ad..b26fe8e409b 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -223,8 +223,7 @@ impl StyleSharingCandidate { style: style, parent_style: parent_style, local_name: element.get_local_name().clone(), - class: element.get_attr(&Null, "class") - .map(|string| string.to_string()), + class: element.get_attr(&Null, &satom!("class")).map(|string| string.to_string()), }) } @@ -232,7 +231,7 @@ impl StyleSharingCandidate { if *element.get_local_name() != self.local_name { return false } - match (&self.class, element.get_attr(&Null, "class")) { + match (&self.class, element.get_attr(&Null, &satom!("class"))) { (&None, Some(_)) | (&Some(_), None) => return false, (&Some(ref this_class), Some(element_class)) if element_class != this_class.as_slice() => { return false @@ -454,7 +453,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { } let ok = { let element = self.as_element(); - element.style_attribute().is_none() && element.get_attr(&Null, "id").is_none() + element.style_attribute().is_none() && element.get_attr(&Null, &satom!("id")).is_none() }; if !ok { return CannotShare(false) @@ -501,7 +500,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { // TODO: case-sensitivity depends on the document type and quirks mode element - .get_attr(&Null, "class") + .get_attr(&Null, &satom!("class")) .map(|attr| { for c in attr.split(style::SELECTOR_WHITESPACE) { bf.insert(&c); @@ -520,7 +519,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { // TODO: case-sensitivity depends on the document type and quirks mode element - .get_attr(&Null, "class") + .get_attr(&Null, &satom!("class")) .map(|attr| { for c in attr.split(style::SELECTOR_WHITESPACE) { bf.remove(&c); diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 4ff04389836..d423cfc1555 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -39,6 +39,7 @@ use serialize::{Encodable, Encoder}; use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId}; use servo_net::image::holder::ImageHolder; use servo_net::local_image_cache::LocalImageCache; +use servo_util::atom::Atom; use servo_util::geometry::Au; use servo_util::geometry; use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin}; @@ -174,7 +175,7 @@ impl ImageFragmentInfo { image_url: Url, local_image_cache: Arc<Mutex<LocalImageCache>>) -> ImageFragmentInfo { - fn convert_length(node: &ThreadSafeLayoutNode, name: &str) -> Option<Au> { + fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option<Au> { let element = node.as_element(); element.get_attr(&namespace::Null, name).and_then(|string| { let n: Option<int> = FromStr::from_str(string); @@ -183,8 +184,8 @@ impl ImageFragmentInfo { } let is_vertical = node.style().writing_mode.is_vertical(); - let dom_width = convert_length(node, "width"); - let dom_height = convert_length(node, "height"); + let dom_width = convert_length(node, &satom!("width")); + let dom_height = convert_length(node, &satom!("height")); ImageFragmentInfo { image: ImageHolder::new(image_url, local_image_cache), computed_inline_size: None, @@ -337,7 +338,7 @@ impl TableColumnFragmentInfo { pub fn new(node: &ThreadSafeLayoutNode) -> TableColumnFragmentInfo { let span = { let element = node.as_element(); - element.get_attr(&namespace::Null, "span").and_then(|string| { + element.get_attr(&namespace::Null, &satom!("span")).and_then(|string| { let n: Option<int> = FromStr::from_str(string); n }) diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 171852573c8..7aa6edc1b17 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -29,6 +29,10 @@ extern crate servo_msg = "msg"; #[phase(plugin, link)] extern crate servo_util = "util"; +#[phase(plugin)] +extern crate string_cache_macros; +extern crate string_cache; + extern crate collections; extern crate encoding; extern crate green; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index bdabc3b5840..01fcc4f2f43 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -273,15 +273,14 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> { fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool { assert!(self.is_element()) let name = if self.is_html_element_in_html_document() { - attr.lower_name.as_slice() + &attr.lower_name } else { - attr.name.as_slice() + &attr.name }; match attr.namespace { SpecificNamespace(ref ns) => { let element = self.as_element(); - element.get_attr(ns, name) - .map_or(false, |attr| test(attr)) + element.get_attr(ns, name).map_or(false, |attr| test(attr)) }, // FIXME: https://github.com/mozilla/servo/issues/1558 AnyNamespace => false, @@ -383,7 +382,7 @@ impl<'le> TElement for LayoutElement<'le> { } #[inline] - fn get_attr(&self, namespace: &Namespace, name: &str) -> Option<&'static str> { + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'static str> { unsafe { self.element.get_attr_val_for_layout(namespace, name) } } @@ -395,7 +394,9 @@ impl<'le> TElement for LayoutElement<'le> { ElementNodeTypeId(HTMLAnchorElementTypeId) | ElementNodeTypeId(HTMLAreaElementTypeId) | ElementNodeTypeId(HTMLLinkElementTypeId) => { - unsafe { self.element.get_attr_val_for_layout(&namespace::Null, "href") } + unsafe { + self.element.get_attr_val_for_layout(&namespace::Null, &satom!("href")) + } } _ => None, } @@ -409,7 +410,9 @@ impl<'le> TElement for LayoutElement<'le> { #[inline] fn get_id(&self) -> Option<Atom> { - unsafe { self.element.get_attr_atom_for_layout(&namespace::Null, "id") } + unsafe { + self.element.get_attr_atom_for_layout(&namespace::Null, &satom!("id")) + } } fn get_disabled_state(&self) -> bool { @@ -424,11 +427,24 @@ impl<'le> TElement for LayoutElement<'le> { } } - fn has_class(&self, name: &str) -> bool { + fn has_class(&self, name: &Atom) -> bool { unsafe { self.element.has_class_for_layout(name) } } + + fn each_class(&self, callback: |&Atom|) { + unsafe { + match self.element.get_classes_for_layout() { + None => {} + Some(ref classes) => { + for class in classes.iter() { + callback(class) + } + } + } + } + } } fn get_content(content_list: &content::T) -> String { @@ -758,8 +774,10 @@ pub struct ThreadSafeLayoutElement<'le> { impl<'le> ThreadSafeLayoutElement<'le> { #[inline] - pub fn get_attr(&self, namespace: &Namespace, name: &str) -> Option<&'static str> { - unsafe { self.element.get_attr_val_for_layout(namespace, name) } + pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'static str> { + unsafe { + self.element.get_attr_val_for_layout(namespace, name) + } } } diff --git a/components/macros/lib.rs b/components/macros/lib.rs index 1ce4832b19a..d0d35f88e68 100644 --- a/components/macros/lib.rs +++ b/components/macros/lib.rs @@ -210,6 +210,10 @@ macro_rules! lazy_init( ) ) +#[macro_export] +macro_rules! satom( + ($str:tt) => (Atom::new(atom!($str))) +) #[cfg(test)] mod tests { diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 1748a57956d..7c3bc88f09d 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -52,5 +52,14 @@ branch = "servo" [dependencies.js] git = "https://github.com/servo/rust-mozjs" +[dependencies.string_cache] +git = "https://github.com/servo/string-cache" +branch = "pre-rustup" + +[dependencies.string_cache_macros] +git = "https://github.com/servo/string-cache" +branch = "pre-rustup" + [dependencies.url] git = "https://github.com/servo/rust-url" + diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index be419eb2a61..60b414199e5 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -13,13 +13,13 @@ use dom::element::{Element, AttributeHandlers}; use dom::node::Node; use dom::window::Window; use dom::virtualmethods::vtable_for; + use servo_util::atom::Atom; use servo_util::namespace; use servo_util::namespace::Namespace; use servo_util::str::{DOMString, split_html_space_chars}; use std::cell::{Ref, RefCell}; use std::mem; -use std::slice::Items; pub enum AttrSettingType { FirstSetAttr, @@ -51,9 +51,9 @@ impl AttrValue { AtomAttrValue(value) } - pub fn tokens<'a>(&'a self) -> Option<Items<'a, Atom>> { + pub fn tokens<'a>(&'a self) -> Option<&'a [Atom]> { match *self { - TokenListAttrValue(_, ref tokens) => Some(tokens.iter()), + TokenListAttrValue(_, ref tokens) => Some(tokens.as_slice()), _ => None } } @@ -189,17 +189,19 @@ impl<'a> AttrHelpers for JSRef<'a, Attr> { pub trait AttrHelpersForLayout { unsafe fn value_ref_forever(&self) -> &'static str; unsafe fn value_atom_forever(&self) -> Option<Atom>; - unsafe fn value_tokens_forever(&self) -> Option<Items<Atom>>; + unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]>; unsafe fn local_name_atom_forever(&self) -> Atom; } impl AttrHelpersForLayout for Attr { + #[inline] unsafe fn value_ref_forever(&self) -> &'static str { // cast to point to T in RefCell<T> directly let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref()); value.as_slice() } + #[inline] unsafe fn value_atom_forever(&self) -> Option<Atom> { // cast to point to T in RefCell<T> directly let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref()); @@ -209,15 +211,17 @@ impl AttrHelpersForLayout for Attr { } } - unsafe fn value_tokens_forever(&self) -> Option<Items<Atom>> { + #[inline] + unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]> { // cast to point to T in RefCell<T> directly let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref()); match *value { - TokenListAttrValue(_, ref tokens) => Some(tokens.iter()), + TokenListAttrValue(_, ref tokens) => Some(tokens.as_slice()), _ => None, } } + #[inline] unsafe fn local_name_atom_forever(&self) -> Atom { self.local_name.clone() } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4d0f8bdb682..8554132862f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5458,6 +5458,7 @@ class GlobalGenRoots(): for protoName in descriptor.prototypeChain[1:-1]: protoDescriptor = config.getDescriptor(protoName) delegate = string.Template('''impl ${selfName} for ${baseName} { + #[inline] fn ${fname}(&self) -> bool { self.${parentName}.${fname}() } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 5f2661f9e10..9b65fa61c41 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -52,6 +52,7 @@ use dom::window::{Window, WindowHelpers}; use html::hubbub_html_parser::build_element_from_tag; use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks}; use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage}; +use servo_util::atom::Atom; use servo_util::namespace; use servo_util::namespace::{Namespace, Null}; use servo_util::str::{DOMString, null_str_as_empty_ref, split_html_space_chars}; @@ -730,7 +731,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { } let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); - element.get_attribute(Null, "name").root().map_or(false, |attr| { + element.get_attribute(Null, &satom!("name")).root().map_or(false, |attr| { attr.value().as_slice() == name.as_slice() }) }) diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs index e57f0310ec5..5f1e0d7de37 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -21,24 +21,23 @@ use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS}; pub struct DOMTokenList { reflector_: Reflector, element: JS<Element>, - local_name: &'static str, + local_name: Atom, } impl DOMTokenList { - pub fn new_inherited(element: &JSRef<Element>, - local_name: &'static str) -> DOMTokenList { + pub fn new_inherited(element: &JSRef<Element>, local_name: &Atom) -> DOMTokenList { DOMTokenList { reflector_: Reflector::new(), element: JS::from_rooted(element), - local_name: local_name, + local_name: local_name.clone(), } } - pub fn new(element: &JSRef<Element>, - local_name: &'static str) -> Temporary<DOMTokenList> { + pub fn new(element: &JSRef<Element>, local_name: &Atom) -> Temporary<DOMTokenList> { let window = window_from_node(element).root(); reflect_dom_object(box DOMTokenList::new_inherited(element, local_name), - &Window(*window), DOMTokenListBinding::Wrap) + &Window(*window), + DOMTokenListBinding::Wrap) } } @@ -56,7 +55,7 @@ trait PrivateDOMTokenListHelpers { impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> { fn attribute(&self) -> Option<Temporary<Attr>> { let element = self.element.root(); - element.deref().get_attribute(Null, self.local_name) + element.deref().get_attribute(Null, &self.local_name) } fn check_token_exceptions<'a>(&self, token: &'a str) -> Fallible<&'a str> { @@ -80,7 +79,9 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { // http://dom.spec.whatwg.org/#dom-domtokenlist-item fn Item(&self, index: u32) -> Option<DOMString> { self.attribute().root().and_then(|attr| attr.value().tokens().and_then(|mut tokens| { - tokens.idx(index as uint).map(|token| token.as_slice().to_string()) + tokens.iter() + .idx(index as uint) + .map(|token| token.as_slice().to_string()) })) } @@ -95,7 +96,7 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { self.check_token_exceptions(token.as_slice()).map(|slice| { self.attribute().root().and_then(|attr| attr.value().tokens().map(|mut tokens| { let atom = Atom::from_slice(slice); - tokens.any(|token| *token == atom) + tokens.iter().any(|token| *token == atom) })).unwrap_or(false) }) } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 953036788f4..b6b76f34593 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -55,6 +55,7 @@ pub struct Element { } impl ElementDerived for EventTarget { + #[inline] fn is_element(&self) -> bool { match self.type_id { NodeTargetTypeId(ElementNodeTypeId(_)) => true, @@ -167,21 +168,22 @@ impl Element { } pub trait RawLayoutElementHelpers { - unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) -> Option<&'static str>; - unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str) -> Option<Atom>; - unsafe fn has_class_for_layout(&self, name: &str) -> bool; + unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option<&'static str>; + unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option<Atom>; + unsafe fn has_class_for_layout(&self, name: &Atom) -> bool; + unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]>; } impl RawLayoutElementHelpers for Element { #[inline] #[allow(unrooted_must_root)] - unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) + unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option<&'static str> { // cast to point to T in RefCell<T> directly let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS<Attr>| { let attr = attr.unsafe_get(); - name == (*attr).local_name_atom_forever().as_slice() && + *name == (*attr).local_name_atom_forever() && (*attr).namespace == *namespace }).map(|attr| { let attr = attr.unsafe_get(); @@ -191,13 +193,13 @@ impl RawLayoutElementHelpers for Element { #[inline] #[allow(unrooted_must_root)] - unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str) + unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option<Atom> { // cast to point to T in RefCell<T> directly let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS<Attr>| { let attr = attr.unsafe_get(); - name == (*attr).local_name_atom_forever().as_slice() && + *name == (*attr).local_name_atom_forever() && (*attr).namespace == *namespace }).and_then(|attr| { let attr = attr.unsafe_get(); @@ -207,16 +209,31 @@ impl RawLayoutElementHelpers for Element { #[inline] #[allow(unrooted_must_root)] - unsafe fn has_class_for_layout(&self, name: &str) -> bool { + unsafe fn has_class_for_layout(&self, name: &Atom) -> bool { let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS<Attr>| { let attr = attr.unsafe_get(); - (*attr).local_name_atom_forever().as_slice() == "class" + (*attr).local_name_atom_forever() == satom!("class") }).map_or(false, |attr| { let attr = attr.unsafe_get(); - (*attr).value_tokens_forever().map(|mut tokens| { tokens.any(|atom| atom.as_slice() == name) }) + (*attr).value_tokens_forever().map(|mut tokens| { + tokens.iter().any(|atom| atom == name) + }) }.take().unwrap()) } + + #[inline] + #[allow(unrooted_must_root)] + unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]> { + let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); + (*attrs).iter().find(|attr: & &JS<Attr>| { + let attr = attr.unsafe_get(); + (*attr).local_name_atom_forever() == satom!("class") + }).and_then(|attr| { + let attr = attr.unsafe_get(); + (*attr).value_tokens_forever() + }) + } } pub trait LayoutElementHelpers { @@ -225,6 +242,7 @@ pub trait LayoutElementHelpers { impl LayoutElementHelpers for JS<Element> { #[allow(unrooted_must_root)] + #[inline] unsafe fn html_element_in_html_document_for_layout(&self) -> bool { if (*self.unsafe_get()).namespace != namespace::HTML { return false @@ -257,10 +275,11 @@ impl<'a> ElementHelpers for JSRef<'a, Element> { } pub trait AttributeHandlers { - /// Returns the attribute with given namespace and case-sensitive local - /// name, if any. - fn get_attribute(&self, namespace: Namespace, local_name: &str) - -> Option<Temporary<Attr>>; + /// Returns the attribute with given namespace and case-insensitive local name, if any. + fn get_attribute(&self, namespace: Namespace, local_name: &Atom) -> Option<Temporary<Attr>>; + /// Returns the attribute with given namespace and case-sensitive local name, if any. + fn get_case_sensitive_attribute(&self, namespace: Namespace, name: &Atom) + -> Option<Temporary<Attr>>; fn set_attribute_from_parser(&self, local_name: Atom, value: DOMString, namespace: Namespace, prefix: Option<DOMString>); @@ -273,27 +292,38 @@ pub trait AttributeHandlers { fn remove_attribute(&self, namespace: Namespace, name: &str); fn notify_attribute_changed(&self, local_name: &Atom); - fn has_class(&self, name: &str) -> bool; + fn has_class(&self, name: &Atom) -> bool; fn set_atomic_attribute(&self, name: &str, value: DOMString); // http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes fn has_attribute(&self, name: &str) -> bool; fn set_bool_attribute(&self, name: &str, value: bool); - fn get_url_attribute(&self, name: &str) -> DOMString; + fn get_url_attribute(&self, name: &Atom) -> DOMString; fn set_url_attribute(&self, name: &str, value: DOMString); - fn get_string_attribute(&self, name: &str) -> DOMString; + fn get_string_attribute(&self, name: &Atom) -> DOMString; fn set_string_attribute(&self, name: &str, value: DOMString); fn set_tokenlist_attribute(&self, name: &str, value: DOMString); - fn get_uint_attribute(&self, name: &str) -> u32; + fn get_uint_attribute(&self, name: &Atom) -> u32; fn set_uint_attribute(&self, name: &str, value: u32); } impl<'a> AttributeHandlers for JSRef<'a, Element> { - fn get_attribute(&self, namespace: Namespace, local_name: &str) -> Option<Temporary<Attr>> { - let local_name = Atom::from_slice(local_name); - self.attrs.borrow().iter().map(|attr| attr.root()).find(|attr| { - *attr.local_name() == local_name && attr.namespace == namespace + fn get_attribute(&self, namespace: Namespace, name: &Atom) -> Option<Temporary<Attr>> { + match self.html_element_in_html_document() { + true => { + let local_name = Atom::from_slice(name.as_slice().to_ascii_lower().as_slice()); + self.get_case_sensitive_attribute(namespace, &local_name) + } + false => self.get_case_sensitive_attribute(namespace, name), + } + } + + fn get_case_sensitive_attribute(&self, namespace: Namespace, local_name: &Atom) + -> Option<Temporary<Attr>> { + let element: &Element = self.deref(); + element.attrs.borrow().iter().map(|attr| attr.root()).find(|attr| { + attr.local_name() == local_name && attr.namespace == namespace }).map(|x| Temporary::from_rooted(&*x)) } @@ -393,11 +423,12 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { } } - fn has_class(&self, name: &str) -> bool { - self.get_attribute(Null, "class").root().map(|attr| { - attr.deref().value().tokens().map(|mut tokens| { - tokens.any(|atom| atom.as_slice() == name) - }).unwrap_or(false) + fn has_class(&self, name: &Atom) -> bool { + self.get_attribute(Null, &satom!("class")).root().map(|attr| { + match attr.deref().value().tokens() { + None => false, + Some(ref atoms) => atoms.iter().any(|atom| atom == name), + } }).unwrap_or(false) } @@ -426,8 +457,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { } } - fn get_url_attribute(&self, name: &str) -> DOMString { - assert!(name == name.to_ascii_lower().as_slice()); + fn get_url_attribute(&self, name: &Atom) -> DOMString { // XXX Resolve URL. self.get_string_attribute(name) } @@ -435,8 +465,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.set_string_attribute(name, value); } - fn get_string_attribute(&self, name: &str) -> DOMString { - assert!(name == name.to_ascii_lower().as_slice()); + fn get_string_attribute(&self, name: &Atom) -> DOMString { match self.get_attribute(Null, name) { Some(x) => { let x = x.root(); @@ -455,8 +484,8 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.set_attribute(name, AttrValue::from_tokenlist(value)); } - fn get_uint_attribute(&self, name: &str) -> u32 { - assert!(name == name.to_ascii_lower().as_slice()); + fn get_uint_attribute(&self, name: &Atom) -> u32 { + assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice()); let attribute = self.get_attribute(Null, name).root(); match attribute { Some(attribute) => { @@ -523,7 +552,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-id fn Id(&self) -> DOMString { - self.get_string_attribute("id") + self.get_string_attribute(&satom!("id")) } // http://dom.spec.whatwg.org/#dom-element-id @@ -533,7 +562,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-classname fn ClassName(&self) -> DOMString { - self.get_string_attribute("class") + self.get_string_attribute(&satom!("class")) } // http://dom.spec.whatwg.org/#dom-element-classname @@ -546,7 +575,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { match self.class_list.get() { Some(class_list) => Temporary::new(class_list), None => { - let class_list = DOMTokenList::new(self, "class").root(); + let class_list = DOMTokenList::new(self, &satom!("class")).root(); self.class_list.assign(Some(class_list.deref().clone())); Temporary::from_rooted(&*class_list) } @@ -577,7 +606,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } else { name }; - self.get_attribute(Null, name.as_slice()).root() + self.get_attribute(Null, &Atom::from_slice(name.as_slice())).root() .map(|s| s.deref().Value()) } @@ -586,7 +615,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> { let namespace = Namespace::from_str(null_str_as_empty_ref(&namespace)); - self.get_attribute(namespace, local_name.as_slice()).root() + self.get_attribute(namespace, &Atom::from_slice(local_name.as_slice())).root() .map(|attr| attr.deref().Value()) } @@ -896,7 +925,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { if !tree_in_doc { return; } - match self.get_attribute(Null, "id").root() { + match self.get_attribute(Null, &satom!("id")).root() { Some(attr) => { let doc = document_from_node(self).root(); let value = attr.deref().Value(); @@ -916,7 +945,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { if !tree_in_doc { return; } - match self.get_attribute(Null, "id").root() { + match self.get_attribute(Null, &satom!("id")).root() { Some(attr) => { let doc = document_from_node(self).root(); let value = attr.deref().Value(); @@ -930,8 +959,8 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { } impl<'a> style::TElement for JSRef<'a, Element> { - fn get_attr(&self, namespace: &Namespace, attr: &str) -> Option<&'static str> { - self.get_attribute(namespace.clone(), attr).root().map(|attr| { + fn get_attr(&self, namespace: &Namespace, attr: &Atom) -> Option<&'static str> { + self.get_case_sensitive_attribute(namespace.clone(), attr).root().map(|attr| { unsafe { mem::transmute(attr.deref().value().as_slice()) } }) } @@ -943,7 +972,9 @@ impl<'a> style::TElement for JSRef<'a, Element> { // selector-link ElementNodeTypeId(HTMLAnchorElementTypeId) | ElementNodeTypeId(HTMLAreaElementTypeId) | - ElementNodeTypeId(HTMLLinkElementTypeId) => self.get_attr(&namespace::Null, "href"), + ElementNodeTypeId(HTMLLinkElementTypeId) => { + self.get_attr(&namespace::Null, &satom!("href")) + } _ => None, } } @@ -958,7 +989,7 @@ impl<'a> style::TElement for JSRef<'a, Element> { node.get_hover_state() } fn get_id<'a>(&self) -> Option<Atom> { - self.get_attribute(namespace::Null, "id").map(|attr| { + self.get_attribute(namespace::Null, &satom!("id")).map(|attr| { let attr = attr.root(); match *attr.value() { AtomAttrValue(ref val) => val.clone(), @@ -974,7 +1005,22 @@ impl<'a> style::TElement for JSRef<'a, Element> { let node: &JSRef<Node> = NodeCast::from_ref(self); node.get_enabled_state() } - fn has_class(&self, name: &str) -> bool { + fn has_class(&self, name: &Atom) -> bool { (self as &AttributeHandlers).has_class(name) } + fn each_class(&self, callback: |&Atom|) { + match self.get_attribute(Null, &satom!("class")) { + None => {} + Some(ref attr) => { + match attr.root().value().tokens() { + None => {} + Some(ref atoms) => { + for atom in atoms.iter() { + callback(atom); + } + } + } + } + } + } } diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs index 0a8efa15890..ea80b3aa1db 100644 --- a/components/script/dom/htmlanchorelement.rs +++ b/components/script/dom/htmlanchorelement.rs @@ -57,7 +57,7 @@ impl<'a> PrivateHTMLAnchorElementHelpers for JSRef<'a, HTMLAnchorElement> { fn handle_event_impl(&self, event: &JSRef<Event>) { if "click" == event.Type().as_slice() && !event.DefaultPrevented() { let element: &JSRef<Element> = ElementCast::from_ref(self); - let attr = element.get_attribute(Null, "href").root(); + let attr = element.get_attribute(Null, &satom!("href")).root(); match attr { Some(ref href) => { let value = href.Value(); diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index bd07b82e53e..78dd03d9859 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -146,15 +146,17 @@ impl HTMLCollection { pub fn by_class_name(window: &JSRef<Window>, root: &JSRef<Node>, classes: DOMString) -> Temporary<HTMLCollection> { struct ClassNameFilter { - classes: Vec<DOMString> + classes: Vec<Atom> } impl CollectionFilter for ClassNameFilter { fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool { - self.classes.iter().all(|class| elem.has_class(class.as_slice())) + self.classes.iter().all(|class| elem.has_class(class)) } } let filter = ClassNameFilter { - classes: split_html_space_chars(classes.as_slice()).map(|class| class.to_string()).collect() + classes: split_html_space_chars(classes.as_slice()).map(|class| { + Atom::from_slice(class) + }).collect() }; HTMLCollection::create(window, root, box filter) } @@ -220,8 +222,8 @@ impl<'a> HTMLCollectionMethods for JSRef<'a, HTMLCollection> { Static(ref elems) => elems.iter() .map(|elem| elem.root()) .find(|elem| { - elem.get_string_attribute("name") == key || - elem.get_string_attribute("id") == key }) + elem.get_string_attribute(&satom!("name")) == key || + elem.get_string_attribute(&satom!("id")) == key }) .map(|maybe_elem| Temporary::from_rooted(&*maybe_elem)), Live(ref root, ref filter) => { let root = root.root(); @@ -232,8 +234,8 @@ impl<'a> HTMLCollectionMethods for JSRef<'a, HTMLCollection> { .map(|elem| elem.clone()) }) .find(|elem| { - elem.get_string_attribute("name") == key || - elem.get_string_attribute("id") == key }) + elem.get_string_attribute(&satom!("name")) == key || + elem.get_string_attribute(&satom!("id")) == key }) .map(|maybe_elem| Temporary::from_rooted(&maybe_elem)) } } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a5c83002327..551a36f448e 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -75,7 +75,7 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { fn get_url(&self) -> Option<Url> { let element: &JSRef<Element> = ElementCast::from_ref(self); - element.get_attribute(Null, "src").root().and_then(|src| { + element.get_attribute(Null, &satom!("src")).root().and_then(|src| { let url = src.deref().value(); if url.as_slice().is_empty() { None @@ -133,7 +133,7 @@ impl HTMLIFrameElement { impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> { fn Src(&self) -> DOMString { let element: &JSRef<Element> = ElementCast::from_ref(self); - element.get_string_attribute("src") + element.get_string_attribute(&satom!("src")) } fn SetSrc(&self, src: DOMString) { @@ -143,7 +143,7 @@ impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> { fn Sandbox(&self) -> DOMString { let element: &JSRef<Element> = ElementCast::from_ref(self); - element.get_string_attribute("sandbox") + element.get_string_attribute(&satom!("sandbox")) } fn SetSandbox(&self, sandbox: DOMString) { diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 3c44a9cba8b..4a25be91e73 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -92,11 +92,11 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { // FIXME: workaround for https://github.com/mozilla/rust/issues/13246; // we get unrooting order failures if these are inside the match. let rel = { - let rel = element.get_attribute(Null, "rel").root(); + let rel = element.get_attribute(Null, &satom!("rel")).root(); rel.map(|rel| rel.deref().value().as_slice().to_string()) }; let href = { - let href = element.get_attribute(Null, "href").root(); + let href = element.get_attribute(Null, &satom!("href")).root(); href.map(|href| href.deref().value().as_slice().to_string()) }; diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index a702916d40a..634051957ea 100644 --- a/components/script/dom/htmlobjectelement.rs +++ b/components/script/dom/htmlobjectelement.rs @@ -63,8 +63,8 @@ impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> { let elem: &JSRef<Element> = ElementCast::from_ref(self); // TODO: support other values - match (elem.get_attribute(Null, "type").map(|x| x.root().Value()), - elem.get_attribute(Null, "data").map(|x| x.root().Value())) { + match (elem.get_attribute(Null, &satom!("type")).map(|x| x.root().Value()), + elem.get_attribute(Null, &satom!("data")).map(|x| x.root().Value())) { (None, Some(uri)) => { if is_image_data(uri.as_slice()) { let data_url = Url::parse(uri.as_slice()).unwrap(); diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 29cb155a984..95cbd666920 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -16,6 +16,7 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; +use servo_util::atom::Atom; use servo_util::namespace::Null; use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec}; @@ -75,7 +76,7 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { fn is_javascript(&self) -> bool { let element: &JSRef<Element> = ElementCast::from_ref(self); - match element.get_attribute(Null, "type").root().map(|s| s.Value()) { + match element.get_attribute(Null, &satom!("type")).root().map(|s| s.Value()) { Some(ref s) if s.is_empty() => { // type attr exists, but empty means js debug!("script type empty, inferring js"); @@ -87,7 +88,9 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { }, None => { debug!("no script type"); - match element.get_attribute(Null, "language").root().map(|s| s.Value()) { + match element.get_attribute(Null, &satom!("language")) + .root() + .map(|s| s.Value()) { Some(ref s) if s.is_empty() => { debug!("script language empty, inferring js"); true @@ -109,7 +112,7 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { impl<'a> HTMLScriptElementMethods for JSRef<'a, HTMLScriptElement> { fn Src(&self) -> DOMString { let element: &JSRef<Element> = ElementCast::from_ref(self); - element.get_url_attribute("src") + element.get_url_attribute(&satom!("src")) } // http://www.whatwg.org/html/#dom-script-text diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 6cfca77593d..23f65a6b186 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -12,7 +12,8 @@ macro_rules! make_getter( use dom::bindings::codegen::InheritTypes::ElementCast; use std::ascii::StrAsciiExt; let element: &JSRef<Element> = ElementCast::from_ref(self); - element.get_string_attribute(stringify!($attr).to_ascii_lower().as_slice()) + element.get_string_attribute(&Atom::from_slice(stringify!($attr).to_ascii_lower() + .as_slice())) } ); ) @@ -38,7 +39,8 @@ macro_rules! make_uint_getter( use dom::bindings::codegen::InheritTypes::ElementCast; use std::ascii::StrAsciiExt; let element: &JSRef<Element> = ElementCast::from_ref(self); - element.get_uint_attribute(stringify!($attr).to_ascii_lower().as_slice()) + element.get_uint_attribute(&Atom::from_slice(stringify!($attr).to_ascii_lower() + .as_slice())) } ); ) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 9e1b73feb12..8462d652e45 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -769,16 +769,19 @@ pub trait RawLayoutNodeHelpers { } impl RawLayoutNodeHelpers for Node { + #[inline] unsafe fn get_hover_state_for_layout(&self) -> bool { (*self.unsafe_get_flags()).contains(InHoverState) } + #[inline] unsafe fn get_disabled_state_for_layout(&self) -> bool { (*self.unsafe_get_flags()).contains(InDisabledState) } + #[inline] unsafe fn get_enabled_state_for_layout(&self) -> bool { (*self.unsafe_get_flags()).contains(InEnabledState) } - + #[inline] fn type_id_for_layout(&self) -> NodeTypeId { self.type_id } @@ -1413,6 +1416,7 @@ impl Node { } } + #[inline] pub unsafe fn unsafe_get_flags(&self) -> *const NodeFlags { mem::transmute(&self.flags) } @@ -1987,7 +1991,7 @@ impl<'a> VirtualMethods for JSRef<'a, Node> { } } -impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> { +impl<'a> style::TNode<JSRef<'a,Element>> for JSRef<'a,Node> { fn parent_node(&self) -> Option<JSRef<'a, Node>> { (self as &NodeHelpers).parent_node().map(|node| *node.root()) } @@ -2021,9 +2025,9 @@ impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> { fn match_attr(&self, attr: &style::AttrSelector, test: |&str| -> bool) -> bool { let name = { if self.is_html_element_in_html_document() { - attr.lower_name.as_slice() + &attr.lower_name } else { - attr.name.as_slice() + &attr.name } }; match attr.namespace { diff --git a/components/script/html/hubbub_html_parser.rs b/components/script/html/hubbub_html_parser.rs index 74dd6ca933b..215c36ac3cf 100644 --- a/components/script/html/hubbub_html_parser.rs +++ b/components/script/html/hubbub_html_parser.rs @@ -472,7 +472,7 @@ pub fn parse_html(page: &Page, }; let script_element: &JSRef<Element> = ElementCast::from_ref(script); - match script_element.get_attribute(Null, "src").root() { + match script_element.get_attribute(Null, &satom!("src")).root() { Some(src) => { debug!("found script: {:s}", src.deref().Value()); let mut url_parser = UrlParser::new(); diff --git a/components/script/lib.rs b/components/script/lib.rs index 9f3effaa368..69d52df8281 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -36,6 +36,9 @@ extern crate servo_macros = "macros"; extern crate servo_net = "net"; extern crate servo_util = "util"; extern crate style; +extern crate string_cache; +#[phase(plugin)] +extern crate string_cache_macros; extern crate sync; extern crate servo_msg = "msg"; extern crate url; diff --git a/components/script/page.rs b/components/script/page.rs index 6e8f414ef8d..eca24e6d814 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -27,6 +27,7 @@ use servo_msg::compositor_msg::ScriptListener; use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData}; use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_net::resource_task::ResourceTask; +use servo_util::atom::Atom; use servo_util::namespace::Null; use servo_util::str::DOMString; use std::cell::{Cell, RefCell, Ref, RefMut}; @@ -373,9 +374,11 @@ impl Page { .filter(|node| node.is_anchor_element()); anchors.find(|node| { let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); - elem.get_attribute(Null, "name").root().map_or(false, |attr| { - attr.deref().value().as_slice() == fragid.as_slice() - }) + elem.get_attribute(Null, &satom!("name")) + .root() + .map_or(false, |attr| { + attr.deref().value().as_slice() == fragid.as_slice() + }) }).map(|node| Temporary::from_rooted(ElementCast::to_ref(&node).unwrap())) } } diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index a8ccfc42e35..9f354a6c9fa 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -29,3 +29,11 @@ git = "https://github.com/servo/rust-cssparser" [dependencies.encoding] git = "https://github.com/lifthrasiir/rust-encoding" +[dependencies.string_cache] +git = "https://github.com/servo/string-cache" +branch = "pre-rustup" + +[dependencies.string_cache_macros] +git = "https://github.com/servo/string-cache" +branch = "pre-rustup" + diff --git a/components/style/lib.rs b/components/style/lib.rs index 107889cb57a..d182c9ffea0 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -11,12 +11,14 @@ #![feature(phase)] #[phase(plugin, link)] extern crate log; +#[phase(plugin)] extern crate string_cache_macros; extern crate debug; extern crate collections; extern crate geom; extern crate num; extern crate serialize; +extern crate string_cache; extern crate sync; extern crate url; diff --git a/components/style/node.rs b/components/style/node.rs index bd71aa6fd79..a4d2ff38e41 100644 --- a/components/style/node.rs +++ b/components/style/node.rs @@ -9,7 +9,7 @@ use selectors::AttrSelector; use servo_util::atom::Atom; use servo_util::namespace::Namespace; - +// FIXME(pcwalton): When we get associated types in Rust, this can be nicer. pub trait TNode<E:TElement> : Clone { fn parent_node(&self) -> Option<Self>; /// Name is prefixed to avoid a conflict with TLayoutNode. @@ -24,7 +24,7 @@ pub trait TNode<E:TElement> : Clone { } pub trait TElement { - fn get_attr(&self, namespace: &Namespace, attr: &str) -> Option<&'static str>; + fn get_attr(&self, namespace: &Namespace, attr: &Atom) -> Option<&'static str>; fn get_link(&self) -> Option<&'static str>; fn get_local_name<'a>(&'a self) -> &'a Atom; fn get_namespace<'a>(&'a self) -> &'a Namespace; @@ -32,5 +32,13 @@ pub trait TElement { 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|); } + + diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index a0ddf7dd31d..76ff6edae49 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -11,7 +11,6 @@ use url::Url; use servo_util::atom::Atom; use servo_util::bloom::BloomFilter; -use servo_util::namespace; use servo_util::smallvec::VecLike; use servo_util::sort; @@ -106,20 +105,14 @@ impl SelectorMap { None => {} } - match element.get_attr(&namespace::Null, "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 @@ -467,7 +460,12 @@ impl DeclarationBlock { } } -pub fn matches<E:TElement, N:TNode<E>>(selector_list: &SelectorList, element: &N, parent_bf: &Option<BloomFilter>) -> bool { +pub fn matches<E:TElement, + N:TNode<E>>( + selector_list: &SelectorList, + element: &N, + parent_bf: &Option<BloomFilter>) + -> bool { get_selector_list_selectors(selector_list).iter().any(|selector| selector.pseudo_element.is_none() && matches_compound_selector(&*selector.compound_selectors, element, parent_bf, &mut false)) @@ -544,11 +542,13 @@ enum SelectorMatchingResult { /// Quickly figures out whether or not the compound selector is worth doing more /// work on. If the simple selectors don't match, or there's a child selector /// that does not appear in the bloom parent bloom filter, we can exit early. -fn can_fast_reject<E: TElement, N: TNode<E>>( - mut selector: &CompoundSelector, - element: &N, - parent_bf: &Option<BloomFilter>, - shareable: &mut bool) -> Option<SelectorMatchingResult> { +fn can_fast_reject<E:TElement, + N:TNode<E>>( + mut selector: &CompoundSelector, + element: &N, + parent_bf: &Option<BloomFilter>, + shareable: &mut bool) + -> Option<SelectorMatchingResult> { if !selector.simple_selectors.iter().all(|simple_selector| { matches_simple_selector(simple_selector, element, shareable) }) { return Some(NotMatchedAndRestartFromClosestLaterSibling); @@ -681,11 +681,11 @@ fn matches_compound_selector_internal<E:TElement, /// `main/css/matching.rs`.) #[inline] pub fn matches_simple_selector<E:TElement, - N:TNode<E>>( - selector: &SimpleSelector, - element: &N, - shareable: &mut bool) - -> bool { + N:TNode<E>>( + selector: &SimpleSelector, + element: &N, + shareable: &mut bool) + -> bool { match *selector { LocalNameSelector(LocalNameSelector { ref name, ref lower_name }) => { let name = if element.is_html_element_in_html_document() { lower_name } else { name }; @@ -710,7 +710,7 @@ pub fn matches_simple_selector<E:TElement, // 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) => { @@ -854,6 +854,7 @@ pub fn matches_simple_selector<E:TElement, } } +#[inline] fn url_is_visited(_url: &str) -> bool { // FIXME: implement this. // This function will probably need to take a "session" @@ -862,8 +863,7 @@ fn url_is_visited(_url: &str) -> bool { } #[inline] -fn matches_generic_nth_child<'a, - E:TElement, +fn matches_generic_nth_child<E:TElement, N:TNode<E>>( element: &N, a: i32, diff --git a/components/style/selectors.rs b/components/style/selectors.rs index c398c09877e..81a538c1205 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -100,8 +100,8 @@ pub struct LocalNameSelector { #[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, } @@ -442,8 +442,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); diff --git a/components/util/atom.rs b/components/util/atom.rs index 49cb047768e..14215d66528 100644 --- a/components/util/atom.rs +++ b/components/util/atom.rs @@ -18,6 +18,13 @@ pub struct Atom { impl Atom { #[inline(always)] + pub fn new(atom: atom::Atom) -> Atom { + Atom { + atom: atom, + } + } + + #[inline(always)] pub fn from_slice(slice: &str) -> Atom { Atom { atom: atom::Atom::from_slice(slice) |