auto merge of #4467 : servo/servo/dataset, r=Ms2ger

This commit is contained in:
bors-servo 2014-12-25 02:27:43 -07:00
commit 0e6304dcf7
33 changed files with 206 additions and 218 deletions

View file

@ -2086,20 +2086,23 @@ class CGDefineProxyHandler(CGAbstractMethod):
return CGAbstractMethod.define(self)
def definition_body(self):
customDefineProperty = 'defineProperty_'
if self.descriptor.operations['IndexedSetter'] or self.descriptor.operations['NamedSetter']:
customDefineProperty = 'defineProperty'
body = """\
let traps = ProxyTraps {
getPropertyDescriptor: Some(getPropertyDescriptor),
getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
defineProperty: Some(defineProperty_),
getOwnPropertyNames: ptr::null(),
defineProperty: Some(%s),
getOwnPropertyNames: Some(getOwnPropertyNames_),
delete_: Some(delete_),
enumerate: ptr::null(),
enumerate: Some(enumerate_),
has: None,
hasOwn: Some(hasOwn),
get: Some(get),
set: None,
keys: ptr::null(),
keys: None,
iterate: None,
call: None,
@ -2120,7 +2123,7 @@ let traps = ProxyTraps {
};
CreateProxyHandler(&traps, &Class as *const _ as *const _)
""" % (FINALIZE_HOOK_NAME,
""" % (customDefineProperty, FINALIZE_HOOK_NAME,
TRACE_HOOK_NAME)
return CGGeneric(body)
@ -2276,8 +2279,15 @@ class CGPerSignatureCall(CGThing):
invalidEnumValueFatal=not setter) for
i in range(argConversionStartsAt, self.argCount)])
errorResult = None
if self.isFallible():
if nativeMethodName == "NamedSetter":
errorResult = " false"
else:
errorResult = " false as JSBool"
cgThings.append(CGCallGenerator(
' false as JSBool' if self.isFallible() else None,
errorResult,
self.getArguments(), self.argsPre, returnType,
self.extendedAttributes, descriptor, nativeMethodName,
static))
@ -3836,14 +3846,14 @@ if expando.is_not_null() {
getIndexedOrExpando = getFromExpando + "\n"
namedGetter = self.descriptor.operations['NamedGetter']
if namedGetter and False: #XXXjdm unfinished
getNamed = ("if (JSID_IS_STRING(id)) {\n" +
if namedGetter:
getNamed = ("if (RUST_JSID_IS_STRING(id) != 0) {\n" +
" let name = jsid_to_str(cx, id);\n" +
" let this = UnwrapProxy(proxy);\n" +
" let this = JS::from_raw(this);\n" +
" let this = this.root();\n" +
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
"}\n") % (self.descriptor.concreteType)
"}\n")
else:
getNamed = ""
@ -4522,6 +4532,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::proxyhandler::{_obj_toString, defineProperty_}',
'dom::bindings::proxyhandler::{FillPropertyDescriptor, GetExpandoObject}',
'dom::bindings::proxyhandler::{delete_, getPropertyDescriptor}',
'dom::bindings::proxyhandler::{getOwnPropertyNames_, enumerate_}',
'dom::bindings::str::ByteString',
'page::JSPageInfo',
'libc',

View file

@ -16,6 +16,7 @@ use js::glue::GetProxyExtra;
use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler};
use js::glue::InvokeGetOwnPropertyDescriptor;
use js::glue::RUST_js_GetErrorMessage;
use js::glue::AutoIdVector;
use js::{JSPROP_GETTER, JSPROP_ENUMERATE, JSPROP_READONLY, JSRESOLVE_QUALIFIED};
use libc;
@ -130,3 +131,14 @@ pub fn FillPropertyDescriptor(desc: &mut JSPropertyDescriptor, obj: *mut JSObjec
desc.setter = None;
desc.shortid = 0;
}
pub unsafe extern fn getOwnPropertyNames_(_cx: *mut JSContext,
_obj: *mut JSObject,
_v: *mut AutoIdVector) -> bool {
true
}
pub unsafe extern fn enumerate_(_cx: *mut JSContext, _obj: *mut JSObject,
_v: *mut AutoIdVector) -> bool {
true
}

View file

@ -84,15 +84,15 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps {
getPropertyDescriptor: None,
getOwnPropertyDescriptor: None,
defineProperty: None,
getOwnPropertyNames: 0 as *const u8,
getOwnPropertyNames: None,
delete_: None,
enumerate: 0 as *const u8,
enumerate: None,
has: None,
hasOwn: None,
get: None,
set: None,
keys: 0 as *const u8,
keys: None,
iterate: None,
call: None,

View file

@ -2,51 +2,56 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DOMStringMapBinding;
use dom::bindings::codegen::Bindings::DOMStringMapBinding::DOMStringMapMethods;
use dom::bindings::error::ErrorResult;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::node::window_from_node;
use dom::htmlelement::{HTMLElement, HTMLElementCustomAttributeHelpers};
use servo_util::str::DOMString;
use std::collections::HashMap;
#[dom_struct]
pub struct DOMStringMap {
map: DOMRefCell<HashMap<DOMString, DOMString>>,
reflector_: Reflector,
element: JS<HTMLElement>,
}
impl DOMStringMap {
fn new_inherited() -> DOMStringMap {
fn new_inherited(element: JSRef<HTMLElement>) -> DOMStringMap {
DOMStringMap {
map: DOMRefCell::new(HashMap::new()),
reflector_: Reflector::new(),
element: JS::from_rooted(element),
}
}
pub fn new(global: GlobalRef) -> Temporary<DOMStringMap> {
reflect_dom_object(box DOMStringMap::new_inherited(),
global, DOMStringMapBinding::Wrap)
pub fn new(element: JSRef<HTMLElement>) -> Temporary<DOMStringMap> {
let window = window_from_node(element).root();
reflect_dom_object(box DOMStringMap::new_inherited(element),
GlobalRef::Window(window.root_ref()), DOMStringMapBinding::Wrap)
}
}
// https://html.spec.whatwg.org/#domstringmap
impl<'a> DOMStringMapMethods for JSRef<'a, DOMStringMap> {
fn NamedCreator(self, name: DOMString, value: DOMString) {
self.map.borrow_mut().insert(name, value);
fn NamedCreator(self, name: DOMString, value: DOMString) -> ErrorResult {
self.NamedSetter(name, value)
}
fn NamedDeleter(self, name: DOMString) {
self.map.borrow_mut().remove(&name);
let element = self.element.root();
element.delete_custom_attr(name)
}
fn NamedSetter(self, name: DOMString, value: DOMString) {
self.map.borrow_mut().insert(name, value);
fn NamedSetter(self, name: DOMString, value: DOMString) -> ErrorResult {
let element = self.element.root();
element.set_custom_attr(name, value)
}
fn NamedGetter(self, name: DOMString, found: &mut bool) -> DOMString {
match self.map.borrow().get(&name) {
let element = self.element.root();
match element.get_custom_attr(name) {
Some(value) => {
*found = true;
value.clone()

View file

@ -465,6 +465,7 @@ pub enum StylePriority {
pub trait ElementHelpers<'a> {
fn html_element_in_html_document(self) -> bool;
fn local_name(self) -> &'a Atom;
fn parsed_name(self, name: DOMString) -> DOMString;
fn namespace(self) -> &'a Namespace;
fn prefix(self) -> &'a Option<DOMString>;
fn attrs(&self) -> Ref<Vec<JS<Attr>>>;
@ -488,6 +489,15 @@ impl<'a> ElementHelpers<'a> for JSRef<'a, Element> {
&self.extended_deref().local_name
}
// https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
fn parsed_name(self, name: DOMString) -> DOMString {
if self.html_element_in_html_document() {
name.as_slice().to_ascii_lower()
} else {
name
}
}
fn namespace(self) -> &'a Namespace {
&self.extended_deref().namespace
}
@ -626,6 +636,7 @@ pub trait AttributeHandlers {
value: DOMString,
prefix: Option<DOMString>);
fn set_attribute(self, name: &Atom, value: AttrValue);
fn set_custom_attribute(self, name: DOMString, value: DOMString) -> ErrorResult;
fn do_set_attribute(self, local_name: Atom, value: AttrValue,
name: Atom, namespace: Namespace,
prefix: Option<DOMString>, cb: |JSRef<Attr>| -> bool);
@ -695,6 +706,23 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
ns!(""), None, |attr| *attr.local_name() == *name);
}
// https://html.spec.whatwg.org/multipage/dom.html#attr-data-*
fn set_custom_attribute(self, name: DOMString, value: DOMString) -> ErrorResult {
// Step 1.
match xml_name_type(name.as_slice()) {
InvalidXMLName => return Err(InvalidCharacter),
_ => {}
}
// Steps 2-5.
let name = Atom::from_slice(name.as_slice());
let value = self.parse_attribute(&ns!(""), &name, value);
self.do_set_attribute(name.clone(), value, name.clone(), ns!(""), None, |attr| {
*attr.name() == name && *attr.namespace() == ns!("")
});
Ok(())
}
fn do_set_attribute(self, local_name: Atom, value: AttrValue,
name: Atom, namespace: Namespace,
prefix: Option<DOMString>, cb: |JSRef<Attr>| -> bool) {
@ -919,11 +947,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
// http://dom.spec.whatwg.org/#dom-element-getattribute
fn GetAttribute(self, name: DOMString) -> Option<DOMString> {
let name = if self.html_element_in_html_document() {
name.as_slice().to_ascii_lower()
} else {
name
};
let name = self.parsed_name(name);
self.get_attribute(ns!(""), &Atom::from_slice(name.as_slice())).root()
.map(|s| s.Value())
}
@ -948,17 +972,13 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
}
// Step 2.
let name = if self.html_element_in_html_document() {
name.as_slice().to_ascii_lower()
} else {
name
};
let name = self.parsed_name(name);
// Step 3-5.
let name = Atom::from_slice(name.as_slice());
let value = self.parse_attribute(&ns!(""), &name, value);
self.do_set_attribute(name.clone(), value, name.clone(), ns!(""), None, |attr| {
attr.name().as_slice() == name.as_slice()
*attr.name() == name
});
Ok(())
}
@ -1029,11 +1049,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
// http://dom.spec.whatwg.org/#dom-element-removeattribute
fn RemoveAttribute(self, name: DOMString) {
let name = if self.html_element_in_html_document() {
name.as_slice().to_ascii_lower()
} else {
name
};
let name = self.parsed_name(name);
self.remove_attribute(ns!(""), name.as_slice())
}

View file

@ -13,10 +13,13 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDeriv
use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
use dom::bindings::js::{JSRef, Temporary, MutNullableJS};
use dom::bindings::error::ErrorResult;
use dom::bindings::error::Error::Syntax;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::cssstyledeclaration::CSSStyleDeclaration;
use dom::document::Document;
use dom::element::{Element, ElementTypeId, ActivationElementHelpers};
use dom::domstringmap::DOMStringMap;
use dom::element::{Element, ElementTypeId, ActivationElementHelpers, AttributeHandlers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use dom::node::{Node, NodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
@ -31,6 +34,7 @@ use std::default::Default;
pub struct HTMLElement {
element: Element,
style_decl: MutNullableJS<CSSStyleDeclaration>,
dataset: MutNullableJS<DOMStringMap>,
}
impl HTMLElementDerived for EventTarget {
@ -48,6 +52,7 @@ impl HTMLElement {
HTMLElement {
element: Element::new_inherited(type_id, tag_name, ns!(HTML), prefix, document),
style_decl: Default::default(),
dataset: Default::default(),
}
}
@ -89,6 +94,11 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
global_event_handlers!(NoOnload)
// https://html.spec.whatwg.org/multipage/dom.html#dom-dataset
fn Dataset(self) -> Temporary<DOMStringMap> {
self.dataset.or_init(|| DOMStringMap::new(self))
}
fn GetOnload(self) -> Option<EventHandlerNonNull> {
if self.is_body_or_frameset() {
let win = window_from_node(self).root();
@ -122,6 +132,51 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
}
}
// https://html.spec.whatwg.org/#attr-data-*
pub trait HTMLElementCustomAttributeHelpers {
fn set_custom_attr(self, name: DOMString, value: DOMString) -> ErrorResult;
fn get_custom_attr(self, name: DOMString) -> Option<DOMString>;
fn delete_custom_attr(self, name: DOMString);
}
fn to_snake_case(name: DOMString) -> DOMString {
let mut attr_name = "data-".into_string();
for ch in name.as_slice().chars() {
if ch.is_uppercase() {
attr_name.push('\x2d');
attr_name.push(ch.to_lowercase());
} else {
attr_name.push(ch);
}
}
attr_name
}
impl<'a> HTMLElementCustomAttributeHelpers for JSRef<'a, HTMLElement> {
fn set_custom_attr(self, name: DOMString, value: DOMString) -> ErrorResult {
if name.as_slice().chars()
.skip_while(|&ch| ch != '\u002d')
.nth(1).map_or(false, |ch| ch as u8 - b'a' < 26) {
return Err(Syntax);
}
let element: JSRef<Element> = ElementCast::from_ref(self);
element.set_custom_attribute(to_snake_case(name), value)
}
fn get_custom_attr(self, name: DOMString) -> Option<DOMString> {
let element: JSRef<Element> = ElementCast::from_ref(self);
element.get_attribute(ns!(""), &Atom::from_slice(to_snake_case(name).as_slice())).map(|attr| {
let attr = attr.root();
attr.value().as_slice().to_string()
})
}
fn delete_custom_attr(self, name: DOMString) {
let element: JSRef<Element> = ElementCast::from_ref(self);
element.remove_attribute(ns!(""), to_snake_case(name).as_slice())
}
}
impl<'a> VirtualMethods for JSRef<'a, HTMLElement> {
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
let element: &JSRef<Element> = ElementCast::from_borrowed_ref(self);

View file

@ -7,6 +7,7 @@
[OverrideBuiltins]
interface DOMStringMap {
getter DOMString (DOMString name);
[Throws]
setter creator void (DOMString name, DOMString value);
deleter void (DOMString name);
};

View file

@ -10,7 +10,7 @@ interface HTMLElement : Element {
attribute DOMString lang;
// attribute boolean translate;
// attribute DOMString dir;
//readonly attribute DOMStringMap dataset;
readonly attribute DOMStringMap dataset;
// microdata
// attribute boolean itemScope;

View file

@ -41,8 +41,8 @@ macro_rules! sizeof_checker (
sizeof_checker!(size_event_target, EventTarget, 56)
sizeof_checker!(size_node, Node, 304)
sizeof_checker!(size_element, Element, 448)
sizeof_checker!(size_htmlelement, HTMLElement, 464)
sizeof_checker!(size_div, HTMLDivElement, 464)
sizeof_checker!(size_span, HTMLSpanElement, 464)
sizeof_checker!(size_htmlelement, HTMLElement, 480)
sizeof_checker!(size_div, HTMLDivElement, 480)
sizeof_checker!(size_span, HTMLSpanElement, 480)
sizeof_checker!(size_text, Text, 336)
sizeof_checker!(size_characterdata, CharacterData, 336)

View file

@ -412,7 +412,7 @@ dependencies = [
[[package]]
name = "js"
version = "0.1.0"
source = "git+https://github.com/servo/rust-mozjs#e04e7307a3e52f46bc9ba3d5682188285110bc67"
source = "git+https://github.com/servo/rust-mozjs#2d86d6fb7ece49ff2f469c391e15e13f2b02af42"
dependencies = [
"mozjs-sys 0.0.0 (git+https://github.com/servo/mozjs)",
]