diff --git a/components/layout/construct.rs b/components/layout/construct.rs index ffdf535874e..82bff208604 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -226,7 +226,7 @@ impl<'a> FlowConstructor<'a> { //FIXME: would it make more sense to use HTMLInputElement::input_type instead of the raw // value? definitely for string comparisons. let elem = node.as_element(); - let data = match elem.get_attr(&ns!(""), "type") { + let data = match elem.get_attr(&ns!(""), &atom!("type")) { Some("checkbox") | Some("radio") => None, Some("button") | Some("submit") | Some("reset") => Some(node.get_input_value().len() as u32), @@ -1158,7 +1158,7 @@ trait ObjectElement<'a> { impl<'ln> ObjectElement<'ln> for ThreadSafeLayoutNode<'ln> { fn get_type_and_data(&self) -> (Option<&'ln str>, Option<&'ln str>) { let elem = self.as_element(); - (elem.get_attr(&ns!(""), "type"), elem.get_attr(&ns!(""), "data")) + (elem.get_attr(&ns!(""), &atom!("type")), elem.get_attr(&ns!(""), &atom!("data"))) } fn has_object_data(&self) -> bool { diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index 2c5207e7fd9..d3ea0b48b7f 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -15,7 +15,6 @@ use script::dom::node::{TextNodeTypeId}; use servo_util::bloom::BloomFilter; use servo_util::cache::{Cache, LRUCache, SimpleHashCache}; use servo_util::smallvec::{SmallVec, SmallVec16}; -use servo_util::str::DOMString; use std::mem; use std::hash::{Hash, sip}; use std::slice::Items; @@ -165,7 +164,8 @@ pub struct StyleSharingCandidate { pub style: Arc, pub parent_style: Arc, pub local_name: Atom, - pub class: Option, + // FIXME(pcwalton): Should be a list of atoms instead. + pub class: Option, } impl PartialEq for StyleSharingCandidate { @@ -222,7 +222,7 @@ impl StyleSharingCandidate { style: style, parent_style: parent_style, local_name: element.get_local_name().clone(), - class: element.get_attr(&ns!(""), "class") + class: element.get_attr(&ns!(""), &atom!("class")) .map(|string| string.to_string()), }) } @@ -231,10 +231,12 @@ impl StyleSharingCandidate { if *element.get_local_name() != self.local_name { return false } - match (&self.class, element.get_attr(&ns!(""), "class")) { + + // FIXME(pcwalton): Use `each_class` here instead of slow string comparison. + match (&self.class, element.get_attr(&ns!(""), &atom!("class"))) { (&None, Some(_)) | (&Some(_), None) => return false, - (&Some(ref this_class), Some(element_class)) - if element_class != this_class.as_slice() => { + (&Some(ref this_class), Some(element_class)) if + element_class != this_class.as_slice() => { return false } (&Some(_), Some(_)) | (&None, None) => {} @@ -457,7 +459,8 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { } let ok = { let element = self.as_element(); - element.style_attribute().is_none() && element.get_attr(&ns!(""), "id").is_none() + element.style_attribute().is_none() && + element.get_attr(&ns!(""), &atom!("id")).is_none() }; if !ok { return CannotShare(false) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 03189115659..47a7980d152 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -48,6 +48,7 @@ use std::cmp::{max, min}; use std::fmt; use std::from_str::FromStr; use std::num::Zero; +use string_cache::Atom; use style::{ComputedValues, TElement, TNode, cascade_anonymous, RGBA}; use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto}; use style::computed_values::{LengthOrPercentageOrNone}; @@ -220,7 +221,7 @@ impl ImageFragmentInfo { image_url: Url, local_image_cache: Arc>>) -> ImageFragmentInfo { - fn convert_length(node: &ThreadSafeLayoutNode, name: &str) -> Option { + fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option { let element = node.as_element(); element.get_attr(&ns!(""), name).and_then(|string| { let n: Option = FromStr::from_str(string); @@ -229,8 +230,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, &atom!("width")); + let dom_height = convert_length(node, &atom!("height")); let opaque_node: OpaqueNode = OpaqueNodeMethods::from_thread_safe_layout_node(node); let untrusted_node: UntrustedNodeAddress = opaque_node.to_untrusted_node_address(); @@ -412,7 +413,7 @@ impl TableColumnFragmentInfo { pub fn new(node: &ThreadSafeLayoutNode) -> TableColumnFragmentInfo { let span = { let element = node.as_element(); - element.get_attr(&ns!(""), "span").and_then(|string| { + element.get_attr(&ns!(""), &atom!("span")).and_then(|string| { let n: Option = FromStr::from_str(string); n }) diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 13e11e06c54..336b47476d8 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -28,9 +28,10 @@ extern crate "net" as servo_net; extern crate "msg" as servo_msg; #[phase(plugin, link)] extern crate "util" as servo_util; -extern crate string_cache; + #[phase(plugin)] extern crate string_cache_macros; +extern crate string_cache; extern crate collections; extern crate encoding; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index c39482c1de6..a4b5903da00 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -317,15 +317,14 @@ impl<'ln> TNode<'ln, 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)) }, AnyNamespace => { let element = self.as_element(); @@ -445,13 +444,15 @@ impl<'le> TElement<'le> for LayoutElement<'le> { } #[inline] - fn get_attr(self, namespace: &Namespace, name: &str) -> Option<&'le str> { + fn get_attr(self, namespace: &Namespace, name: &Atom) -> Option<&'le str> { unsafe { self.element.get_attr_val_for_layout(namespace, name) } } #[inline] - fn get_attrs(self, name: &str) -> Vec<&'le str> { - unsafe { self.element.get_attr_vals_for_layout(name) } + fn get_attrs(self, name: &Atom) -> Vec<&'le str> { + unsafe { + self.element.get_attr_vals_for_layout(name) + } } fn get_link(self) -> Option<&'le str> { @@ -462,7 +463,9 @@ impl<'le> TElement<'le> for LayoutElement<'le> { ElementNodeTypeId(HTMLAnchorElementTypeId) | ElementNodeTypeId(HTMLAreaElementTypeId) | ElementNodeTypeId(HTMLLinkElementTypeId) => { - unsafe { self.element.get_attr_val_for_layout(&ns!(""), "href") } + unsafe { + self.element.get_attr_val_for_layout(&ns!(""), &atom!("href")) + } } _ => None, } @@ -476,7 +479,9 @@ impl<'le> TElement<'le> for LayoutElement<'le> { #[inline] fn get_id(self) -> Option { - unsafe { self.element.get_attr_atom_for_layout(&ns!(""), "id") } + unsafe { + self.element.get_attr_atom_for_layout(&ns!(""), &atom!("id")) + } } fn get_disabled_state(self) -> bool { @@ -491,7 +496,7 @@ impl<'le> TElement<'le> 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) } @@ -502,8 +507,8 @@ impl<'le> TElement<'le> for LayoutElement<'le> { unsafe { match self.element.get_classes_for_layout() { None => {} - Some(mut classes) => { - for class in classes { + Some(ref classes) => { + for class in classes.iter() { callback(class) } } @@ -867,8 +872,10 @@ pub struct ThreadSafeLayoutElement<'le> { impl<'le> ThreadSafeLayoutElement<'le> { #[inline] - pub fn get_attr(&self, namespace: &Namespace, name: &str) -> Option<&'le str> { - unsafe { self.element.get_attr_val_for_layout(namespace, name) } + pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> { + unsafe { + self.element.get_attr_val_for_layout(namespace, name) + } } } diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index d54be57b8e0..3e81bb31943 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -17,7 +17,6 @@ use devtools_traits::AttrInfo; use servo_util::str::{DOMString, split_html_space_chars}; use std::cell::{Ref, RefCell}; use std::mem; -use std::slice::Items; use string_cache::{Atom, Namespace}; pub enum AttrSettingType { @@ -51,9 +50,9 @@ impl AttrValue { AtomAttrValue(value) } - pub fn tokens<'a>(&'a self) -> Option> { + 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 } } @@ -215,17 +214,19 @@ impl<'a> AttrHelpers<'a> for JSRef<'a, Attr> { pub trait AttrHelpersForLayout { unsafe fn value_ref_forever(&self) -> &'static str; unsafe fn value_atom_forever(&self) -> Option; - unsafe fn value_tokens_forever(&self) -> Option>; + 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 directly let value = mem::transmute::<&RefCell, &AttrValue>(&self.value); value.as_slice() } + #[inline] unsafe fn value_atom_forever(&self) -> Option { // cast to point to T in RefCell directly let value = mem::transmute::<&RefCell, &AttrValue>(&self.value); @@ -235,15 +236,17 @@ impl AttrHelpersForLayout for Attr { } } - unsafe fn value_tokens_forever(&self) -> Option> { + #[inline] + unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]> { // cast to point to T in RefCell directly let value = mem::transmute::<&RefCell, &AttrValue>(&self.value); 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 7cf193baf0c..2981cbf341a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5451,6 +5451,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 f37a8feb2f6..bbcf3514734 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -123,7 +123,8 @@ impl CollectionFilter for EmbedsFilter { struct LinksFilter; impl CollectionFilter for LinksFilter { fn filter(&self, elem: JSRef, _root: JSRef) -> bool { - (elem.is_htmlanchorelement() || elem.is_htmlareaelement()) && elem.has_attribute("href") + (elem.is_htmlanchorelement() || elem.is_htmlareaelement()) && + elem.has_attribute(&atom!("href")) } } @@ -147,7 +148,7 @@ impl CollectionFilter for ScriptsFilter { struct AnchorsFilter; impl CollectionFilter for AnchorsFilter { fn filter(&self, elem: JSRef, _root: JSRef) -> bool { - elem.is_htmlanchorelement() && elem.has_attribute("href") + elem.is_htmlanchorelement() && elem.has_attribute(&atom!("href")) } } @@ -278,7 +279,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { self.GetElementById(fragid.clone()).or_else(|| { let check_anchor = |&node: &JSRef| { let elem: JSRef = ElementCast::from_ref(node); - elem.get_attribute(ns!(""), "name").root().map_or(false, |attr| { + elem.get_attribute(ns!(""), &atom!("name")).root().map_or(false, |attr| { attr.value().as_slice() == fragid.as_slice() }) }; @@ -785,7 +786,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { } let element: JSRef = ElementCast::to_ref(node).unwrap(); - element.get_attribute(ns!(""), "name").root().map_or(false, |attr| { + element.get_attribute(ns!(""), &atom!("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 59d931dea31..a23e5e49bac 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -21,12 +21,11 @@ use string_cache::Atom; pub struct DOMTokenList { reflector_: Reflector, element: JS, - local_name: &'static str, + local_name: Atom, } impl DOMTokenList { - fn new_inherited(element: JSRef, - local_name: &'static str) -> DOMTokenList { + pub fn new_inherited(element: JSRef, local_name: Atom) -> DOMTokenList { DOMTokenList { reflector_: Reflector::new(), element: JS::from_rooted(element), @@ -34,11 +33,11 @@ impl DOMTokenList { } } - pub fn new(element: JSRef, - local_name: &'static str) -> Temporary { + pub fn new(element: JSRef, local_name: &Atom) -> Temporary { let window = window_from_node(element).root(); - reflect_dom_object(box DOMTokenList::new_inherited(element, local_name), - &Window(*window), DOMTokenListBinding::Wrap) + reflect_dom_object(box DOMTokenList::new_inherited(element, local_name.clone()), + &Window(*window), + DOMTokenListBinding::Wrap) } } @@ -56,7 +55,7 @@ trait PrivateDOMTokenListHelpers { impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> { fn attribute(self) -> Option> { let element = self.element.root(); - element.get_attribute(ns!(""), self.local_name) + element.get_attribute(ns!(""), &self.local_name) } fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible<&'a str> { @@ -79,8 +78,8 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { // http://dom.spec.whatwg.org/#dom-domtokenlist-item fn Item(self, index: u32) -> Option { - 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()) + self.attribute().root().and_then(|attr| attr.value().tokens().and_then(|tokens| { + tokens.get(index as uint).map(|token| token.as_slice().to_string()) })) } @@ -93,9 +92,9 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { // http://dom.spec.whatwg.org/#dom-domtokenlist-contains fn Contains(self, token: DOMString) -> Fallible { self.check_token_exceptions(token.as_slice()).map(|slice| { - self.attribute().root().and_then(|attr| attr.value().tokens().map(|mut tokens| { + self.attribute().root().and_then(|attr| attr.value().tokens().map(|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 6ff62874731..2c1685fb407 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -38,7 +38,6 @@ use std::ascii::StrAsciiExt; use std::cell::{Ref, RefMut, RefCell}; use std::default::Default; use std::mem; -use std::slice::Items; use string_cache::{Atom, Namespace}; use url::UrlParser; @@ -57,6 +56,7 @@ pub struct Element { } impl ElementDerived for EventTarget { + #[inline] fn is_element(&self) -> bool { match *self.type_id() { NodeTargetTypeId(ElementNodeTypeId(_)) => true, @@ -205,24 +205,25 @@ impl Element { } pub trait RawLayoutElementHelpers { - unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &str) -> Option<&'a str>; - unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &str) -> Vec<&'a str>; - unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str) -> Option; - unsafe fn has_class_for_layout(&self, name: &str) -> bool; - unsafe fn get_classes_for_layout<'a>(&'a self) -> Option>; + unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &Atom) + -> Option<&'a str>; + unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &Atom) -> Vec<&'a str>; + unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option; + 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<'a>(&'a self, namespace: &Namespace, name: &str) + unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> { // cast to point to T in RefCell directly let attrs: *const Vec> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS| { let attr = attr.unsafe_get(); - name == (*attr).local_name_atom_forever().as_slice() && - *(*attr).namespace() == *namespace + *name == (*attr).local_name_atom_forever() && + (*attr).namespace() == namespace }).map(|attr| { let attr = attr.unsafe_get(); (*attr).value_ref_forever() @@ -231,12 +232,12 @@ impl RawLayoutElementHelpers for Element { #[inline] #[allow(unrooted_must_root)] - unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &str) -> Vec<&'a str> { + unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &Atom) -> Vec<&'a str> { // cast to point to T in RefCell directly let attrs: *const Vec> = mem::transmute(&self.attrs); (*attrs).iter().filter_map(|attr: &JS| { let attr = attr.unsafe_get(); - if name == (*attr).local_name_atom_forever().as_slice() { + if *name == (*attr).local_name_atom_forever() { Some((*attr).value_ref_forever()) } else { None @@ -246,14 +247,14 @@ 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 { // cast to point to T in RefCell directly let attrs: *const Vec> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS| { let attr = attr.unsafe_get(); - name == (*attr).local_name_atom_forever().as_slice() && - *(*attr).namespace() == *namespace + *name == (*attr).local_name_atom_forever() && + (*attr).namespace() == namespace }).and_then(|attr| { let attr = attr.unsafe_get(); (*attr).value_atom_forever() @@ -262,24 +263,26 @@ 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> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS| { let attr = attr.unsafe_get(); - (*attr).local_name_atom_forever().as_slice() == "class" + (*attr).local_name_atom_forever() == atom!("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(|tokens| { + tokens.iter().any(|atom| atom == name) + }) }.take().unwrap()) } #[inline] #[allow(unrooted_must_root)] - unsafe fn get_classes_for_layout<'a>(&'a self) -> Option> { + unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]> { let attrs: *const Vec> = mem::transmute(&self.attrs); (*attrs).iter().find(|attr: & &JS| { let attr = attr.unsafe_get(); - (*attr).local_name_atom_forever().as_slice() == "class" + (*attr).local_name_atom_forever() == atom!("class") }).and_then(|attr| { let attr = attr.unsafe_get(); (*attr).value_tokens_forever() @@ -293,6 +296,7 @@ pub trait LayoutElementHelpers { impl LayoutElementHelpers for JS { #[allow(unrooted_must_root)] + #[inline] unsafe fn html_element_in_html_document_for_layout(&self) -> bool { if (*self.unsafe_get()).namespace != ns!(HTML) { return false @@ -355,14 +359,16 @@ impl<'a> ElementHelpers<'a> 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) + fn get_attribute(self, namespace: Namespace, local_name: &Atom) -> Option>; - fn get_attributes(self, local_name: &str) + fn get_attributes(self, local_name: &Atom) -> Vec>; - fn set_attribute_from_parser(self, local_name: Atom, - value: DOMString, namespace: Namespace, + fn set_attribute_from_parser(self, + local_name: Atom, + value: DOMString, + namespace: Namespace, prefix: Option); - fn set_attribute(self, name: &str, value: AttrValue); + fn set_attribute(self, name: &Atom, value: AttrValue); fn do_set_attribute(self, local_name: Atom, value: AttrValue, name: Atom, namespace: Namespace, prefix: Option, cb: |JSRef| -> bool); @@ -371,34 +377,33 @@ 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 notify_attribute_removed(self); - fn set_atomic_attribute(self, name: &str, value: DOMString); + fn set_atomic_attribute(self, name: &Atom, 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 set_url_attribute(self, name: &str, value: DOMString); - fn get_string_attribute(self, name: &str) -> 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 set_uint_attribute(self, name: &str, value: u32); + fn has_attribute(self, name: &Atom) -> bool; + fn set_bool_attribute(self, name: &Atom, value: bool); + fn get_url_attribute(self, name: &Atom) -> DOMString; + fn set_url_attribute(self, name: &Atom, value: DOMString); + fn get_string_attribute(self, name: &Atom) -> DOMString; + fn set_string_attribute(self, name: &Atom, value: DOMString); + fn set_tokenlist_attribute(self, name: &Atom, value: DOMString); + fn get_uint_attribute(self, name: &Atom) -> u32; + fn set_uint_attribute(self, name: &Atom, value: u32); } impl<'a> AttributeHandlers for JSRef<'a, Element> { - fn get_attribute(self, namespace: Namespace, local_name: &str) -> Option> { + fn get_attribute(self, namespace: Namespace, local_name: &Atom) -> Option> { self.get_attributes(local_name).iter().map(|attr| attr.root()) .find(|attr| *attr.namespace() == namespace) .map(|x| Temporary::from_rooted(*x)) } - fn get_attributes(self, local_name: &str) -> Vec> { - let local_name = Atom::from_slice(local_name); + fn get_attributes(self, local_name: &Atom) -> Vec> { self.attrs.borrow().iter().map(|attr| attr.root()).filter_map(|attr| { - if *attr.local_name() == local_name { + if *attr.local_name() == *local_name { Some(Temporary::from_rooted(*attr)) } else { None @@ -406,8 +411,10 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { }).collect() } - fn set_attribute_from_parser(self, local_name: Atom, - value: DOMString, namespace: Namespace, + fn set_attribute_from_parser(self, + local_name: Atom, + value: DOMString, + namespace: Namespace, prefix: Option) { let name = match prefix { None => local_name.clone(), @@ -420,16 +427,15 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.do_set_attribute(local_name, value, name, namespace, prefix, |_| false) } - fn set_attribute(self, name: &str, value: AttrValue) { - assert!(name == name.to_ascii_lower().as_slice()); - assert!(!name.contains(":")); + fn set_attribute(self, name: &Atom, value: AttrValue) { + assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice()); + assert!(!name.as_slice().contains(":")); let node: JSRef = NodeCast::from_ref(self); node.wait_until_safe_to_modify_dom(); - let name = Atom::from_slice(name); self.do_set_attribute(name.clone(), value, name.clone(), - ns!(""), None, |attr| *attr.local_name() == name); + ns!(""), None, |attr| *attr.local_name() == *name); } fn do_set_attribute(self, local_name: Atom, value: AttrValue, @@ -507,41 +513,40 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { } } - fn has_class(&self, name: &str) -> bool { - self.get_attribute(ns!(""), "class").root().map(|attr| { - attr.value().tokens().map(|mut tokens| { - tokens.any(|atom| atom.as_slice() == name) + fn has_class(&self, name: &Atom) -> bool { + self.get_attribute(ns!(""), &atom!("class")).root().map(|attr| { + attr.value().tokens().map(|tokens| { + tokens.iter().any(|atom| atom == name) }).unwrap_or(false) }).unwrap_or(false) } - fn set_atomic_attribute(self, name: &str, value: DOMString) { - assert!(name == name.to_ascii_lower().as_slice()); + fn set_atomic_attribute(self, name: &Atom, value: DOMString) { + assert!(name.as_slice().eq_ignore_ascii_case(name.as_slice())); let value = AttrValue::from_atomic(value); self.set_attribute(name, value); } - fn has_attribute(self, name: &str) -> bool { - let name = match self.html_element_in_html_document() { - true => Atom::from_slice(name.to_ascii_lower().as_slice()), - false => Atom::from_slice(name) - }; + fn has_attribute(self, name: &Atom) -> bool { + assert!(name.as_slice().chars().all(|ch| { + !ch.is_ascii() || ch.to_ascii().to_lowercase() == ch.to_ascii() + })); self.attrs.borrow().iter().map(|attr| attr.root()).any(|attr| { - *attr.local_name() == name && *attr.namespace() == ns!("") + *attr.local_name() == *name && *attr.namespace() == ns!("") }) } - fn set_bool_attribute(self, name: &str, value: bool) { + fn set_bool_attribute(self, name: &Atom, value: bool) { if self.has_attribute(name) == value { return; } if value { self.set_string_attribute(name, String::new()); } else { - self.remove_attribute(ns!(""), name); + self.remove_attribute(ns!(""), name.as_slice()); } } - fn get_url_attribute(self, name: &str) -> DOMString { - assert!(name == name.to_ascii_lower().as_slice()); + fn get_url_attribute(self, name: &Atom) -> DOMString { + assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice()); if !self.has_attribute(name) { return "".to_string(); } @@ -555,29 +560,30 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { Err(_) => "".to_string() } } - fn set_url_attribute(self, name: &str, value: DOMString) { + fn set_url_attribute(self, name: &Atom, value: DOMString) { 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(ns!(""), name) { Some(x) => x.root().Value(), None => "".to_string() } } - fn set_string_attribute(self, name: &str, value: DOMString) { - assert!(name == name.to_ascii_lower().as_slice()); + fn set_string_attribute(self, name: &Atom, value: DOMString) { + assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice()); self.set_attribute(name, StringAttrValue(value)); } - fn set_tokenlist_attribute(self, name: &str, value: DOMString) { - assert!(name == name.to_ascii_lower().as_slice()); + fn set_tokenlist_attribute(self, name: &Atom, value: DOMString) { + assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice()); 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().chars().all(|ch| { + !ch.is_ascii() || ch.to_ascii().to_lowercase() == ch.to_ascii() + })); let attribute = self.get_attribute(ns!(""), name).root(); match attribute { Some(attribute) => { @@ -589,8 +595,8 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { None => 0, } } - fn set_uint_attribute(self, name: &str, value: u32) { - assert!(name == name.to_ascii_lower().as_slice()); + fn set_uint_attribute(self, name: &Atom, value: u32) { + assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice()); self.set_attribute(name, UIntAttrValue(value.to_string(), value)); } } @@ -628,28 +634,28 @@ 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(&atom!("id")) } // http://dom.spec.whatwg.org/#dom-element-id fn SetId(self, id: DOMString) { - self.set_atomic_attribute("id", id); + self.set_atomic_attribute(&atom!("id"), id); } // http://dom.spec.whatwg.org/#dom-element-classname fn ClassName(self) -> DOMString { - self.get_string_attribute("class") + self.get_string_attribute(&atom!("class")) } // http://dom.spec.whatwg.org/#dom-element-classname fn SetClassName(self, class: DOMString) { - self.set_tokenlist_attribute("class", class); + self.set_tokenlist_attribute(&atom!("class"), class); } // http://dom.spec.whatwg.org/#dom-element-classlist fn ClassList(self) -> Temporary { if self.class_list.get().is_none() { - let class_list = DOMTokenList::new(self, "class"); + let class_list = DOMTokenList::new(self, &atom!("class")); self.class_list.assign(Some(class_list)); } self.class_list.get().unwrap() @@ -676,7 +682,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } else { name }; - self.get_attribute(ns!(""), name.as_slice()).root() + self.get_attribute(ns!(""), &Atom::from_slice(name.as_slice())).root() .map(|s| s.Value()) } @@ -685,7 +691,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { namespace: Option, local_name: DOMString) -> Option { let namespace = namespace::from_domstring(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.Value()) } @@ -808,9 +814,17 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } // http://dom.spec.whatwg.org/#dom-element-hasattribute - fn HasAttribute(self, - name: DOMString) -> bool { - self.has_attribute(name.as_slice()) + fn HasAttribute(self, name: DOMString) -> bool { + // Step 1. + if self.html_element_in_html_document() { + // TODO(pcwalton): Small string optimization here. + return self.has_attribute(&Atom::from_slice(name.as_slice() + .to_ascii_lower() + .as_slice())) + } + + // Step 2. + self.has_attribute(&Atom::from_slice(name.as_slice())) } // http://dom.spec.whatwg.org/#dom-element-hasattributens @@ -997,7 +1011,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { if !tree_in_doc { return; } - match self.get_attribute(ns!(""), "id").root() { + match self.get_attribute(ns!(""), &atom!("id")).root() { Some(attr) => { let doc = document_from_node(*self).root(); let value = attr.Value(); @@ -1018,7 +1032,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { if !tree_in_doc { return; } - match self.get_attribute(ns!(""), "id").root() { + match self.get_attribute(ns!(""), &atom!("id")).root() { Some(attr) => { let doc = document_from_node(*self).root(); let value = attr.Value(); @@ -1033,12 +1047,12 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { } impl<'a> style::TElement<'a> for JSRef<'a, Element> { - fn get_attr(self, namespace: &Namespace, attr: &str) -> Option<&'a str> { + fn get_attr(self, namespace: &Namespace, attr: &Atom) -> Option<&'a str> { self.get_attribute(namespace.clone(), attr).root().map(|attr| { unsafe { mem::transmute(attr.value().as_slice()) } }) } - fn get_attrs(self, attr: &str) -> Vec<&'a str> { + fn get_attrs(self, attr: &Atom) -> Vec<&'a str> { self.get_attributes(attr).iter().map(|attr| attr.root()).map(|attr| { unsafe { mem::transmute(attr.value().as_slice()) } }).collect() @@ -1051,7 +1065,7 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> { // selector-link ElementNodeTypeId(HTMLAnchorElementTypeId) | ElementNodeTypeId(HTMLAreaElementTypeId) | - ElementNodeTypeId(HTMLLinkElementTypeId) => self.get_attr(&ns!(""), "href"), + ElementNodeTypeId(HTMLLinkElementTypeId) => self.get_attr(&ns!(""), &atom!("href")), _ => None, } } @@ -1078,7 +1092,7 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> { node.get_hover_state() } fn get_id(self) -> Option { - self.get_attribute(ns!(""), "id").map(|attr| { + self.get_attribute(ns!(""), &atom!("id")).map(|attr| { let attr = attr.root(); match *attr.value() { AtomAttrValue(ref val) => val.clone(), @@ -1094,23 +1108,23 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> { let node: JSRef = NodeCast::from_ref(self); node.get_enabled_state() } - fn has_class(self, name: &str) -> bool { + fn has_class(self, name: &Atom) -> bool { // FIXME(zwarich): Remove this when UFCS lands and there is a better way // of disambiguating methods. - fn has_class(this: T, name: &str) -> bool { + fn has_class(this: T, name: &Atom) -> bool { this.has_class(name) } has_class(self, name) } fn each_class(self, callback: |&Atom|) { - match self.get_attribute(ns!(""), "class").root() { + match self.get_attribute(ns!(""), &atom!("class")).root() { None => {} - Some(attr) => { - match attr.deref().value().tokens() { + Some(ref attr) => { + match attr.value().tokens() { None => {} - Some(mut tokens) => { - for token in tokens { + Some(tokens) => { + for token in tokens.iter() { callback(token) } } diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs index 19492ef6264..aad63f98ba8 100644 --- a/components/script/dom/htmlanchorelement.rs +++ b/components/script/dom/htmlanchorelement.rs @@ -56,7 +56,7 @@ impl<'a> PrivateHTMLAnchorElementHelpers for JSRef<'a, HTMLAnchorElement> { fn handle_event_impl(self, event: JSRef) { if "click" == event.Type().as_slice() && !event.DefaultPrevented() { let element: JSRef = ElementCast::from_ref(self); - let attr = element.get_attribute(ns!(""), "href").root(); + let attr = element.get_attribute(ns!(""), &atom!("href")).root(); match attr { Some(ref href) => { let value = href.Value(); diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index af4dec6dcb3..ec2377297f3 100644 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -62,7 +62,7 @@ impl<'a> HTMLButtonElementMethods for JSRef<'a, HTMLButtonElement> { // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type fn Type(self) -> DOMString { let elem: JSRef = ElementCast::from_ref(self); - let ty = elem.get_string_attribute("type").into_ascii_lower(); + let ty = elem.get_string_attribute(&atom!("type")).into_ascii_lower(); // https://html.spec.whatwg.org/multipage/forms.html#attr-button-type match ty.as_slice() { "reset" | "button" | "menu" => ty, diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index ac5a5d7ded5..69a96a086fc 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -68,7 +68,7 @@ impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> { fn SetWidth(self, width: u32) { let elem: JSRef = ElementCast::from_ref(self); - elem.set_uint_attribute("width", width) + elem.set_uint_attribute(&atom!("width"), width) } fn Height(self) -> u32 { @@ -77,7 +77,7 @@ impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> { fn SetHeight(self, height: u32) { let elem: JSRef = ElementCast::from_ref(self); - elem.set_uint_attribute("height", height) + elem.set_uint_attribute(&atom!("height"), height) } fn GetContext(self, id: DOMString) -> Option> { diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index 035ee8287a4..abd8b6857aa 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -139,15 +139,17 @@ impl HTMLCollection { -> Temporary { #[jstraceable] struct ClassNameFilter { - classes: Vec + classes: Vec } impl CollectionFilter for ClassNameFilter { fn filter(&self, elem: JSRef, _root: JSRef) -> 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) } @@ -216,8 +218,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(&atom!("name")) == key || + elem.get_string_attribute(&atom!("id")) == key }) .map(|maybe_elem| Temporary::from_rooted(*maybe_elem)), Live(ref root, ref filter) => { let root = root.root(); @@ -230,8 +232,8 @@ impl<'a> HTMLCollectionMethods for JSRef<'a, HTMLCollection> { } }) .find(|elem| { - elem.get_string_attribute("name") == key || - elem.get_string_attribute("id") == key }) + elem.get_string_attribute(&atom!("name")) == key || + elem.get_string_attribute(&atom!("id")) == key }) .map(|maybe_elem| Temporary::from_rooted(maybe_elem)) } } diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 363e90fa596..ed18eb109f2 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -28,6 +28,7 @@ use std::ascii::OwnedStrAsciiExt; use std::str::StrSlice; use url::UrlParser; use url::form_urlencoded::serialize; +use string_cache::Atom; #[jstraceable] #[must_root] @@ -349,14 +350,24 @@ impl<'a> FormSubmitter<'a> { fn action(&self) -> DOMString { match *self { FormElement(form) => form.Action(), - InputElement(input_element) => input_element.get_form_attribute("formaction", |i| i.FormAction(), |f| f.Action()) + InputElement(input_element) => { + // FIXME(pcwalton): Make this a static atom. + input_element.get_form_attribute(&Atom::from_slice("formaction"), + |i| i.FormAction(), + |f| f.Action()) + } } } fn enctype(&self) -> FormEncType { let attr = match *self { FormElement(form) => form.Enctype(), - InputElement(input_element) => input_element.get_form_attribute("formenctype", |i| i.FormEnctype(), |f| f.Enctype()) + InputElement(input_element) => { + // FIXME(pcwalton): Make this a static atom. + input_element.get_form_attribute(&Atom::from_slice("formenctype"), + |i| i.FormEnctype(), + |f| f.Enctype()) + } }; match attr.as_slice() { "multipart/form-data" => FormDataEncoded, @@ -370,7 +381,12 @@ impl<'a> FormSubmitter<'a> { fn method(&self) -> FormMethod { let attr = match *self { FormElement(form) => form.Method(), - InputElement(input_element) => input_element.get_form_attribute("formmethod", |i| i.FormMethod(), |f| f.Method()) + InputElement(input_element) => { + // FIXME(pcwalton): Make this a static atom. + input_element.get_form_attribute(&Atom::from_slice("formmethod"), + |i| i.FormMethod(), + |f| f.Method()) + } }; match attr.as_slice() { "dialog" => FormDialog, @@ -382,14 +398,20 @@ impl<'a> FormSubmitter<'a> { fn target(&self) -> DOMString { match *self { FormElement(form) => form.Target(), - InputElement(input_element) => input_element.get_form_attribute("formtarget", |i| i.FormTarget(), |f| f.Target()) + InputElement(input_element) => { + // FIXME(pcwalton): Make this a static atom. + input_element.get_form_attribute(&Atom::from_slice("formtarget"), + |i| i.FormTarget(), + |f| f.Target()) + } } } } pub trait FormOwner<'a> : Copy { fn form_owner(self) -> Option>; - fn get_form_attribute(self, attr: &str, + fn get_form_attribute(self, + attr: &Atom, input: |Self| -> DOMString, owner: |JSRef| -> DOMString) -> DOMString { if self.to_element().has_attribute(attr) { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 77bbfcf9013..108fbbe4dc2 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -87,7 +87,7 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { fn get_url(self) -> Option { let element: JSRef = ElementCast::from_ref(self); - element.get_attribute(ns!(""), "src").root().and_then(|src| { + element.get_attribute(ns!(""), &atom!("src")).root().and_then(|src| { let url = src.value(); if url.as_slice().is_empty() { None @@ -150,22 +150,22 @@ impl HTMLIFrameElement { impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> { fn Src(self) -> DOMString { let element: JSRef = ElementCast::from_ref(self); - element.get_string_attribute("src") + element.get_string_attribute(&atom!("src")) } fn SetSrc(self, src: DOMString) { let element: JSRef = ElementCast::from_ref(self); - element.set_url_attribute("src", src) + element.set_url_attribute(&atom!("src"), src) } fn Sandbox(self) -> DOMString { let element: JSRef = ElementCast::from_ref(self); - element.get_string_attribute("sandbox") + element.get_string_attribute(&atom!("sandbox")) } fn SetSandbox(self, sandbox: DOMString) { let element: JSRef = ElementCast::from_ref(self); - element.set_string_attribute("sandbox", sandbox); + element.set_string_attribute(&atom!("sandbox"), sandbox); } fn GetContentWindow(self) -> Option> { diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index d8a4f9d67f6..c706fcfcd7e 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -113,7 +113,7 @@ impl<'a> HTMLImageElementMethods for JSRef<'a, HTMLImageElement> { fn SetIsMap(self, is_map: bool) { let element: JSRef = ElementCast::from_ref(self); - element.set_string_attribute("ismap", is_map.to_string()) + element.set_string_attribute(&atom!("ismap"), is_map.to_string()) } fn Width(self) -> u32 { @@ -124,7 +124,7 @@ impl<'a> HTMLImageElementMethods for JSRef<'a, HTMLImageElement> { fn SetWidth(self, width: u32) { let elem: JSRef = ElementCast::from_ref(self); - elem.set_uint_attribute("width", width) + elem.set_uint_attribute(&atom!("width"), width) } fn Height(self) -> u32 { @@ -135,7 +135,7 @@ impl<'a> HTMLImageElementMethods for JSRef<'a, HTMLImageElement> { fn SetHeight(self, height: u32) { let elem: JSRef = ElementCast::from_ref(self); - elem.set_uint_attribute("height", height) + elem.set_uint_attribute(&atom!("height"), height) } make_getter!(Name) @@ -188,7 +188,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLImageElement> { _ => (), } - if "src" == name.as_slice() { + if atom!("src") == *name { self.update_image(None); } } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 52cb51eeaff..b256dab7f3d 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -232,7 +232,7 @@ impl<'a> HTMLInputElementHelpers for JSRef<'a, HTMLInputElement> { fn get_radio_group(self) -> Option { //TODO: determine form owner let elem: JSRef = ElementCast::from_ref(self); - elem.get_attribute(ns!(""), "name") + elem.get_attribute(ns!(""), &atom!("name")) .root() .map(|name| name.Value()) } @@ -409,7 +409,7 @@ impl<'a> FormOwner<'a> for JSRef<'a, HTMLInputElement> { fn form_owner(self) -> Option> { // https://html.spec.whatwg.org/multipage/forms.html#reset-the-form-owner let elem: JSRef = ElementCast::from_ref(self); - let owner = elem.get_string_attribute("form"); + let owner = elem.get_string_attribute(&atom!("form")); if !owner.is_empty() { let doc = document_from_node(self).root(); let owner = doc.GetElementById(owner).root(); diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 1c641562d81..13c4bf3b513 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -48,7 +48,7 @@ impl HTMLLinkElement { } } -fn get_attr(element: JSRef, name: &str) -> Option { +fn get_attr(element: JSRef, name: &Atom) -> Option { let elem = element.get_attribute(ns!(""), name).root(); elem.map(|e| e.value().as_slice().to_string()) } @@ -76,7 +76,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { } let element: JSRef = ElementCast::from_ref(*self); - let rel = get_attr(element, "rel"); + let rel = get_attr(element, &atom!("rel")); match (rel, name.as_slice()) { (ref rel, "href") => { @@ -97,8 +97,8 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { if tree_in_doc { let element: JSRef = ElementCast::from_ref(*self); - let rel = get_attr(element, "rel"); - let href = get_attr(element, "href"); + let rel = get_attr(element, &atom!("rel")); + let href = get_attr(element, &atom!("href")); match (rel, href) { (ref rel, Some(ref href)) if is_stylesheet(rel) => { diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index d7a073150ef..a7de41d3599 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 = ElementCast::from_ref(*self); // TODO: support other values - match (elem.get_attribute(ns!(""), "type").map(|x| x.root().Value()), - elem.get_attribute(ns!(""), "data").map(|x| x.root().Value())) { + match (elem.get_attribute(ns!(""), &atom!("type")).map(|x| x.root().Value()), + elem.get_attribute(ns!(""), &atom!("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/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index e44011bc2ce..1493e5cecef 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -74,7 +74,7 @@ impl<'a> HTMLOptionElementMethods for JSRef<'a, HTMLOptionElement> { // http://www.whatwg.org/html/#dom-option-disabled fn SetDisabled(self, disabled: bool) { let elem: JSRef = ElementCast::from_ref(self); - elem.set_bool_attribute("disabled", disabled) + elem.set_bool_attribute(&atom!("disabled"), disabled) } // http://www.whatwg.org/html/#dom-option-text diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 138c7ea8679..e4c268d5713 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -75,7 +75,7 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { fn is_javascript(self) -> bool { let element: JSRef = ElementCast::from_ref(self); - match element.get_attribute(ns!(""), "type").root().map(|s| s.Value()) { + match element.get_attribute(ns!(""), &atom!("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 +87,9 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { }, None => { debug!("no script type"); - match element.get_attribute(ns!(""), "language").root().map(|s| s.Value()) { + match element.get_attribute(ns!(""), &atom!("language")) + .root() + .map(|s| s.Value()) { Some(ref s) if s.is_empty() => { debug!("script language empty, inferring js"); true @@ -109,7 +111,7 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { impl<'a> HTMLScriptElementMethods for JSRef<'a, HTMLScriptElement> { fn Src(self) -> DOMString { let element: JSRef = ElementCast::from_ref(self); - element.get_url_attribute("src") + element.get_url_attribute(&atom!("src")) } // http://www.whatwg.org/html/#dom-script-text diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index d825bf1f3a1..011254600d3 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -67,7 +67,7 @@ impl<'a> HTMLSelectElementMethods for JSRef<'a, HTMLSelectElement> { // https://html.spec.whatwg.org/multipage/forms.html#dom-select-type fn Type(self) -> DOMString { let elem: JSRef = ElementCast::from_ref(self); - if elem.has_attribute("multiple") { + if elem.has_attribute(&atom!("multiple")) { "select-multiple".to_string() } else { "select-one".to_string() diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index b4b0d4d2ef7..b0aba98c7d6 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -11,7 +11,7 @@ macro_rules! make_getter( #[allow(unused_imports)] use std::ascii::StrAsciiExt; let element: JSRef = ElementCast::from_ref(self); - element.get_string_attribute($htmlname) + element.get_string_attribute(&Atom::from_slice($htmlname.to_ascii_lower().as_slice())) } ); ($attr:ident) => { @@ -28,7 +28,8 @@ macro_rules! make_bool_getter( #[allow(unused_imports)] use std::ascii::StrAsciiExt; let element: JSRef = ElementCast::from_ref(self); - element.has_attribute($htmlname) + // FIXME(pcwalton): Do this at compile time, not runtime. + element.has_attribute(&Atom::from_slice($htmlname)) } ); ($attr:ident) => { @@ -45,7 +46,8 @@ macro_rules! make_uint_getter( #[allow(unused_imports)] use std::ascii::StrAsciiExt; let element: JSRef = ElementCast::from_ref(self); - element.get_uint_attribute($htmlname) + // FIXME(pcwalton): Do this at compile time, not runtime. + element.get_uint_attribute(&Atom::from_slice($htmlname)) } ); ($attr:ident) => { @@ -62,10 +64,12 @@ macro_rules! make_url_getter( #[allow(unused_imports)] use std::ascii::StrAsciiExt; let element: JSRef = ElementCast::from_ref(self); - element.get_url_attribute($htmlname) + // FIXME(pcwalton): Do this at compile time, not runtime. + element.get_url_attribute(&Atom::from_slice($htmlname)) } ); ($attr:ident) => { + // FIXME(pcwalton): Do this at compile time, not runtime. make_url_getter!($attr, stringify!($attr).to_ascii_lower().as_slice()) } ) @@ -79,7 +83,7 @@ macro_rules! make_url_or_base_getter( #[allow(unused_imports)] use std::ascii::StrAsciiExt; let element: JSRef = ElementCast::from_ref(self); - let url = element.get_url_attribute($htmlname); + let url = element.get_url_attribute(&Atom::from_slice($htmlname)); match url.as_slice() { "" => { let window = window_from_node(self).root(); @@ -103,7 +107,8 @@ macro_rules! make_enumerated_getter( #[allow(unused_imports)] use std::ascii::StrAsciiExt; let element: JSRef = ElementCast::from_ref(self); - let val = element.get_string_attribute($htmlname).into_ascii_lower(); + let val = element.get_string_attribute(&Atom::from_slice($htmlname)) + .into_ascii_lower(); // https://html.spec.whatwg.org/multipage/forms.html#attr-fs-method match val.as_slice() { $($choices)|+ => val, @@ -125,7 +130,8 @@ macro_rules! make_setter( use dom::element::{Element, AttributeHandlers}; use dom::bindings::codegen::InheritTypes::ElementCast; let element: JSRef = ElementCast::from_ref(self); - element.set_string_attribute($htmlname, value) + // FIXME(pcwalton): Do this at compile time, not at runtime. + element.set_string_attribute(&Atom::from_slice($htmlname), value) } ); ) @@ -137,7 +143,8 @@ macro_rules! make_bool_setter( use dom::element::{Element, AttributeHandlers}; use dom::bindings::codegen::InheritTypes::ElementCast; let element: JSRef = ElementCast::from_ref(self); - element.set_bool_attribute($htmlname, value) + // FIXME(pcwalton): Do this at compile time, not at runtime. + element.set_bool_attribute(&Atom::from_slice($htmlname), value) } ); ) @@ -149,7 +156,8 @@ macro_rules! make_uint_setter( use dom::element::{Element, AttributeHandlers}; use dom::bindings::codegen::InheritTypes::ElementCast; let element: JSRef = ElementCast::from_ref(self); - element.set_uint_attribute($htmlname, value) + // FIXME(pcwalton): Do this at compile time, not at runtime. + element.set_uint_attribute(&Atom::from_slice($htmlname), value) } ); ) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 2716c56dc5c..dc6351c9954 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -919,16 +919,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 } @@ -1581,6 +1584,7 @@ impl Node { } } + #[inline] pub unsafe fn unsafe_get_flags(&self) -> *const NodeFlags { mem::transmute(&self.flags) } @@ -2221,9 +2225,9 @@ impl<'a> style::TNode<'a, 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 { @@ -2294,7 +2298,7 @@ impl<'a> DisabledStateHelpers for JSRef<'a, Node> { fn check_disabled_attribute(self) { let elem: JSRef<'a, Element> = ElementCast::to_ref(self).unwrap(); - let has_disabled_attrib = elem.has_attribute("disabled"); + let has_disabled_attrib = elem.has_attribute(&atom!("disabled")); self.set_disabled_state(has_disabled_attrib); self.set_enabled_state(!has_disabled_attrib); } diff --git a/components/script/html/hubbub_html_parser.rs b/components/script/html/hubbub_html_parser.rs index 27f37984517..490e35ff655 100644 --- a/components/script/html/hubbub_html_parser.rs +++ b/components/script/html/hubbub_html_parser.rs @@ -481,7 +481,7 @@ pub fn parse_html(page: &Page, }; let script_element: JSRef = ElementCast::from_ref(script); - match script_element.get_attribute(ns!(""), "src").root() { + match script_element.get_attribute(ns!(""), &atom!("src")).root() { Some(src) => { debug!("found script: {:s}", src.Value()); let mut url_parser = UrlParser::new(); diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index cdd4e0ce48b..f0ab29d7148 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -35,3 +35,4 @@ git = "https://github.com/servo/string-cache" [dependencies.string_cache_macros] git = "https://github.com/servo/string-cache" + diff --git a/components/style/lib.rs b/components/style/lib.rs index e9e3ed27cee..6655613e74a 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -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; diff --git a/components/style/node.rs b/components/style/node.rs index 8fc74d5738c..3dbde03cd97 100644 --- a/components/style/node.rs +++ b/components/style/node.rs @@ -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; fn first_child(self) -> Option; @@ -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; 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 39e0fb73e5f..10447d0c6fa 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -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) diff --git a/components/style/selectors.rs b/components/style/selectors.rs index 6c783e70349..8cd5508326a 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -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, 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,