script: Use atom comparison in more places, especially for attributes.

75% improvement in style recalc for Guardians of the Galaxy.
This commit is contained in:
Patrick Walton 2014-09-12 13:28:37 -07:00
parent 61642d64b5
commit 874db26104
32 changed files with 300 additions and 147 deletions

6
Cargo.lock generated
View file

@ -265,6 +265,8 @@ dependencies = [
"net 0.0.1", "net 0.0.1",
"script 0.0.1", "script 0.0.1",
"script_traits 0.0.1", "script_traits 0.0.1",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#37a5869d4130bf75e2f082bab54767d56d4ba63a)",
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#37a5869d4130bf75e2f082bab54767d56d4ba63a)",
"style 0.0.1", "style 0.0.1",
"url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)", "url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)",
"util 0.0.1", "util 0.0.1",
@ -374,6 +376,8 @@ dependencies = [
"msg 0.0.1", "msg 0.0.1",
"net 0.0.1", "net 0.0.1",
"script_traits 0.0.1", "script_traits 0.0.1",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#37a5869d4130bf75e2f082bab54767d56d4ba63a)",
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#37a5869d4130bf75e2f082bab54767d56d4ba63a)",
"style 0.0.1", "style 0.0.1",
"url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)", "url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)",
"util 0.0.1", "util 0.0.1",
@ -431,6 +435,8 @@ dependencies = [
"encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#12b6610adff6eddc060691888c36017cd3ad57f7)", "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#12b6610adff6eddc060691888c36017cd3ad57f7)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#2982b770db6e5e3270305e0fd6b8068f6f80a489)", "geom 0.1.0 (git+https://github.com/servo/rust-geom#2982b770db6e5e3270305e0fd6b8068f6f80a489)",
"macros 0.0.1", "macros 0.0.1",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#37a5869d4130bf75e2f082bab54767d56d4ba63a)",
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#37a5869d4130bf75e2f082bab54767d56d4ba63a)",
"url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)", "url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)",
"util 0.0.1", "util 0.0.1",
] ]

View file

@ -39,3 +39,12 @@ git = "https://github.com/servo/rust-geom"
[dependencies.url] [dependencies.url]
git = "https://github.com/servo/rust-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"

View file

@ -57,6 +57,7 @@ use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNo
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId};
use script::dom::node::{TextNodeTypeId}; use script::dom::node::{TextNodeTypeId};
use script::dom::htmlobjectelement::is_image_data; use script::dom::htmlobjectelement::is_image_data;
use servo_util::atom::Atom;
use servo_util::namespace; use servo_util::namespace;
use std::mem; use std::mem;
use std::sync::atomics::Relaxed; use std::sync::atomics::Relaxed;
@ -1047,7 +1048,8 @@ trait ObjectElement {
impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> { impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> {
fn get_type_and_data(&self) -> (Option<&'static str>, Option<&'static str>) { fn get_type_and_data(&self) -> (Option<&'static str>, Option<&'static str>) {
let elem = self.as_element(); 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 { fn has_object_data(&self) -> bool {

View file

@ -223,8 +223,7 @@ impl StyleSharingCandidate {
style: style, style: style,
parent_style: parent_style, parent_style: parent_style,
local_name: element.get_local_name().clone(), local_name: element.get_local_name().clone(),
class: element.get_attr(&Null, "class") class: element.get_attr(&Null, &satom!("class")).map(|string| string.to_string()),
.map(|string| string.to_string()),
}) })
} }
@ -232,7 +231,7 @@ impl StyleSharingCandidate {
if *element.get_local_name() != self.local_name { if *element.get_local_name() != self.local_name {
return false 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, (&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 return false
@ -454,7 +453,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
} }
let ok = { let ok = {
let element = self.as_element(); 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 { if !ok {
return CannotShare(false) return CannotShare(false)
@ -501,7 +500,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
element element
.get_attr(&Null, "class") .get_attr(&Null, &satom!("class"))
.map(|attr| { .map(|attr| {
for c in attr.split(style::SELECTOR_WHITESPACE) { for c in attr.split(style::SELECTOR_WHITESPACE) {
bf.insert(&c); bf.insert(&c);
@ -520,7 +519,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
element element
.get_attr(&Null, "class") .get_attr(&Null, &satom!("class"))
.map(|attr| { .map(|attr| {
for c in attr.split(style::SELECTOR_WHITESPACE) { for c in attr.split(style::SELECTOR_WHITESPACE) {
bf.remove(&c); bf.remove(&c);

View file

@ -39,6 +39,7 @@ use serialize::{Encodable, Encoder};
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId}; use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
use servo_net::image::holder::ImageHolder; use servo_net::image::holder::ImageHolder;
use servo_net::local_image_cache::LocalImageCache; use servo_net::local_image_cache::LocalImageCache;
use servo_util::atom::Atom;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::geometry; use servo_util::geometry;
use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin}; use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin};
@ -174,7 +175,7 @@ impl ImageFragmentInfo {
image_url: Url, image_url: Url,
local_image_cache: Arc<Mutex<LocalImageCache>>) local_image_cache: Arc<Mutex<LocalImageCache>>)
-> ImageFragmentInfo { -> ImageFragmentInfo {
fn convert_length(node: &ThreadSafeLayoutNode, name: &str) -> Option<Au> { fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option<Au> {
let element = node.as_element(); let element = node.as_element();
element.get_attr(&namespace::Null, name).and_then(|string| { element.get_attr(&namespace::Null, name).and_then(|string| {
let n: Option<int> = FromStr::from_str(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 is_vertical = node.style().writing_mode.is_vertical();
let dom_width = convert_length(node, "width"); let dom_width = convert_length(node, &satom!("width"));
let dom_height = convert_length(node, "height"); let dom_height = convert_length(node, &satom!("height"));
ImageFragmentInfo { ImageFragmentInfo {
image: ImageHolder::new(image_url, local_image_cache), image: ImageHolder::new(image_url, local_image_cache),
computed_inline_size: None, computed_inline_size: None,
@ -337,7 +338,7 @@ impl TableColumnFragmentInfo {
pub fn new(node: &ThreadSafeLayoutNode) -> TableColumnFragmentInfo { pub fn new(node: &ThreadSafeLayoutNode) -> TableColumnFragmentInfo {
let span = { let span = {
let element = node.as_element(); 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); let n: Option<int> = FromStr::from_str(string);
n n
}) })

View file

@ -29,6 +29,10 @@ extern crate servo_msg = "msg";
#[phase(plugin, link)] #[phase(plugin, link)]
extern crate servo_util = "util"; extern crate servo_util = "util";
#[phase(plugin)]
extern crate string_cache_macros;
extern crate string_cache;
extern crate collections; extern crate collections;
extern crate encoding; extern crate encoding;
extern crate green; extern crate green;

View file

@ -273,15 +273,14 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool { fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool {
assert!(self.is_element()) assert!(self.is_element())
let name = if self.is_html_element_in_html_document() { let name = if self.is_html_element_in_html_document() {
attr.lower_name.as_slice() &attr.lower_name
} else { } else {
attr.name.as_slice() &attr.name
}; };
match attr.namespace { match attr.namespace {
SpecificNamespace(ref ns) => { SpecificNamespace(ref ns) => {
let element = self.as_element(); let element = self.as_element();
element.get_attr(ns, name) element.get_attr(ns, name).map_or(false, |attr| test(attr))
.map_or(false, |attr| test(attr))
}, },
// FIXME: https://github.com/mozilla/servo/issues/1558 // FIXME: https://github.com/mozilla/servo/issues/1558
AnyNamespace => false, AnyNamespace => false,
@ -383,7 +382,7 @@ impl<'le> TElement for LayoutElement<'le> {
} }
#[inline] #[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) } unsafe { self.element.get_attr_val_for_layout(namespace, name) }
} }
@ -395,7 +394,9 @@ impl<'le> TElement for LayoutElement<'le> {
ElementNodeTypeId(HTMLAnchorElementTypeId) | ElementNodeTypeId(HTMLAnchorElementTypeId) |
ElementNodeTypeId(HTMLAreaElementTypeId) | ElementNodeTypeId(HTMLAreaElementTypeId) |
ElementNodeTypeId(HTMLLinkElementTypeId) => { 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, _ => None,
} }
@ -409,7 +410,9 @@ impl<'le> TElement for LayoutElement<'le> {
#[inline] #[inline]
fn get_id(&self) -> Option<Atom> { 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 { 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 { unsafe {
self.element.has_class_for_layout(name) 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 { fn get_content(content_list: &content::T) -> String {
@ -758,8 +774,10 @@ pub struct ThreadSafeLayoutElement<'le> {
impl<'le> ThreadSafeLayoutElement<'le> { impl<'le> ThreadSafeLayoutElement<'le> {
#[inline] #[inline]
pub fn get_attr(&self, namespace: &Namespace, name: &str) -> Option<&'static str> { pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'static str> {
unsafe { self.element.get_attr_val_for_layout(namespace, name) } unsafe {
self.element.get_attr_val_for_layout(namespace, name)
}
} }
} }

View file

@ -210,6 +210,10 @@ macro_rules! lazy_init(
) )
) )
#[macro_export]
macro_rules! satom(
($str:tt) => (Atom::new(atom!($str)))
)
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -52,5 +52,14 @@ branch = "servo"
[dependencies.js] [dependencies.js]
git = "https://github.com/servo/rust-mozjs" 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] [dependencies.url]
git = "https://github.com/servo/rust-url" git = "https://github.com/servo/rust-url"

View file

@ -13,13 +13,13 @@ use dom::element::{Element, AttributeHandlers};
use dom::node::Node; use dom::node::Node;
use dom::window::Window; use dom::window::Window;
use dom::virtualmethods::vtable_for; use dom::virtualmethods::vtable_for;
use servo_util::atom::Atom; use servo_util::atom::Atom;
use servo_util::namespace; use servo_util::namespace;
use servo_util::namespace::Namespace; use servo_util::namespace::Namespace;
use servo_util::str::{DOMString, split_html_space_chars}; use servo_util::str::{DOMString, split_html_space_chars};
use std::cell::{Ref, RefCell}; use std::cell::{Ref, RefCell};
use std::mem; use std::mem;
use std::slice::Items;
pub enum AttrSettingType { pub enum AttrSettingType {
FirstSetAttr, FirstSetAttr,
@ -51,9 +51,9 @@ impl AttrValue {
AtomAttrValue(value) AtomAttrValue(value)
} }
pub fn tokens<'a>(&'a self) -> Option<Items<'a, Atom>> { pub fn tokens<'a>(&'a self) -> Option<&'a [Atom]> {
match *self { match *self {
TokenListAttrValue(_, ref tokens) => Some(tokens.iter()), TokenListAttrValue(_, ref tokens) => Some(tokens.as_slice()),
_ => None _ => None
} }
} }
@ -189,17 +189,19 @@ impl<'a> AttrHelpers for JSRef<'a, Attr> {
pub trait AttrHelpersForLayout { pub trait AttrHelpersForLayout {
unsafe fn value_ref_forever(&self) -> &'static str; unsafe fn value_ref_forever(&self) -> &'static str;
unsafe fn value_atom_forever(&self) -> Option<Atom>; 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; unsafe fn local_name_atom_forever(&self) -> Atom;
} }
impl AttrHelpersForLayout for Attr { impl AttrHelpersForLayout for Attr {
#[inline]
unsafe fn value_ref_forever(&self) -> &'static str { unsafe fn value_ref_forever(&self) -> &'static str {
// cast to point to T in RefCell<T> directly // cast to point to T in RefCell<T> directly
let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref()); let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref());
value.as_slice() value.as_slice()
} }
#[inline]
unsafe fn value_atom_forever(&self) -> Option<Atom> { unsafe fn value_atom_forever(&self) -> Option<Atom> {
// cast to point to T in RefCell<T> directly // cast to point to T in RefCell<T> directly
let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref()); 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 // cast to point to T in RefCell<T> directly
let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref()); let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref());
match *value { match *value {
TokenListAttrValue(_, ref tokens) => Some(tokens.iter()), TokenListAttrValue(_, ref tokens) => Some(tokens.as_slice()),
_ => None, _ => None,
} }
} }
#[inline]
unsafe fn local_name_atom_forever(&self) -> Atom { unsafe fn local_name_atom_forever(&self) -> Atom {
self.local_name.clone() self.local_name.clone()
} }

View file

@ -5458,6 +5458,7 @@ class GlobalGenRoots():
for protoName in descriptor.prototypeChain[1:-1]: for protoName in descriptor.prototypeChain[1:-1]:
protoDescriptor = config.getDescriptor(protoName) protoDescriptor = config.getDescriptor(protoName)
delegate = string.Template('''impl ${selfName} for ${baseName} { delegate = string.Template('''impl ${selfName} for ${baseName} {
#[inline]
fn ${fname}(&self) -> bool { fn ${fname}(&self) -> bool {
self.${parentName}.${fname}() self.${parentName}.${fname}()
} }

View file

@ -52,6 +52,7 @@ use dom::window::{Window, WindowHelpers};
use html::hubbub_html_parser::build_element_from_tag; use html::hubbub_html_parser::build_element_from_tag;
use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks}; use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks};
use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage}; use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage};
use servo_util::atom::Atom;
use servo_util::namespace; use servo_util::namespace;
use servo_util::namespace::{Namespace, Null}; use servo_util::namespace::{Namespace, Null};
use servo_util::str::{DOMString, null_str_as_empty_ref, split_html_space_chars}; 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(); 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() attr.value().as_slice() == name.as_slice()
}) })
}) })

View file

@ -21,24 +21,23 @@ use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
pub struct DOMTokenList { pub struct DOMTokenList {
reflector_: Reflector, reflector_: Reflector,
element: JS<Element>, element: JS<Element>,
local_name: &'static str, local_name: Atom,
} }
impl DOMTokenList { impl DOMTokenList {
pub fn new_inherited(element: &JSRef<Element>, pub fn new_inherited(element: &JSRef<Element>, local_name: &Atom) -> DOMTokenList {
local_name: &'static str) -> DOMTokenList {
DOMTokenList { DOMTokenList {
reflector_: Reflector::new(), reflector_: Reflector::new(),
element: JS::from_rooted(element), element: JS::from_rooted(element),
local_name: local_name, local_name: local_name.clone(),
} }
} }
pub fn new(element: &JSRef<Element>, pub fn new(element: &JSRef<Element>, local_name: &Atom) -> Temporary<DOMTokenList> {
local_name: &'static str) -> Temporary<DOMTokenList> {
let window = window_from_node(element).root(); let window = window_from_node(element).root();
reflect_dom_object(box DOMTokenList::new_inherited(element, local_name), 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> { impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> {
fn attribute(&self) -> Option<Temporary<Attr>> { fn attribute(&self) -> Option<Temporary<Attr>> {
let element = self.element.root(); 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> { 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 // http://dom.spec.whatwg.org/#dom-domtokenlist-item
fn Item(&self, index: u32) -> Option<DOMString> { fn Item(&self, index: u32) -> Option<DOMString> {
self.attribute().root().and_then(|attr| attr.value().tokens().and_then(|mut tokens| { 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.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(|mut tokens| {
let atom = Atom::from_slice(slice); let atom = Atom::from_slice(slice);
tokens.any(|token| *token == atom) tokens.iter().any(|token| *token == atom)
})).unwrap_or(false) })).unwrap_or(false)
}) })
} }

View file

@ -55,6 +55,7 @@ pub struct Element {
} }
impl ElementDerived for EventTarget { impl ElementDerived for EventTarget {
#[inline]
fn is_element(&self) -> bool { fn is_element(&self) -> bool {
match self.type_id { match self.type_id {
NodeTargetTypeId(ElementNodeTypeId(_)) => true, NodeTargetTypeId(ElementNodeTypeId(_)) => true,
@ -167,21 +168,22 @@ impl Element {
} }
pub trait RawLayoutElementHelpers { pub trait RawLayoutElementHelpers {
unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) -> Option<&'static str>; 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: &str) -> Option<Atom>; unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option<Atom>;
unsafe fn has_class_for_layout(&self, name: &str) -> bool; unsafe fn has_class_for_layout(&self, name: &Atom) -> bool;
unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]>;
} }
impl RawLayoutElementHelpers for Element { impl RawLayoutElementHelpers for Element {
#[inline] #[inline]
#[allow(unrooted_must_root)] #[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> { -> Option<&'static str> {
// cast to point to T in RefCell<T> directly // cast to point to T in RefCell<T> directly
let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| { (*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get(); let attr = attr.unsafe_get();
name == (*attr).local_name_atom_forever().as_slice() && *name == (*attr).local_name_atom_forever() &&
(*attr).namespace == *namespace (*attr).namespace == *namespace
}).map(|attr| { }).map(|attr| {
let attr = attr.unsafe_get(); let attr = attr.unsafe_get();
@ -191,13 +193,13 @@ impl RawLayoutElementHelpers for Element {
#[inline] #[inline]
#[allow(unrooted_must_root)] #[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> { -> Option<Atom> {
// cast to point to T in RefCell<T> directly // cast to point to T in RefCell<T> directly
let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| { (*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get(); let attr = attr.unsafe_get();
name == (*attr).local_name_atom_forever().as_slice() && *name == (*attr).local_name_atom_forever() &&
(*attr).namespace == *namespace (*attr).namespace == *namespace
}).and_then(|attr| { }).and_then(|attr| {
let attr = attr.unsafe_get(); let attr = attr.unsafe_get();
@ -207,16 +209,31 @@ impl RawLayoutElementHelpers for Element {
#[inline] #[inline]
#[allow(unrooted_must_root)] #[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); let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| { (*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get(); let attr = attr.unsafe_get();
(*attr).local_name_atom_forever().as_slice() == "class" (*attr).local_name_atom_forever() == satom!("class")
}).map_or(false, |attr| { }).map_or(false, |attr| {
let attr = attr.unsafe_get(); 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()) }.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 { pub trait LayoutElementHelpers {
@ -225,6 +242,7 @@ pub trait LayoutElementHelpers {
impl LayoutElementHelpers for JS<Element> { impl LayoutElementHelpers for JS<Element> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
#[inline]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool { unsafe fn html_element_in_html_document_for_layout(&self) -> bool {
if (*self.unsafe_get()).namespace != namespace::HTML { if (*self.unsafe_get()).namespace != namespace::HTML {
return false return false
@ -257,10 +275,11 @@ impl<'a> ElementHelpers for JSRef<'a, Element> {
} }
pub trait AttributeHandlers { pub trait AttributeHandlers {
/// Returns the attribute with given namespace and case-sensitive local /// Returns the attribute with given namespace and case-insensitive local name, if any.
/// name, if any. fn get_attribute(&self, namespace: Namespace, local_name: &Atom) -> Option<Temporary<Attr>>;
fn get_attribute(&self, namespace: Namespace, local_name: &str) /// Returns the attribute with given namespace and case-sensitive local name, if any.
-> Option<Temporary<Attr>>; fn get_case_sensitive_attribute(&self, namespace: Namespace, name: &Atom)
-> Option<Temporary<Attr>>;
fn set_attribute_from_parser(&self, local_name: Atom, fn set_attribute_from_parser(&self, local_name: Atom,
value: DOMString, namespace: Namespace, value: DOMString, namespace: Namespace,
prefix: Option<DOMString>); prefix: Option<DOMString>);
@ -273,27 +292,38 @@ pub trait AttributeHandlers {
fn remove_attribute(&self, namespace: Namespace, name: &str); fn remove_attribute(&self, namespace: Namespace, name: &str);
fn notify_attribute_changed(&self, local_name: &Atom); 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); fn set_atomic_attribute(&self, name: &str, value: DOMString);
// http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes // http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes
fn has_attribute(&self, name: &str) -> bool; fn has_attribute(&self, name: &str) -> bool;
fn set_bool_attribute(&self, name: &str, value: 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 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_string_attribute(&self, name: &str, value: DOMString);
fn set_tokenlist_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); fn set_uint_attribute(&self, name: &str, value: u32);
} }
impl<'a> AttributeHandlers for JSRef<'a, Element> { impl<'a> AttributeHandlers for JSRef<'a, Element> {
fn get_attribute(&self, namespace: Namespace, local_name: &str) -> Option<Temporary<Attr>> { fn get_attribute(&self, namespace: Namespace, name: &Atom) -> Option<Temporary<Attr>> {
let local_name = Atom::from_slice(local_name); match self.html_element_in_html_document() {
self.attrs.borrow().iter().map(|attr| attr.root()).find(|attr| { true => {
*attr.local_name() == local_name && attr.namespace == namespace 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)) }).map(|x| Temporary::from_rooted(&*x))
} }
@ -393,11 +423,12 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
} }
} }
fn has_class(&self, name: &str) -> bool { fn has_class(&self, name: &Atom) -> bool {
self.get_attribute(Null, "class").root().map(|attr| { self.get_attribute(Null, &satom!("class")).root().map(|attr| {
attr.deref().value().tokens().map(|mut tokens| { match attr.deref().value().tokens() {
tokens.any(|atom| atom.as_slice() == name) None => false,
}).unwrap_or(false) Some(ref atoms) => atoms.iter().any(|atom| atom == name),
}
}).unwrap_or(false) }).unwrap_or(false)
} }
@ -426,8 +457,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
} }
} }
fn get_url_attribute(&self, name: &str) -> DOMString { fn get_url_attribute(&self, name: &Atom) -> DOMString {
assert!(name == name.to_ascii_lower().as_slice());
// XXX Resolve URL. // XXX Resolve URL.
self.get_string_attribute(name) self.get_string_attribute(name)
} }
@ -435,8 +465,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
self.set_string_attribute(name, value); self.set_string_attribute(name, value);
} }
fn get_string_attribute(&self, name: &str) -> DOMString { fn get_string_attribute(&self, name: &Atom) -> DOMString {
assert!(name == name.to_ascii_lower().as_slice());
match self.get_attribute(Null, name) { match self.get_attribute(Null, name) {
Some(x) => { Some(x) => {
let x = x.root(); let x = x.root();
@ -455,8 +484,8 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
self.set_attribute(name, AttrValue::from_tokenlist(value)); self.set_attribute(name, AttrValue::from_tokenlist(value));
} }
fn get_uint_attribute(&self, name: &str) -> u32 { fn get_uint_attribute(&self, name: &Atom) -> u32 {
assert!(name == name.to_ascii_lower().as_slice()); assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice());
let attribute = self.get_attribute(Null, name).root(); let attribute = self.get_attribute(Null, name).root();
match attribute { match attribute {
Some(attribute) => { Some(attribute) => {
@ -523,7 +552,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
// http://dom.spec.whatwg.org/#dom-element-id // http://dom.spec.whatwg.org/#dom-element-id
fn Id(&self) -> DOMString { fn Id(&self) -> DOMString {
self.get_string_attribute("id") self.get_string_attribute(&satom!("id"))
} }
// http://dom.spec.whatwg.org/#dom-element-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 // http://dom.spec.whatwg.org/#dom-element-classname
fn ClassName(&self) -> DOMString { fn ClassName(&self) -> DOMString {
self.get_string_attribute("class") self.get_string_attribute(&satom!("class"))
} }
// http://dom.spec.whatwg.org/#dom-element-classname // http://dom.spec.whatwg.org/#dom-element-classname
@ -546,7 +575,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
match self.class_list.get() { match self.class_list.get() {
Some(class_list) => Temporary::new(class_list), Some(class_list) => Temporary::new(class_list),
None => { 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())); self.class_list.assign(Some(class_list.deref().clone()));
Temporary::from_rooted(&*class_list) Temporary::from_rooted(&*class_list)
} }
@ -577,7 +606,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
} else { } else {
name 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()) .map(|s| s.deref().Value())
} }
@ -586,7 +615,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
namespace: Option<DOMString>, namespace: Option<DOMString>,
local_name: DOMString) -> Option<DOMString> { local_name: DOMString) -> Option<DOMString> {
let namespace = Namespace::from_str(null_str_as_empty_ref(&namespace)); 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()) .map(|attr| attr.deref().Value())
} }
@ -896,7 +925,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> {
if !tree_in_doc { return; } if !tree_in_doc { return; }
match self.get_attribute(Null, "id").root() { match self.get_attribute(Null, &satom!("id")).root() {
Some(attr) => { Some(attr) => {
let doc = document_from_node(self).root(); let doc = document_from_node(self).root();
let value = attr.deref().Value(); let value = attr.deref().Value();
@ -916,7 +945,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> {
if !tree_in_doc { return; } if !tree_in_doc { return; }
match self.get_attribute(Null, "id").root() { match self.get_attribute(Null, &satom!("id")).root() {
Some(attr) => { Some(attr) => {
let doc = document_from_node(self).root(); let doc = document_from_node(self).root();
let value = attr.deref().Value(); let value = attr.deref().Value();
@ -930,8 +959,8 @@ impl<'a> VirtualMethods for JSRef<'a, Element> {
} }
impl<'a> style::TElement for JSRef<'a, Element> { impl<'a> style::TElement for JSRef<'a, Element> {
fn get_attr(&self, namespace: &Namespace, attr: &str) -> Option<&'static str> { fn get_attr(&self, namespace: &Namespace, attr: &Atom) -> Option<&'static str> {
self.get_attribute(namespace.clone(), attr).root().map(|attr| { self.get_case_sensitive_attribute(namespace.clone(), attr).root().map(|attr| {
unsafe { mem::transmute(attr.deref().value().as_slice()) } unsafe { mem::transmute(attr.deref().value().as_slice()) }
}) })
} }
@ -943,7 +972,9 @@ impl<'a> style::TElement for JSRef<'a, Element> {
// selector-link // selector-link
ElementNodeTypeId(HTMLAnchorElementTypeId) | ElementNodeTypeId(HTMLAnchorElementTypeId) |
ElementNodeTypeId(HTMLAreaElementTypeId) | ElementNodeTypeId(HTMLAreaElementTypeId) |
ElementNodeTypeId(HTMLLinkElementTypeId) => self.get_attr(&namespace::Null, "href"), ElementNodeTypeId(HTMLLinkElementTypeId) => {
self.get_attr(&namespace::Null, &satom!("href"))
}
_ => None, _ => None,
} }
} }
@ -958,7 +989,7 @@ impl<'a> style::TElement for JSRef<'a, Element> {
node.get_hover_state() node.get_hover_state()
} }
fn get_id<'a>(&self) -> Option<Atom> { 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(); let attr = attr.root();
match *attr.value() { match *attr.value() {
AtomAttrValue(ref val) => val.clone(), 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); let node: &JSRef<Node> = NodeCast::from_ref(self);
node.get_enabled_state() node.get_enabled_state()
} }
fn has_class(&self, name: &str) -> bool { fn has_class(&self, name: &Atom) -> bool {
(self as &AttributeHandlers).has_class(name) (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);
}
}
}
}
}
}
} }

View file

@ -57,7 +57,7 @@ impl<'a> PrivateHTMLAnchorElementHelpers for JSRef<'a, HTMLAnchorElement> {
fn handle_event_impl(&self, event: &JSRef<Event>) { fn handle_event_impl(&self, event: &JSRef<Event>) {
if "click" == event.Type().as_slice() && !event.DefaultPrevented() { if "click" == event.Type().as_slice() && !event.DefaultPrevented() {
let element: &JSRef<Element> = ElementCast::from_ref(self); 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 { match attr {
Some(ref href) => { Some(ref href) => {
let value = href.Value(); let value = href.Value();

View file

@ -146,15 +146,17 @@ impl HTMLCollection {
pub fn by_class_name(window: &JSRef<Window>, root: &JSRef<Node>, classes: DOMString) pub fn by_class_name(window: &JSRef<Window>, root: &JSRef<Node>, classes: DOMString)
-> Temporary<HTMLCollection> { -> Temporary<HTMLCollection> {
struct ClassNameFilter { struct ClassNameFilter {
classes: Vec<DOMString> classes: Vec<Atom>
} }
impl CollectionFilter for ClassNameFilter { impl CollectionFilter for ClassNameFilter {
fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool { 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 { 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) HTMLCollection::create(window, root, box filter)
} }
@ -220,8 +222,8 @@ impl<'a> HTMLCollectionMethods for JSRef<'a, HTMLCollection> {
Static(ref elems) => elems.iter() Static(ref elems) => elems.iter()
.map(|elem| elem.root()) .map(|elem| elem.root())
.find(|elem| { .find(|elem| {
elem.get_string_attribute("name") == key || elem.get_string_attribute(&satom!("name")) == key ||
elem.get_string_attribute("id") == key }) elem.get_string_attribute(&satom!("id")) == key })
.map(|maybe_elem| Temporary::from_rooted(&*maybe_elem)), .map(|maybe_elem| Temporary::from_rooted(&*maybe_elem)),
Live(ref root, ref filter) => { Live(ref root, ref filter) => {
let root = root.root(); let root = root.root();
@ -232,8 +234,8 @@ impl<'a> HTMLCollectionMethods for JSRef<'a, HTMLCollection> {
.map(|elem| elem.clone()) .map(|elem| elem.clone())
}) })
.find(|elem| { .find(|elem| {
elem.get_string_attribute("name") == key || elem.get_string_attribute(&satom!("name")) == key ||
elem.get_string_attribute("id") == key }) elem.get_string_attribute(&satom!("id")) == key })
.map(|maybe_elem| Temporary::from_rooted(&maybe_elem)) .map(|maybe_elem| Temporary::from_rooted(&maybe_elem))
} }
} }

View file

@ -75,7 +75,7 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
fn get_url(&self) -> Option<Url> { fn get_url(&self) -> Option<Url> {
let element: &JSRef<Element> = ElementCast::from_ref(self); 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(); let url = src.deref().value();
if url.as_slice().is_empty() { if url.as_slice().is_empty() {
None None
@ -133,7 +133,7 @@ impl HTMLIFrameElement {
impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> { impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
fn Src(&self) -> DOMString { fn Src(&self) -> DOMString {
let element: &JSRef<Element> = ElementCast::from_ref(self); let element: &JSRef<Element> = ElementCast::from_ref(self);
element.get_string_attribute("src") element.get_string_attribute(&satom!("src"))
} }
fn SetSrc(&self, src: DOMString) { fn SetSrc(&self, src: DOMString) {
@ -143,7 +143,7 @@ impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
fn Sandbox(&self) -> DOMString { fn Sandbox(&self) -> DOMString {
let element: &JSRef<Element> = ElementCast::from_ref(self); let element: &JSRef<Element> = ElementCast::from_ref(self);
element.get_string_attribute("sandbox") element.get_string_attribute(&satom!("sandbox"))
} }
fn SetSandbox(&self, sandbox: DOMString) { fn SetSandbox(&self, sandbox: DOMString) {

View file

@ -92,11 +92,11 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> {
// FIXME: workaround for https://github.com/mozilla/rust/issues/13246; // FIXME: workaround for https://github.com/mozilla/rust/issues/13246;
// we get unrooting order failures if these are inside the match. // we get unrooting order failures if these are inside the match.
let rel = { 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()) rel.map(|rel| rel.deref().value().as_slice().to_string())
}; };
let href = { 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()) href.map(|href| href.deref().value().as_slice().to_string())
}; };

View file

@ -63,8 +63,8 @@ impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> {
let elem: &JSRef<Element> = ElementCast::from_ref(self); let elem: &JSRef<Element> = ElementCast::from_ref(self);
// TODO: support other values // TODO: support other values
match (elem.get_attribute(Null, "type").map(|x| x.root().Value()), match (elem.get_attribute(Null, &satom!("type")).map(|x| x.root().Value()),
elem.get_attribute(Null, "data").map(|x| x.root().Value())) { elem.get_attribute(Null, &satom!("data")).map(|x| x.root().Value())) {
(None, Some(uri)) => { (None, Some(uri)) => {
if is_image_data(uri.as_slice()) { if is_image_data(uri.as_slice()) {
let data_url = Url::parse(uri.as_slice()).unwrap(); let data_url = Url::parse(uri.as_slice()).unwrap();

View file

@ -16,6 +16,7 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
use servo_util::atom::Atom;
use servo_util::namespace::Null; use servo_util::namespace::Null;
use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec}; 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> { impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> {
fn is_javascript(&self) -> bool { fn is_javascript(&self) -> bool {
let element: &JSRef<Element> = ElementCast::from_ref(self); 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() => { Some(ref s) if s.is_empty() => {
// type attr exists, but empty means js // type attr exists, but empty means js
debug!("script type empty, inferring js"); debug!("script type empty, inferring js");
@ -87,7 +88,9 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> {
}, },
None => { None => {
debug!("no script type"); 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() => { Some(ref s) if s.is_empty() => {
debug!("script language empty, inferring js"); debug!("script language empty, inferring js");
true true
@ -109,7 +112,7 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> {
impl<'a> HTMLScriptElementMethods for JSRef<'a, HTMLScriptElement> { impl<'a> HTMLScriptElementMethods for JSRef<'a, HTMLScriptElement> {
fn Src(&self) -> DOMString { fn Src(&self) -> DOMString {
let element: &JSRef<Element> = ElementCast::from_ref(self); 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 // http://www.whatwg.org/html/#dom-script-text

View file

@ -12,7 +12,8 @@ macro_rules! make_getter(
use dom::bindings::codegen::InheritTypes::ElementCast; use dom::bindings::codegen::InheritTypes::ElementCast;
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
let element: &JSRef<Element> = ElementCast::from_ref(self); 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 dom::bindings::codegen::InheritTypes::ElementCast;
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
let element: &JSRef<Element> = ElementCast::from_ref(self); 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()))
} }
); );
) )

View file

@ -769,16 +769,19 @@ pub trait RawLayoutNodeHelpers {
} }
impl RawLayoutNodeHelpers for Node { impl RawLayoutNodeHelpers for Node {
#[inline]
unsafe fn get_hover_state_for_layout(&self) -> bool { unsafe fn get_hover_state_for_layout(&self) -> bool {
(*self.unsafe_get_flags()).contains(InHoverState) (*self.unsafe_get_flags()).contains(InHoverState)
} }
#[inline]
unsafe fn get_disabled_state_for_layout(&self) -> bool { unsafe fn get_disabled_state_for_layout(&self) -> bool {
(*self.unsafe_get_flags()).contains(InDisabledState) (*self.unsafe_get_flags()).contains(InDisabledState)
} }
#[inline]
unsafe fn get_enabled_state_for_layout(&self) -> bool { unsafe fn get_enabled_state_for_layout(&self) -> bool {
(*self.unsafe_get_flags()).contains(InEnabledState) (*self.unsafe_get_flags()).contains(InEnabledState)
} }
#[inline]
fn type_id_for_layout(&self) -> NodeTypeId { fn type_id_for_layout(&self) -> NodeTypeId {
self.type_id self.type_id
} }
@ -1413,6 +1416,7 @@ impl Node {
} }
} }
#[inline]
pub unsafe fn unsafe_get_flags(&self) -> *const NodeFlags { pub unsafe fn unsafe_get_flags(&self) -> *const NodeFlags {
mem::transmute(&self.flags) 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>> { fn parent_node(&self) -> Option<JSRef<'a, Node>> {
(self as &NodeHelpers).parent_node().map(|node| *node.root()) (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 { fn match_attr(&self, attr: &style::AttrSelector, test: |&str| -> bool) -> bool {
let name = { let name = {
if self.is_html_element_in_html_document() { if self.is_html_element_in_html_document() {
attr.lower_name.as_slice() &attr.lower_name
} else { } else {
attr.name.as_slice() &attr.name
} }
}; };
match attr.namespace { match attr.namespace {

View file

@ -472,7 +472,7 @@ pub fn parse_html(page: &Page,
}; };
let script_element: &JSRef<Element> = ElementCast::from_ref(script); 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) => { Some(src) => {
debug!("found script: {:s}", src.deref().Value()); debug!("found script: {:s}", src.deref().Value());
let mut url_parser = UrlParser::new(); let mut url_parser = UrlParser::new();

View file

@ -36,6 +36,9 @@ extern crate servo_macros = "macros";
extern crate servo_net = "net"; extern crate servo_net = "net";
extern crate servo_util = "util"; extern crate servo_util = "util";
extern crate style; extern crate style;
extern crate string_cache;
#[phase(plugin)]
extern crate string_cache_macros;
extern crate sync; extern crate sync;
extern crate servo_msg = "msg"; extern crate servo_msg = "msg";
extern crate url; extern crate url;

View file

@ -27,6 +27,7 @@ use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData}; use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::atom::Atom;
use servo_util::namespace::Null; use servo_util::namespace::Null;
use servo_util::str::DOMString; use servo_util::str::DOMString;
use std::cell::{Cell, RefCell, Ref, RefMut}; use std::cell::{Cell, RefCell, Ref, RefMut};
@ -373,9 +374,11 @@ impl Page {
.filter(|node| node.is_anchor_element()); .filter(|node| node.is_anchor_element());
anchors.find(|node| { anchors.find(|node| {
let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
elem.get_attribute(Null, "name").root().map_or(false, |attr| { elem.get_attribute(Null, &satom!("name"))
attr.deref().value().as_slice() == fragid.as_slice() .root()
}) .map_or(false, |attr| {
attr.deref().value().as_slice() == fragid.as_slice()
})
}).map(|node| Temporary::from_rooted(ElementCast::to_ref(&node).unwrap())) }).map(|node| Temporary::from_rooted(ElementCast::to_ref(&node).unwrap()))
} }
} }

View file

@ -29,3 +29,11 @@ git = "https://github.com/servo/rust-cssparser"
[dependencies.encoding] [dependencies.encoding]
git = "https://github.com/lifthrasiir/rust-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"

View file

@ -11,12 +11,14 @@
#![feature(phase)] #![feature(phase)]
#[phase(plugin, link)] extern crate log; #[phase(plugin, link)] extern crate log;
#[phase(plugin)] extern crate string_cache_macros;
extern crate debug; extern crate debug;
extern crate collections; extern crate collections;
extern crate geom; extern crate geom;
extern crate num; extern crate num;
extern crate serialize; extern crate serialize;
extern crate string_cache;
extern crate sync; extern crate sync;
extern crate url; extern crate url;

View file

@ -9,7 +9,7 @@ use selectors::AttrSelector;
use servo_util::atom::Atom; use servo_util::atom::Atom;
use servo_util::namespace::Namespace; use servo_util::namespace::Namespace;
// FIXME(pcwalton): When we get associated types in Rust, this can be nicer.
pub trait TNode<E:TElement> : Clone { pub trait TNode<E:TElement> : Clone {
fn parent_node(&self) -> Option<Self>; fn parent_node(&self) -> Option<Self>;
/// Name is prefixed to avoid a conflict with TLayoutNode. /// Name is prefixed to avoid a conflict with TLayoutNode.
@ -24,7 +24,7 @@ pub trait TNode<E:TElement> : Clone {
} }
pub trait TElement { 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_link(&self) -> Option<&'static str>;
fn get_local_name<'a>(&'a self) -> &'a Atom; fn get_local_name<'a>(&'a self) -> &'a Atom;
fn get_namespace<'a>(&'a self) -> &'a Namespace; fn get_namespace<'a>(&'a self) -> &'a Namespace;
@ -32,5 +32,13 @@ pub trait TElement {
fn get_id(&self) -> Option<Atom>; fn get_id(&self) -> Option<Atom>;
fn get_disabled_state(&self) -> bool; fn get_disabled_state(&self) -> bool;
fn get_enabled_state(&self) -> bool; fn get_enabled_state(&self) -> bool;
fn has_class(&self, name: &str) -> bool; fn has_class(&self, name: &Atom) -> bool;
// Ordinarily I wouldn't use callbacks like this, but the alternative is
// really messy, since there is a `JSRef` and a `RefCell` involved. Maybe
// in the future when we have associated types and/or a more convenient
// JS GC story... --pcwalton
fn each_class(&self, callback: |&Atom|);
} }

View file

@ -11,7 +11,6 @@ use url::Url;
use servo_util::atom::Atom; use servo_util::atom::Atom;
use servo_util::bloom::BloomFilter; use servo_util::bloom::BloomFilter;
use servo_util::namespace;
use servo_util::smallvec::VecLike; use servo_util::smallvec::VecLike;
use servo_util::sort; use servo_util::sort;
@ -106,20 +105,14 @@ impl SelectorMap {
None => {} None => {}
} }
match element.get_attr(&namespace::Null, "class") { element.each_class(|class| {
Some(ref class_attr) => { SelectorMap::get_matching_rules_from_hash(node,
// FIXME: Store classes pre-split as atoms to make the loop below faster. parent_bf,
for class in class_attr.split(SELECTOR_WHITESPACE) { &self.class_hash,
SelectorMap::get_matching_rules_from_hash(node, class,
parent_bf, matching_rules_list,
&self.class_hash, shareable);
&Atom::from_slice(class), });
matching_rules_list,
shareable);
}
}
None => {}
}
let local_name_hash = if node.is_html_element_in_html_document() { let local_name_hash = if node.is_html_element_in_html_document() {
&self.lower_local_name_hash &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| get_selector_list_selectors(selector_list).iter().any(|selector|
selector.pseudo_element.is_none() && selector.pseudo_element.is_none() &&
matches_compound_selector(&*selector.compound_selectors, element, parent_bf, &mut false)) 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 /// 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 /// 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. /// that does not appear in the bloom parent bloom filter, we can exit early.
fn can_fast_reject<E: TElement, N: TNode<E>>( fn can_fast_reject<E:TElement,
mut selector: &CompoundSelector, N:TNode<E>>(
element: &N, mut selector: &CompoundSelector,
parent_bf: &Option<BloomFilter>, element: &N,
shareable: &mut bool) -> Option<SelectorMatchingResult> { parent_bf: &Option<BloomFilter>,
shareable: &mut bool)
-> Option<SelectorMatchingResult> {
if !selector.simple_selectors.iter().all(|simple_selector| { if !selector.simple_selectors.iter().all(|simple_selector| {
matches_simple_selector(simple_selector, element, shareable) }) { matches_simple_selector(simple_selector, element, shareable) }) {
return Some(NotMatchedAndRestartFromClosestLaterSibling); return Some(NotMatchedAndRestartFromClosestLaterSibling);
@ -681,11 +681,11 @@ fn matches_compound_selector_internal<E:TElement,
/// `main/css/matching.rs`.) /// `main/css/matching.rs`.)
#[inline] #[inline]
pub fn matches_simple_selector<E:TElement, pub fn matches_simple_selector<E:TElement,
N:TNode<E>>( N:TNode<E>>(
selector: &SimpleSelector, selector: &SimpleSelector,
element: &N, element: &N,
shareable: &mut bool) shareable: &mut bool)
-> bool { -> bool {
match *selector { match *selector {
LocalNameSelector(LocalNameSelector { ref name, ref lower_name }) => { LocalNameSelector(LocalNameSelector { ref name, ref lower_name }) => {
let name = if element.is_html_element_in_html_document() { lower_name } else { 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. // TODO: cache and intern class names on elements.
ClassSelector(ref class) => { ClassSelector(ref class) => {
let element = element.as_element(); let element = element.as_element();
element.has_class(class.as_slice()) element.has_class(class)
} }
AttrExists(ref attr) => { AttrExists(ref attr) => {
@ -854,6 +854,7 @@ pub fn matches_simple_selector<E:TElement,
} }
} }
#[inline]
fn url_is_visited(_url: &str) -> bool { fn url_is_visited(_url: &str) -> bool {
// FIXME: implement this. // FIXME: implement this.
// This function will probably need to take a "session" // This function will probably need to take a "session"
@ -862,8 +863,7 @@ fn url_is_visited(_url: &str) -> bool {
} }
#[inline] #[inline]
fn matches_generic_nth_child<'a, fn matches_generic_nth_child<E:TElement,
E:TElement,
N:TNode<E>>( N:TNode<E>>(
element: &N, element: &N,
a: i32, a: i32,

View file

@ -100,8 +100,8 @@ pub struct LocalNameSelector {
#[deriving(Eq, PartialEq, Clone, Hash)] #[deriving(Eq, PartialEq, Clone, Hash)]
pub struct AttrSelector { pub struct AttrSelector {
pub name: String, pub name: Atom,
pub lower_name: String, pub lower_name: Atom,
pub namespace: NamespaceConstraint, 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((_, None)) => fail!("Implementation error, this should not happen."),
Some((namespace, Some(local_name))) => AttrSelector { Some((namespace, Some(local_name))) => AttrSelector {
namespace: namespace, namespace: namespace,
lower_name: local_name.as_slice().to_ascii_lower(), lower_name: Atom::from_slice(local_name.as_slice().to_ascii_lower().as_slice()),
name: local_name, name: Atom::from_slice(local_name.as_slice()),
}, },
}; };
skip_whitespace(iter); skip_whitespace(iter);

View file

@ -17,6 +17,13 @@ pub struct Atom {
} }
impl Atom { impl Atom {
#[inline(always)]
pub fn new(atom: atom::Atom) -> Atom {
Atom {
atom: atom,
}
}
#[inline(always)] #[inline(always)]
pub fn from_slice(slice: &str) -> Atom { pub fn from_slice(slice: &str) -> Atom {
Atom { Atom {

6
ports/cef/Cargo.lock generated
View file

@ -277,6 +277,8 @@ dependencies = [
"net 0.0.1", "net 0.0.1",
"script 0.0.1", "script 0.0.1",
"script_traits 0.0.1", "script_traits 0.0.1",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#df34aaaaed9c4598eef5f4445d28aeb5afac574a)",
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#df34aaaaed9c4598eef5f4445d28aeb5afac574a)",
"style 0.0.1", "style 0.0.1",
"url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)", "url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)",
"util 0.0.1", "util 0.0.1",
@ -386,6 +388,8 @@ dependencies = [
"msg 0.0.1", "msg 0.0.1",
"net 0.0.1", "net 0.0.1",
"script_traits 0.0.1", "script_traits 0.0.1",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#df34aaaaed9c4598eef5f4445d28aeb5afac574a)",
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#df34aaaaed9c4598eef5f4445d28aeb5afac574a)",
"style 0.0.1", "style 0.0.1",
"url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)", "url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)",
"util 0.0.1", "util 0.0.1",
@ -467,6 +471,8 @@ dependencies = [
"encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#12b6610adff6eddc060691888c36017cd3ad57f7)", "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#12b6610adff6eddc060691888c36017cd3ad57f7)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#2982b770db6e5e3270305e0fd6b8068f6f80a489)", "geom 0.1.0 (git+https://github.com/servo/rust-geom#2982b770db6e5e3270305e0fd6b8068f6f80a489)",
"macros 0.0.1", "macros 0.0.1",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#df34aaaaed9c4598eef5f4445d28aeb5afac574a)",
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache?ref=pre-rustup#df34aaaaed9c4598eef5f4445d28aeb5afac574a)",
"url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)", "url 0.1.0 (git+https://github.com/servo/rust-url#678bb4d52638b1cfdab78ef8e521566c9240fb1a)",
"util 0.0.1", "util 0.0.1",
] ]