diff --git a/src/components/layout/wrapper.rs b/src/components/layout/wrapper.rs index adf0151749c..b0ecbbcd2fd 100644 --- a/src/components/layout/wrapper.rs +++ b/src/components/layout/wrapper.rs @@ -393,6 +393,11 @@ impl<'le> TElement for LayoutElement<'le> { self.element.node.get_hover_state_for_layout() } } + + #[inline] + fn get_id(&self) -> Option { + unsafe { self.element.get_attr_atom_for_layout(&namespace::Null, "id") } + } } fn get_content(content_list: &content::T) -> String { diff --git a/src/components/script/dom/attr.rs b/src/components/script/dom/attr.rs index f58631176f1..0e499ebf477 100644 --- a/src/components/script/dom/attr.rs +++ b/src/components/script/dom/attr.rs @@ -167,6 +167,7 @@ impl<'a> AttrMethods for JSRef<'a, Attr> { pub trait AttrHelpersForLayout { unsafe fn value_ref_forever(&self) -> &'static str; + unsafe fn value_atom_forever(&self) -> Option; } impl AttrHelpersForLayout for Attr { @@ -175,4 +176,13 @@ impl AttrHelpersForLayout for Attr { let value = mem::transmute::<&RefCell, &AttrValue>(self.value.deref()); value.as_slice() } + + unsafe fn value_atom_forever(&self) -> Option { + // cast to point to T in RefCell directly + let value = mem::transmute::<&RefCell, &AttrValue>(self.value.deref()); + match *value { + AtomAttrValue(ref val) => Some(val.clone()), + _ => None, + } + } } diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 6fc0ba1b4c0..afc176b8a26 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -6,7 +6,7 @@ use cssparser::tokenize; use dom::attr::{Attr, ReplacedAttr, FirstSetAttr, AttrHelpersForLayout}; -use dom::attr::{AttrValue, StringAttrValue, UIntAttrValue}; +use dom::attr::{AttrValue, StringAttrValue, UIntAttrValue, AtomAttrValue}; use dom::attrlist::AttrList; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::ElementBinding; @@ -168,6 +168,7 @@ 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; } impl RawLayoutElementHelpers for Element { @@ -184,6 +185,20 @@ impl RawLayoutElementHelpers for Element { (*attr).value_ref_forever() }) } + + #[inline] + unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str) + -> Option { + // cast to point to T in RefCell directly + let attrs: *Vec> = mem::transmute(&self.attrs); + (*attrs).iter().find(|attr: & &JS| { + let attr = attr.unsafe_get(); + name == (*attr).local_name.as_slice() && (*attr).namespace == *namespace + }).and_then(|attr| { + let attr = attr.unsafe_get(); + (*attr).value_atom_forever() + }) + } } pub trait LayoutElementHelpers { @@ -901,4 +916,13 @@ impl<'a> style::TElement for JSRef<'a, Element> { let node: &JSRef = NodeCast::from_ref(self); node.get_hover_state() } + fn get_id<'a>(&self) -> Option { + self.get_attribute(namespace::Null, "id").map(|attr| { + let attr = attr.root(); + match *attr.value() { + AtomAttrValue(ref val) => val.clone(), + _ => fail!("`id` attribute should be AtomAttrValue"), + } + }) + } } diff --git a/src/components/style/node.rs b/src/components/style/node.rs index 5d00d34c746..62c588dffd4 100644 --- a/src/components/style/node.rs +++ b/src/components/style/node.rs @@ -26,5 +26,6 @@ pub trait TElement { fn get_local_name<'a>(&'a self) -> &'a Atom; fn get_namespace<'a>(&'a self) -> &'a Namespace; fn get_hover_state(&self) -> bool; + fn get_id(&self) -> Option; } diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs index eeff8b3c60e..3b6de24c1c5 100644 --- a/src/components/style/selector_matching.rs +++ b/src/components/style/selector_matching.rs @@ -267,7 +267,7 @@ impl SelectorMap { match *ss { // TODO(pradeep): Implement case-sensitivity based on the document type and quirks // mode. - IDSelector(ref id) => return Some(id.clone()), + IDSelector(ref id) => return Some(id.as_slice().clone().to_string()), _ => {} } } @@ -691,9 +691,8 @@ fn matches_simple_selector { *shareable = false; let element = element.as_element(); - element.get_attr(&namespace::Null, "id") - .map_or(false, |attr| { - attr == id.as_slice() + element.get_id().map_or(false, |attr| { + attr == *id }) } // TODO: cache and intern class names on elements. diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs index 951f85b8e20..8eadd371086 100644 --- a/src/components/style/selectors.rs +++ b/src/components/style/selectors.rs @@ -10,6 +10,7 @@ use sync::Arc; use cssparser::ast::*; use cssparser::parse_nth; +use servo_util::atom::Atom; use servo_util::namespace::Namespace; use servo_util::namespace; @@ -56,7 +57,7 @@ pub enum Combinator { #[deriving(PartialEq, Clone)] pub enum SimpleSelector { - IDSelector(String), + IDSelector(Atom), ClassSelector(String), LocalNameSelector(String), NamespaceSelector(Namespace), @@ -306,7 +307,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_ -> SimpleSelectorParseResult { match iter.peek() { Some(&IDHash(_)) => match iter.next() { - Some(IDHash(id)) => SimpleSelectorResult(IDSelector(id)), + Some(IDHash(id)) => SimpleSelectorResult(IDSelector(Atom::from_slice(id.as_slice()))), _ => fail!("Implementation error, this should not happen."), }, Some(&Delim('.')) => { @@ -572,6 +573,7 @@ fn skip_whitespace(iter: &mut Iter) -> bool { mod tests { use sync::Arc; use cssparser; + use servo_util::atom::Atom; use servo_util::namespace; use namespaces::NamespaceMap; use super::*; @@ -611,7 +613,7 @@ mod tests { }))) assert!(parse("#bar") == Some(vec!(Selector{ compound_selectors: Arc::new(CompoundSelector { - simple_selectors: vec!(IDSelector("bar".to_string())), + simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))), next: None, }), pseudo_element: None, @@ -621,7 +623,7 @@ mod tests { compound_selectors: Arc::new(CompoundSelector { simple_selectors: vec!(LocalNameSelector("e".to_string()), ClassSelector("foo".to_string()), - IDSelector("bar".to_string())), + IDSelector(Atom::from_slice("bar"))), next: None, }), pseudo_element: None, @@ -629,7 +631,7 @@ mod tests { }))) assert!(parse("e.foo #bar") == Some(vec!(Selector{ compound_selectors: Arc::new(CompoundSelector { - simple_selectors: vec!(IDSelector("bar".to_string())), + simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))), next: Some((box CompoundSelector { simple_selectors: vec!(LocalNameSelector("e".to_string()), ClassSelector("foo".to_string())),