aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py23
-rw-r--r--components/script/dom/bindings/conversions.rs171
-rw-r--r--components/script/dom/webidls/Blob.webidl8
-rw-r--r--components/script/dom/webidls/WebSocket.webidl3
4 files changed, 153 insertions, 52 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index b11a7fe25c1..03a5bce5b0f 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -832,7 +832,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if treatNullAs not in treatAs:
raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs)
if type.nullable():
- nullBehavior = "()"
+ # Note: the actual behavior passed here doesn't matter for nullable
+ # strings.
+ nullBehavior = "StringificationBehavior::Default"
else:
nullBehavior = treatAs[treatNullAs]
@@ -1046,7 +1048,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % str(type))
- assert not isEnforceRange and not isClamp
+ if type.isInteger():
+ if isEnforceRange:
+ conversionBehavior = "ConversionBehavior::EnforceRange"
+ elif isClamp:
+ conversionBehavior = "ConversionBehavior::Clamp"
+ else:
+ conversionBehavior = "ConversionBehavior::Default"
+ else:
+ assert not isEnforceRange and not isClamp
+ conversionBehavior = "()"
if failureCode is None:
failureCode = 'return 0'
@@ -1055,12 +1066,11 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=">")
- # XXXjdm support conversionBehavior here
template = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
+ "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
" Ok(v) => v,\n"
" Err(_) => { %s }\n"
- "}" % exceptionCode)
+ "}" % (conversionBehavior, exceptionCode))
if defaultValue is not None:
if isinstance(defaultValue, IDLNullValue):
@@ -2002,6 +2012,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
'dom::bindings::codegen::PrototypeList',
'dom::bindings::conversions::FromJSValConvertible',
'dom::bindings::conversions::ToJSValConvertible',
+ 'dom::bindings::conversions::ConversionBehavior',
'dom::bindings::conversions::native_from_handlevalue',
'dom::bindings::conversions::StringificationBehavior',
'dom::bindings::error::throw_not_in_union',
@@ -5209,7 +5220,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
'dom::bindings::callback::wrap_call_this_object',
- 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}',
+ 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionBehavior}',
'dom::bindings::conversions::{native_from_reflector, native_from_handlevalue, native_from_handleobject}',
'dom::bindings::conversions::DOM_OBJECT_SLOT',
'dom::bindings::conversions::IDLInterface',
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index 9f6ed02a289..d1508060648 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -57,13 +57,54 @@ use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
use libc;
use num::Float;
+use num::traits::{Bounded, Zero};
use std::borrow::ToOwned;
-use std::default;
use std::slice;
use std::ptr;
use std::rc::Rc;
use core::nonzero::NonZero;
+trait As<O>: Copy {
+ fn cast(self) -> O;
+}
+
+macro_rules! impl_as {
+ ($I:ty, $O:ty) => (
+ impl As<$O> for $I {
+ fn cast(self) -> $O {
+ self as $O
+ }
+ }
+ )
+}
+
+impl_as!(f64, u8);
+impl_as!(f64, u16);
+impl_as!(f64, u32);
+impl_as!(f64, u64);
+impl_as!(f64, i8);
+impl_as!(f64, i16);
+impl_as!(f64, i32);
+impl_as!(f64, i64);
+
+impl_as!(u8, f64);
+impl_as!(u16, f64);
+impl_as!(u32, f64);
+impl_as!(u64, f64);
+impl_as!(i8, f64);
+impl_as!(i16, f64);
+impl_as!(i32, f64);
+impl_as!(i64, f64);
+
+impl_as!(i32, i8);
+impl_as!(i32, u8);
+impl_as!(i32, i16);
+impl_as!(u16, u16);
+impl_as!(i32, i32);
+impl_as!(u32, u32);
+impl_as!(i64, i64);
+impl_as!(u64, u64);
+
/// A trait to retrieve the constants necessary to check if a `JSObject`
/// implements a given interface.
pub trait IDLInterface {
@@ -91,6 +132,54 @@ pub trait FromJSValConvertible {
fn from_jsval(cx: *mut JSContext, val: HandleValue, option: Self::Config) -> Result<Self, ()>;
}
+/// Behavior for converting out-of-range integers.
+#[derive(PartialEq, Eq)]
+pub enum ConversionBehavior {
+ /// Wrap into the integer's range.
+ Default,
+ /// Throw an exception.
+ EnforceRange,
+ /// Clamp into the integer's range.
+ Clamp
+}
+
+/// Try to cast the number to a smaller type, but
+/// if it doesn't fit, it will return an error.
+fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<D, ()>
+ where D: Bounded + As<f64>,
+ f64: As<D>
+{
+ if d.is_infinite() {
+ throw_type_error(cx, "value out of range in an EnforceRange argument");
+ return Err(());
+ }
+
+ let rounded = d.round();
+ if D::min_value().cast() <= rounded && rounded <= D::max_value().cast() {
+ Ok(rounded.cast())
+ } else {
+ throw_type_error(cx, "value out of range in an EnforceRange argument");
+ Err(())
+ }
+}
+
+/// Try to cast the number to a smaller type, but if it doesn't fit,
+/// round it to the MAX or MIN of the source type before casting it to
+/// the destination type.
+fn clamp_to<D>(d: f64) -> D
+ where D: Bounded + As<f64> + Zero,
+ f64: As<D>
+{
+ if d.is_nan() {
+ D::zero()
+ } else if d > D::max_value().cast() {
+ D::max_value()
+ } else if d < D::min_value().cast() {
+ D::min_value()
+ } else {
+ d.cast()
+ }
+}
impl ToJSValConvertible for () {
fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
@@ -116,6 +205,22 @@ impl ToJSValConvertible for HandleValue {
}
}
+#[inline]
+fn convert_int_from_jsval<T, M>(cx: *mut JSContext, value: HandleValue,
+ option: ConversionBehavior,
+ convert_fn: fn(*mut JSContext, HandleValue) -> Result<M, ()>)
+ -> Result<T, ()>
+ where T: Bounded + Zero + As<f64>,
+ M: Zero + As<T>,
+ f64: As<T>
+{
+ match option {
+ ConversionBehavior::Default => Ok(try!(convert_fn(cx, value)).cast()),
+ ConversionBehavior::EnforceRange => enforce_range(cx, try!(ToNumber(cx, value))),
+ ConversionBehavior::Clamp => Ok(clamp_to(try!(ToNumber(cx, value)))),
+ }
+}
+
impl ToJSValConvertible for bool {
fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
rval.set(BooleanValue(*self));
@@ -136,10 +241,9 @@ impl ToJSValConvertible for i8 {
}
impl FromJSValConvertible for i8 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i8, ()> {
- let result = ToInt32(cx, val);
- result.map(|v| v as i8)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<i8, ()> {
+ convert_int_from_jsval(cx, val, option, ToInt32)
}
}
@@ -150,10 +254,9 @@ impl ToJSValConvertible for u8 {
}
impl FromJSValConvertible for u8 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u8, ()> {
- let result = ToInt32(cx, val);
- result.map(|v| v as u8)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<u8, ()> {
+ convert_int_from_jsval(cx, val, option, ToInt32)
}
}
@@ -164,10 +267,9 @@ impl ToJSValConvertible for i16 {
}
impl FromJSValConvertible for i16 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i16, ()> {
- let result = ToInt32(cx, val);
- result.map(|v| v as i16)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<i16, ()> {
+ convert_int_from_jsval(cx, val, option, ToInt32)
}
}
@@ -178,9 +280,9 @@ impl ToJSValConvertible for u16 {
}
impl FromJSValConvertible for u16 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u16, ()> {
- ToUint16(cx, val)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<u16, ()> {
+ convert_int_from_jsval(cx, val, option, ToUint16)
}
}
@@ -191,9 +293,9 @@ impl ToJSValConvertible for i32 {
}
impl FromJSValConvertible for i32 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i32, ()> {
- ToInt32(cx, val)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<i32, ()> {
+ convert_int_from_jsval(cx, val, option, ToInt32)
}
}
@@ -204,9 +306,9 @@ impl ToJSValConvertible for u32 {
}
impl FromJSValConvertible for u32 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u32, ()> {
- ToUint32(cx, val)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<u32, ()> {
+ convert_int_from_jsval(cx, val, option, ToUint32)
}
}
@@ -219,9 +321,9 @@ impl ToJSValConvertible for i64 {
}
impl FromJSValConvertible for i64 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i64, ()> {
- ToInt64(cx, val)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<i64, ()> {
+ convert_int_from_jsval(cx, val, option, ToInt64)
}
}
@@ -234,9 +336,9 @@ impl ToJSValConvertible for u64 {
}
impl FromJSValConvertible for u64 {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u64, ()> {
- ToUint64(cx, val)
+ type Config = ConversionBehavior;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: ConversionBehavior) -> Result<u64, ()> {
+ convert_int_from_jsval(cx, val, option, ToUint64)
}
}
@@ -323,12 +425,6 @@ pub enum StringificationBehavior {
Empty,
}
-impl default::Default for StringificationBehavior {
- fn default() -> StringificationBehavior {
- StringificationBehavior::Default
- }
-}
-
/// Convert the given `JSString` to a `DOMString`. Fails if the string does not
/// contain valid UTF-16.
pub fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString {
@@ -666,13 +762,12 @@ impl<T: ToJSValConvertible> ToJSValConvertible for Option<Rc<T>> {
}
}
-impl<X: default::Default, T: FromJSValConvertible<Config=X>> FromJSValConvertible for Option<T> {
- type Config = ();
- fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) -> Result<Option<T>, ()> {
+impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
+ type Config = T::Config;
+ fn from_jsval(cx: *mut JSContext, value: HandleValue, option: T::Config) -> Result<Option<T>, ()> {
if value.get().is_null_or_undefined() {
Ok(None)
} else {
- let option: X = default::Default::default();
let result: Result<T, ()> = FromJSValConvertible::from_jsval(cx, value, option);
result.map(Some)
}
diff --git a/components/script/dom/webidls/Blob.webidl b/components/script/dom/webidls/Blob.webidl
index 70bbdc8c9ef..6d91f65b1f5 100644
--- a/components/script/dom/webidls/Blob.webidl
+++ b/components/script/dom/webidls/Blob.webidl
@@ -16,12 +16,8 @@ interface Blob {
//slice Blob into byte-ranged chunks
- //TODO: implement slice with [Clamp]
- //Blob slice([Clamp] optional long long start,
- // [Clamp] optional long long end,
- // optional DOMString contentType);
- Blob slice(optional long long start,
- optional long long end,
+ Blob slice([Clamp] optional long long start,
+ [Clamp] optional long long end,
optional DOMString contentType);
//void close();
diff --git a/components/script/dom/webidls/WebSocket.webidl b/components/script/dom/webidls/WebSocket.webidl
index 3fd2fcd403d..20a710168e8 100644
--- a/components/script/dom/webidls/WebSocket.webidl
+++ b/components/script/dom/webidls/WebSocket.webidl
@@ -21,8 +21,7 @@ interface WebSocket : EventTarget {
attribute EventHandler onclose;
//readonly attribute DOMString extensions;
//readonly attribute DOMString protocol;
- //[Throws] void close([Clamp] optional unsigned short code, optional USVString reason); //Clamp doesn't work
- [Throws] void close(optional unsigned short code, optional USVString reason); //No clamp version - works
+ [Throws] void close([Clamp] optional unsigned short code, optional USVString reason);
//messaging
//attribute EventHandler onmessage;