diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 31 | ||||
-rw-r--r-- | components/script/dom/bindings/conversions.rs | 17 | ||||
-rw-r--r-- | components/script/dom/bindings/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/mozmap.rs | 109 | ||||
-rw-r--r-- | components/script/dom/testbinding.rs | 28 | ||||
-rw-r--r-- | components/script/dom/webidls/TestBinding.webidl | 28 |
6 files changed, 207 insertions, 7 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 654714ec204..ca7901a56e3 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -93,13 +93,15 @@ def stripTrailingWhitespace(text): def innerContainerType(type): - assert type.isSequence() + assert type.isSequence() or type.isMozMap() return type.inner.inner if type.nullable() else type.inner def wrapInNativeContainerType(type, inner): if type.isSequence(): containerType = "Vec" + elif type.isMozMap(): + containerType = "MozMap" else: raise TypeError("Unexpected container type %s", type) @@ -733,7 +735,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.isArray(): raise TypeError("Can't handle array arguments yet") - if type.isSequence(): + if type.isSequence() or type.isMozMap(): innerInfo = getJSToNativeConversionInfo(innerContainerType(type), descriptorProvider, isMember=isMember) @@ -1274,7 +1276,7 @@ def typeNeedsCx(type, retVal=False): # Returns a conversion behavior suitable for a type def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs): - if type.isSequence(): + if type.isSequence() or type.isMozMap(): return getConversionConfigForType(innerContainerType(type), isEnforceRange, isClamp, treatNullAs) if type.isDOMString(): assert not isEnforceRange and not isClamp @@ -1359,7 +1361,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result - if returnType.isSequence(): + if returnType.isSequence() or returnType.isMozMap(): result = getRetvalDeclarationForType(innerContainerType(returnType), descriptorProvider) result = wrapInNativeContainerType(returnType, result) if returnType.nullable(): @@ -1894,6 +1896,8 @@ class CGImports(CGWrapper): parentName = getIdentifier(descriptor.interface.parent).name descriptor = descriptorProvider.getDescriptor(parentName) extras += [descriptor.path, descriptor.bindingPath] + elif t.isType() and t.isMozMap(): + extras += ['dom::bindings::mozmap::MozMap'] else: if t.isEnum(): extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values'] @@ -2186,6 +2190,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', 'dom::bindings::js::Root', + 'dom::bindings::mozmap::MozMap', 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', 'dom::bindings::str::USVString', @@ -4004,7 +4009,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isEnum(): name = type.inner.identifier.name typeName = name - elif type.isSequence(): + elif type.isSequence() or type.isMozMap(): name = type.name inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider) typeName = wrapInNativeContainerType(type, CGGeneric(inner["typeName"])).define() @@ -4153,14 +4158,25 @@ class CGUnionConversionStruct(CGThing): else: object = None - hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object + mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes) + if len(mozMapMemberTypes) > 0: + assert len(mozMapMemberTypes) == 1 + typeName = mozMapMemberTypes[0].name + mozMapObject = CGGeneric(get_match(typeName)) + names.append(typeName) + else: + mozMapObject = None + + hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object or mozMapObject if hasObjectTypes: - assert interfaceObject or arrayObject + assert interfaceObject or arrayObject or mozMapObject templateBody = CGList([], "\n") if interfaceObject: templateBody.append(interfaceObject) if arrayObject: templateBody.append(arrayObject) + if mozMapObject: + templateBody.append(mozMapObject) conversions.append(CGIfWrapper("value.get().is_object()", templateBody)) stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()] numericTypes = [t for t in memberTypes if t.isNumeric()] @@ -5545,6 +5561,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::proxyhandler::fill_property_descriptor', 'dom::bindings::proxyhandler::get_expando_object', 'dom::bindings::proxyhandler::get_property_descriptor', + 'dom::bindings::mozmap::MozMap', 'dom::bindings::num::Finite', 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index bb29b9904a1..55c3c41f460 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -44,6 +44,7 @@ pub use js::conversions::ConversionBehavior; use js::conversions::latin1_to_string; use js::error::throw_type_error; use js::glue::{GetProxyPrivate, IsWrapper}; +use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT}; use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject}; use js::jsapi::{HandleId, HandleObject, HandleValue, JSClass, JSContext}; use js::jsapi::{JSObject, JSString, JS_GetArrayBufferViewType, JS_GetClass}; @@ -129,6 +130,22 @@ pub fn string_jsid_to_string(cx: *mut JSContext, id: HandleId) -> DOMString { } } +/// Convert `id` to a `DOMString`. Returns `None` if `id` is not a string or +/// integer. +/// +/// Handling of invalid UTF-16 in strings depends on the relevant option. +pub unsafe fn jsid_to_string(cx: *mut JSContext, id: HandleId) -> Option<DOMString> { + if RUST_JSID_IS_STRING(id) { + return Some(jsstring_to_str(cx, RUST_JSID_TO_STRING(id))); + } + + if RUST_JSID_IS_INT(id) { + return Some(RUST_JSID_TO_INT(id).to_string().into()); + } + + None +} + // http://heycam.github.io/webidl/#es-USVString impl ToJSValConvertible for USVString { unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index 16607c9045f..4cb10add852 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -140,6 +140,7 @@ pub mod inheritance; pub mod interface; pub mod iterable; pub mod js; +pub mod mozmap; pub mod namespace; pub mod num; pub mod proxyhandler; diff --git a/components/script/dom/bindings/mozmap.rs b/components/script/dom/bindings/mozmap.rs new file mode 100644 index 00000000000..557ba0662a0 --- /dev/null +++ b/components/script/dom/bindings/mozmap.rs @@ -0,0 +1,109 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +//! The `MozMap` (open-ended dictionary) type. + +use dom::bindings::conversions::jsid_to_string; +use dom::bindings::str::DOMString; +use js::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionResult}; +use js::jsapi::GetPropertyKeys; +use js::jsapi::HandleValue; +use js::jsapi::JSContext; +use js::jsapi::JSITER_OWNONLY; +use js::jsapi::JSPROP_ENUMERATE; +use js::jsapi::JS_DefineUCProperty2; +use js::jsapi::JS_GetPropertyById; +use js::jsapi::JS_NewPlainObject; +use js::jsapi::MutableHandleValue; +use js::jsval::ObjectValue; +use js::jsval::UndefinedValue; +use js::rust::IdVector; +use std::collections::HashMap; +use std::ops::Deref; + +/// The `MozMap` (open-ended dictionary) type. +pub struct MozMap<T> { + map: HashMap<DOMString, T>, +} + +impl<T> MozMap<T> { + /// Create an empty `MozMap`. + pub fn new() -> Self { + MozMap { + map: HashMap::new(), + } + } +} + +impl<T> Deref for MozMap<T> { + type Target = HashMap<DOMString, T>; + + fn deref(&self) -> &HashMap<DOMString, T> { + &self.map + } +} + +impl<T, C> FromJSValConvertible for MozMap<T> + where T: FromJSValConvertible<Config=C>, + C: Clone, +{ + type Config = C; + unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, config: C) + -> Result<ConversionResult<Self>, ()> { + if !value.is_object() { + return Ok(ConversionResult::Failure("MozMap value was not an object".into())); + } + + rooted!(in(cx) let object = value.to_object()); + let ids = IdVector::new(cx); + assert!(GetPropertyKeys(cx, object.handle(), JSITER_OWNONLY, ids.get())); + + let mut map = HashMap::new(); + for id in &*ids { + rooted!(in(cx) let id = *id); + + rooted!(in(cx) let mut property = UndefinedValue()); + if !JS_GetPropertyById(cx, object.handle(), id.handle(), property.handle_mut()) { + return Err(()); + } + + let property = match try!(T::from_jsval(cx, property.handle(), config.clone())) { + ConversionResult::Success(property) => property, + ConversionResult::Failure(message) => return Ok(ConversionResult::Failure(message)), + }; + + let key = jsid_to_string(cx, id.handle()).unwrap(); + map.insert(key, property); + } + + Ok(ConversionResult::Success(MozMap { + map: map, + })) + } +} + +impl<T: ToJSValConvertible> ToJSValConvertible for MozMap<T> { + #[inline] + unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + rooted!(in(cx) let js_object = JS_NewPlainObject(cx)); + assert!(!js_object.handle().is_null()); + + rooted!(in(cx) let mut js_value = UndefinedValue()); + for (key, value) in &self.map { + let key = key.encode_utf16().collect::<Vec<_>>(); + value.to_jsval(cx, js_value.handle_mut()); + + assert!(JS_DefineUCProperty2(cx, + js_object.handle(), + key.as_ptr(), + key.len(), + js_value.handle(), + JSPROP_ENUMERATE, + None, + None)); + } + + rval.set(ObjectValue(&*js_object.handle().get())); + } +} diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index b9e34ebe0a7..566ff2d9375 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -10,6 +10,7 @@ use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::TestBindingBinding; use dom::bindings::codegen::Bindings::TestBindingBinding::{TestBindingMethods, TestDictionary}; use dom::bindings::codegen::Bindings::TestBindingBinding::{TestDictionaryDefaults, TestEnum}; +use dom::bindings::codegen::UnionTypes; use dom::bindings::codegen::UnionTypes::{BlobOrBoolean, BlobOrBlobSequence, LongOrLongSequenceSequence}; use dom::bindings::codegen::UnionTypes::{BlobOrString, BlobOrUnsignedLong, EventOrString}; use dom::bindings::codegen::UnionTypes::{ByteStringOrLong, ByteStringSequenceOrLongOrString}; @@ -21,6 +22,7 @@ use dom::bindings::codegen::UnionTypes::{StringOrUnsignedLong, StringOrBoolean, use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; +use dom::bindings::mozmap::MozMap; use dom::bindings::num::Finite; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString, USVString}; @@ -619,6 +621,32 @@ impl TestBindingMethods for TestBinding { fn FuncControlledMethodDisabled(&self) {} fn FuncControlledMethodEnabled(&self) {} + fn PassMozMap(&self, _: MozMap<i32>) {} + fn PassNullableMozMap(&self, _: Option<MozMap<i32> >) {} + fn PassMozMapOfNullableInts(&self, _: MozMap<Option<i32>>) {} + fn PassOptionalMozMapOfNullableInts(&self, _: Option<MozMap<Option<i32>>>) {} + fn PassOptionalNullableMozMapOfNullableInts(&self, _: Option<Option<MozMap<Option<i32>> >>) {} + fn PassCastableObjectMozMap(&self, _: MozMap<Root<TestBinding>>) {} + fn PassNullableCastableObjectMozMap(&self, _: MozMap<Option<Root<TestBinding>>>) {} + fn PassCastableObjectNullableMozMap(&self, _: Option<MozMap<Root<TestBinding>>>) {} + fn PassNullableCastableObjectNullableMozMap(&self, _: Option<MozMap<Option<Root<TestBinding>>>>) {} + fn PassOptionalMozMap(&self, _: Option<MozMap<i32>>) {} + fn PassOptionalNullableMozMap(&self, _: Option<Option<MozMap<i32>>>) {} + fn PassOptionalNullableMozMapWithDefaultValue(&self, _: Option<MozMap<i32>>) {} + fn PassOptionalObjectMozMap(&self, _: Option<MozMap<Root<TestBinding>>>) {} + fn PassStringMozMap(&self, _: MozMap<DOMString>) {} + fn PassByteStringMozMap(&self, _: MozMap<ByteString>) {} + fn PassMozMapOfMozMaps(&self, _: MozMap<MozMap<i32>>) {} + fn PassMozMapUnion(&self, _: UnionTypes::LongOrByteStringMozMap) {} + fn PassMozMapUnion2(&self, _: UnionTypes::TestBindingOrByteStringMozMap) {} + fn PassMozMapUnion3(&self, _: UnionTypes::TestBindingOrByteStringSequenceSequenceOrByteStringMozMap) {} + fn ReceiveMozMap(&self) -> MozMap<i32> { MozMap::new() } + fn ReceiveNullableMozMap(&self) -> Option<MozMap<i32>> { Some(MozMap::new()) } + fn ReceiveMozMapOfNullableInts(&self) -> MozMap<Option<i32>> { MozMap::new() } + fn ReceiveNullableMozMapOfNullableInts(&self) -> Option<MozMap<Option<i32>>> { Some(MozMap::new()) } + fn ReceiveMozMapOfMozMaps(&self) -> MozMap<MozMap<i32>> { MozMap::new() } + fn ReceiveAnyMozMap(&self) -> MozMap<JSVal> { MozMap::new() } + fn PassSequenceSequence(&self, _seq: Vec<Vec<i32>>) {} fn ReturnSequenceSequence(&self) -> Vec<Vec<i32>> { vec![] } fn PassUnionSequenceSequence(&self, seq: LongOrLongSequenceSequence) { diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index d98b9428031..e35b914d08e 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -429,6 +429,34 @@ interface TestBinding { sequence<sequence<long>> returnSequenceSequence(); void passUnionSequenceSequence((long or sequence<sequence<long>>) seq); + void passMozMap(MozMap<long> arg); + void passNullableMozMap(MozMap<long>? arg); + void passMozMapOfNullableInts(MozMap<long?> arg); + void passOptionalMozMapOfNullableInts(optional MozMap<long?> arg); + void passOptionalNullableMozMapOfNullableInts(optional MozMap<long?>? arg); + void passCastableObjectMozMap(MozMap<TestBinding> arg); + void passNullableCastableObjectMozMap(MozMap<TestBinding?> arg); + void passCastableObjectNullableMozMap(MozMap<TestBinding>? arg); + void passNullableCastableObjectNullableMozMap(MozMap<TestBinding?>? arg); + void passOptionalMozMap(optional MozMap<long> arg); + void passOptionalNullableMozMap(optional MozMap<long>? arg); + void passOptionalNullableMozMapWithDefaultValue(optional MozMap<long>? arg = null); + void passOptionalObjectMozMap(optional MozMap<TestBinding> arg); + void passStringMozMap(MozMap<DOMString> arg); + void passByteStringMozMap(MozMap<ByteString> arg); + void passMozMapOfMozMaps(MozMap<MozMap<long>> arg); + + void passMozMapUnion((long or MozMap<ByteString>) init); + void passMozMapUnion2((TestBinding or MozMap<ByteString>) init); + void passMozMapUnion3((TestBinding or sequence<sequence<ByteString>> or MozMap<ByteString>) init); + + MozMap<long> receiveMozMap(); + MozMap<long>? receiveNullableMozMap(); + MozMap<long?> receiveMozMapOfNullableInts(); + MozMap<long?>? receiveNullableMozMapOfNullableInts(); + MozMap<MozMap<long>> receiveMozMapOfMozMaps(); + MozMap<any> receiveAnyMozMap(); + static attribute boolean booleanAttributeStatic; static void receiveVoidStatic(); boolean BooleanMozPreference(DOMString pref_name); |