servo: Merge #3623 - script: Use atom comparison in more places, especially for attributes (from pcwalton:use-atoms-2); r=jdm

75% improvement in style recalc for Guardians of the Galaxy.

Source-Repo: https://github.com/servo/servo
Source-Revision: 8077edc0622b04aeb26d42ced86ea285c9cac0e7
This commit is contained in:
Patrick Walton 2014-10-14 12:42:35 -06:00
Родитель ee7c17eaa4
Коммит 7495bb838a
31 изменённых файлов: 305 добавлений и 237 удалений

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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<ComputedValues>,
pub parent_style: Arc<ComputedValues>,
pub local_name: Atom,
pub class: Option<DOMString>,
// FIXME(pcwalton): Should be a list of atoms instead.
pub class: Option<String>,
}
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)

Просмотреть файл

@ -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<Mutex<LocalImageCache<UntrustedNodeAddress>>>)
-> ImageFragmentInfo {
fn convert_length(node: &ThreadSafeLayoutNode, name: &str) -> Option<Au> {
fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option<Au> {
let element = node.as_element();
element.get_attr(&ns!(""), name).and_then(|string| {
let n: Option<int> = 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<int> = FromStr::from_str(string);
n
})

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<Atom> {
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)
}
}
}

Просмотреть файл

@ -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<Items<'a, Atom>> {
pub fn tokens<'a>(&'a self) -> Option<&'a [Atom]> {
match *self {
TokenListAttrValue(_, ref tokens) => Some(tokens.iter()),
TokenListAttrValue(_, ref tokens) => Some(tokens.as_slice()),
_ => None
}
}
@ -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<Atom>;
unsafe fn value_tokens_forever(&self) -> Option<Items<Atom>>;
unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]>;
unsafe fn local_name_atom_forever(&self) -> Atom;
}
impl AttrHelpersForLayout for Attr {
#[inline]
unsafe fn value_ref_forever(&self) -> &'static str {
// cast to point to T in RefCell<T> directly
let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(&self.value);
value.as_slice()
}
#[inline]
unsafe fn value_atom_forever(&self) -> Option<Atom> {
// cast to point to T in RefCell<T> directly
let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(&self.value);
@ -235,15 +236,17 @@ impl AttrHelpersForLayout for Attr {
}
}
unsafe fn value_tokens_forever(&self) -> Option<Items<Atom>> {
#[inline]
unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]> {
// cast to point to T in RefCell<T> directly
let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(&self.value);
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()
}

Просмотреть файл

@ -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}()
}

Просмотреть файл

@ -123,7 +123,8 @@ impl CollectionFilter for EmbedsFilter {
struct LinksFilter;
impl CollectionFilter for LinksFilter {
fn filter(&self, elem: JSRef<Element>, _root: JSRef<Node>) -> 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<Element>, _root: JSRef<Node>) -> 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<HTMLAnchorElement>| {
let elem: JSRef<Element> = 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<Element> = 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()
})
})

Просмотреть файл

@ -21,12 +21,11 @@ use string_cache::Atom;
pub struct DOMTokenList {
reflector_: Reflector,
element: JS<Element>,
local_name: &'static str,
local_name: Atom,
}
impl DOMTokenList {
fn new_inherited(element: JSRef<Element>,
local_name: &'static str) -> DOMTokenList {
pub fn new_inherited(element: JSRef<Element>, local_name: Atom) -> DOMTokenList {
DOMTokenList {
reflector_: Reflector::new(),
element: JS::from_rooted(element),
@ -34,11 +33,11 @@ impl DOMTokenList {
}
}
pub fn new(element: JSRef<Element>,
local_name: &'static str) -> Temporary<DOMTokenList> {
pub fn new(element: JSRef<Element>, local_name: &Atom) -> Temporary<DOMTokenList> {
let window = window_from_node(element).root();
reflect_dom_object(box DOMTokenList::new_inherited(element, local_name),
&Window(*window), DOMTokenListBinding::Wrap)
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<Temporary<Attr>> {
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<DOMString> {
self.attribute().root().and_then(|attr| attr.value().tokens().and_then(|mut tokens| {
tokens.idx(index as uint).map(|token| token.as_slice().to_string())
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<bool> {
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)
})
}

Просмотреть файл

@ -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<Atom>;
unsafe fn has_class_for_layout(&self, name: &str) -> bool;
unsafe fn get_classes_for_layout<'a>(&'a self) -> Option<Items<'a,Atom>>;
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<Atom>;
unsafe fn has_class_for_layout(&self, name: &Atom) -> bool;
unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]>;
}
impl RawLayoutElementHelpers for Element {
#[inline]
#[allow(unrooted_must_root)]
unsafe fn get_attr_val_for_layout<'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<T> directly
let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get();
name == (*attr).local_name_atom_forever().as_slice() &&
*(*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<T> directly
let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().filter_map(|attr: &JS<Attr>| {
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<Atom> {
// cast to point to T in RefCell<T> directly
let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get();
name == (*attr).local_name_atom_forever().as_slice() &&
*(*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<JS<Attr>> = mem::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get();
(*attr).local_name_atom_forever().as_slice() == "class"
(*attr).local_name_atom_forever() == 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<Items<'a,Atom>> {
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().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<Element> {
#[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<Temporary<Attr>>;
fn get_attributes(self, local_name: &str)
fn get_attributes(self, local_name: &Atom)
-> Vec<Temporary<Attr>>;
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<DOMString>);
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<DOMString>, cb: |JSRef<Attr>| -> 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<Temporary<Attr>> {
fn get_attribute(self, namespace: Namespace, local_name: &Atom) -> Option<Temporary<Attr>> {
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<Temporary<Attr>> {
let local_name = Atom::from_slice(local_name);
fn get_attributes(self, local_name: &Atom) -> Vec<Temporary<Attr>> {
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<DOMString>) {
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<Node> = 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<DOMTokenList> {
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<DOMString>,
local_name: DOMString) -> Option<DOMString> {
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<Atom> {
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<Node> = 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<T: AttributeHandlers>(this: T, name: &str) -> bool {
fn has_class<T: AttributeHandlers>(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)
}
}

Просмотреть файл

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

Просмотреть файл

@ -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<Element> = 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,

Просмотреть файл

@ -68,7 +68,7 @@ impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> {
fn SetWidth(self, width: u32) {
let elem: JSRef<Element> = 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<Element> = ElementCast::from_ref(self);
elem.set_uint_attribute("height", height)
elem.set_uint_attribute(&atom!("height"), height)
}
fn GetContext(self, id: DOMString) -> Option<Temporary<CanvasRenderingContext2D>> {

Просмотреть файл

@ -139,15 +139,17 @@ impl HTMLCollection {
-> Temporary<HTMLCollection> {
#[jstraceable]
struct ClassNameFilter {
classes: Vec<DOMString>
classes: Vec<Atom>
}
impl CollectionFilter for ClassNameFilter {
fn filter(&self, elem: JSRef<Element>, _root: JSRef<Node>) -> bool {
self.classes.iter().all(|class| elem.has_class(class.as_slice()))
self.classes.iter().all(|class| elem.has_class(class))
}
}
let filter = ClassNameFilter {
classes: split_html_space_chars(classes.as_slice()).map(|class| class.to_string()).collect()
classes: split_html_space_chars(classes.as_slice()).map(|class| {
Atom::from_slice(class)
}).collect()
};
HTMLCollection::create(window, root, box filter)
}
@ -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))
}
}

Просмотреть файл

@ -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<Temporary<HTMLFormElement>>;
fn get_form_attribute(self, attr: &str,
fn get_form_attribute(self,
attr: &Atom,
input: |Self| -> DOMString,
owner: |JSRef<HTMLFormElement>| -> DOMString) -> DOMString {
if self.to_element().has_attribute(attr) {

Просмотреть файл

@ -87,7 +87,7 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
fn get_url(self) -> Option<Url> {
let element: JSRef<Element> = ElementCast::from_ref(self);
element.get_attribute(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<Element> = ElementCast::from_ref(self);
element.get_string_attribute("src")
element.get_string_attribute(&atom!("src"))
}
fn SetSrc(self, src: DOMString) {
let element: JSRef<Element> = ElementCast::from_ref(self);
element.set_url_attribute("src", src)
element.set_url_attribute(&atom!("src"), src)
}
fn Sandbox(self) -> DOMString {
let element: JSRef<Element> = ElementCast::from_ref(self);
element.get_string_attribute("sandbox")
element.get_string_attribute(&atom!("sandbox"))
}
fn SetSandbox(self, sandbox: DOMString) {
let element: JSRef<Element> = ElementCast::from_ref(self);
element.set_string_attribute("sandbox", sandbox);
element.set_string_attribute(&atom!("sandbox"), sandbox);
}
fn GetContentWindow(self) -> Option<Temporary<Window>> {

Просмотреть файл

@ -113,7 +113,7 @@ impl<'a> HTMLImageElementMethods for JSRef<'a, HTMLImageElement> {
fn SetIsMap(self, is_map: bool) {
let element: JSRef<Element> = 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<Element> = 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<Element> = 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);
}
}

Просмотреть файл

@ -232,7 +232,7 @@ impl<'a> HTMLInputElementHelpers for JSRef<'a, HTMLInputElement> {
fn get_radio_group(self) -> Option<String> {
//TODO: determine form owner
let elem: JSRef<Element> = 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<Temporary<HTMLFormElement>> {
// https://html.spec.whatwg.org/multipage/forms.html#reset-the-form-owner
let elem: JSRef<Element> = 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();

Просмотреть файл

@ -48,7 +48,7 @@ impl HTMLLinkElement {
}
}
fn get_attr(element: JSRef<Element>, name: &str) -> Option<String> {
fn get_attr(element: JSRef<Element>, name: &Atom) -> Option<String> {
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<Element> = 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<Element> = 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) => {

Просмотреть файл

@ -63,8 +63,8 @@ impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> {
let elem: JSRef<Element> = ElementCast::from_ref(*self);
// TODO: support other values
match (elem.get_attribute(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();

Просмотреть файл

@ -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<Element> = 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

Просмотреть файл

@ -75,7 +75,7 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[
impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> {
fn is_javascript(self) -> bool {
let element: JSRef<Element> = ElementCast::from_ref(self);
match element.get_attribute(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<Element> = ElementCast::from_ref(self);
element.get_url_attribute("src")
element.get_url_attribute(&atom!("src"))
}
// http://www.whatwg.org/html/#dom-script-text

Просмотреть файл

@ -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<Element> = ElementCast::from_ref(self);
if elem.has_attribute("multiple") {
if elem.has_attribute(&atom!("multiple")) {
"select-multiple".to_string()
} else {
"select-one".to_string()

Просмотреть файл

@ -11,7 +11,7 @@ macro_rules! make_getter(
#[allow(unused_imports)]
use std::ascii::StrAsciiExt;
let element: JSRef<Element> = 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<Element> = 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<Element> = 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<Element> = 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<Element> = 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<Element> = 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<Element> = 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<Element> = 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<Element> = 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)
}
);
)

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -481,7 +481,7 @@ pub fn parse_html(page: &Page,
};
let script_element: JSRef<Element> = 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();

Просмотреть файл

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

Просмотреть файл

@ -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;

Просмотреть файл

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

Просмотреть файл

@ -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)

Просмотреть файл

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