aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/interface.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/bindings/interface.rs')
-rw-r--r--components/script/dom/bindings/interface.rs331
1 files changed, 135 insertions, 196 deletions
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs
index 1e21c3db651..f7786163cc5 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script/dom/bindings/interface.rs
@@ -6,6 +6,7 @@
use dom::bindings::codegen::InterfaceObjectMap::Globals;
use dom::bindings::codegen::PrototypeList;
+use dom::bindings::constant::{ConstantSpec, define_constants};
use dom::bindings::conversions::{DOM_OBJECT_SLOT, get_dom_class};
use dom::bindings::guard::Guard;
use dom::bindings::utils::{DOM_PROTOTYPE_SLOT, ProtoOrIfaceArray, get_proto_or_iface_array};
@@ -13,8 +14,8 @@ use js::error::throw_type_error;
use js::glue::{RUST_SYMBOL_TO_JSID, UncheckedUnwrapObject};
use js::jsapi::{Class, ClassOps, CompartmentOptions, GetGlobalForObjectCrossCompartment};
use js::jsapi::{GetWellKnownSymbol, HandleObject, HandleValue, JSAutoCompartment};
-use js::jsapi::{JSClass, JSContext, JSFUN_CONSTRUCTOR, JSFunctionSpec, JSNative, JSObject};
-use js::jsapi::{JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING};
+use js::jsapi::{JSClass, JSContext, JSFUN_CONSTRUCTOR, JSFunctionSpec, JSObject};
+use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING};
use js::jsapi::{JSPropertySpec, JSString, JSTracer, JSVersion, JS_AtomizeAndPinString};
use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_DefineProperty2};
use js::jsapi::{JS_DefineProperty4, JS_DefinePropertyById3, JS_FireOnNewGlobalObject};
@@ -24,99 +25,11 @@ use js::jsapi::{JS_NewObject, JS_NewObjectWithUniqueType, JS_NewPlainObject};
use js::jsapi::{JS_NewStringCopyN, JS_SetReservedSlot, MutableHandleObject};
use js::jsapi::{MutableHandleValue, ObjectOps, OnNewGlobalHookOption, SymbolCode};
use js::jsapi::{TrueHandleValue, Value};
-use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue};
-use js::jsval::{PrivateValue, UInt32Value};
+use js::jsval::{JSVal, PrivateValue};
use js::rust::{define_methods, define_properties};
use libc;
use std::ptr;
-/// Representation of an IDL constant value.
-#[derive(Clone)]
-pub enum ConstantVal {
- /// `long` constant.
- IntVal(i32),
- /// `unsigned long` constant.
- UintVal(u32),
- /// `double` constant.
- DoubleVal(f64),
- /// `boolean` constant.
- BoolVal(bool),
- /// `null` constant.
- NullVal,
-}
-
-/// Representation of an IDL constant.
-#[derive(Clone)]
-pub struct ConstantSpec {
- /// name of the constant.
- pub name: &'static [u8],
- /// value of the constant.
- pub value: ConstantVal,
-}
-
-impl ConstantSpec {
- /// Returns a `JSVal` that represents the value of this `ConstantSpec`.
- pub fn get_value(&self) -> JSVal {
- match self.value {
- ConstantVal::NullVal => NullValue(),
- ConstantVal::IntVal(i) => Int32Value(i),
- ConstantVal::UintVal(u) => UInt32Value(u),
- ConstantVal::DoubleVal(d) => DoubleValue(d),
- ConstantVal::BoolVal(b) => BooleanValue(b),
- }
- }
-}
-
-/// A JSNative that cannot be null.
-pub type NonNullJSNative =
- unsafe extern "C" fn (arg1: *mut JSContext, arg2: libc::c_uint, arg3: *mut JSVal) -> bool;
-
-/// Defines constants on `obj`.
-/// Fails on JSAPI failure.
-unsafe fn define_constants(
- cx: *mut JSContext,
- obj: HandleObject,
- constants: &[ConstantSpec]) {
- for spec in constants {
- rooted!(in(cx) let value = spec.get_value());
- assert!(JS_DefineProperty(cx,
- obj,
- spec.name.as_ptr() as *const libc::c_char,
- value.handle(),
- JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
- None,
- None));
- }
-}
-
-unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
- obj: HandleObject,
- _indent: u32)
- -> *mut JSString {
- let js_class = JS_GetClass(obj.get());
- assert!(!js_class.is_null());
- let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
- assert!(!repr.is_empty());
- let ret = JS_NewStringCopyN(cx, repr.as_ptr() as *const libc::c_char, repr.len());
- assert!(!ret.is_null());
- ret
-}
-
-const OBJECT_OPS: ObjectOps = ObjectOps {
- lookupProperty: None,
- defineProperty: None,
- hasProperty: None,
- getProperty: None,
- setProperty: None,
- getOwnPropertyDescriptor: None,
- deleteProperty: None,
- watch: None,
- unwatch: None,
- getElements: None,
- enumerate: None,
- funToString: Some(fun_to_string_hook),
-};
-
/// The class of a non-callback interface object.
#[derive(Copy, Clone)]
pub struct NonCallbackInterfaceObjectClass {
@@ -133,27 +46,8 @@ pub struct NonCallbackInterfaceObjectClass {
unsafe impl Sync for NonCallbackInterfaceObjectClass {}
impl NonCallbackInterfaceObjectClass {
- /// Create `ClassOps` for a `NonCallbackInterfaceObjectClass`.
- pub const fn ops(constructor_behavior: InterfaceConstructorBehavior)
- -> ClassOps {
- ClassOps {
- addProperty: None,
- delProperty: None,
- getProperty: None,
- setProperty: None,
- enumerate: None,
- resolve: None,
- mayResolve: None,
- finalize: None,
- call: constructor_behavior.call,
- construct: constructor_behavior.construct,
- hasInstance: Some(has_instance_hook),
- trace: None,
- }
- }
-
/// Create a new `NonCallbackInterfaceObjectClass` structure.
- pub const fn new(ops: &'static ClassOps,
+ pub const fn new(constructor_behavior: &'static InterfaceConstructorBehavior,
string_rep: &'static [u8],
proto_id: PrototypeList::ID,
proto_depth: u16)
@@ -162,7 +56,7 @@ impl NonCallbackInterfaceObjectClass {
class: Class {
name: b"Function\0" as *const _ as *const libc::c_char,
flags: 0,
- cOps: ops,
+ cOps: &constructor_behavior.0,
spec: ptr::null(),
ext: ptr::null(),
oOps: &OBJECT_OPS,
@@ -186,26 +80,43 @@ pub type ConstructorClassHook =
unsafe extern "C" fn(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool;
/// The constructor behavior of a non-callback interface object.
-pub struct InterfaceConstructorBehavior {
- call: JSNative,
- construct: JSNative,
-}
+pub struct InterfaceConstructorBehavior(ClassOps);
impl InterfaceConstructorBehavior {
/// An interface constructor that unconditionally throws a type error.
- pub const fn throw() -> InterfaceConstructorBehavior {
- InterfaceConstructorBehavior {
+ pub const fn throw() -> Self {
+ InterfaceConstructorBehavior(ClassOps {
+ addProperty: None,
+ delProperty: None,
+ getProperty: None,
+ setProperty: None,
+ enumerate: None,
+ resolve: None,
+ mayResolve: None,
+ finalize: None,
call: Some(invalid_constructor),
construct: Some(invalid_constructor),
- }
+ hasInstance: Some(has_instance_hook),
+ trace: None,
+ })
}
/// An interface constructor that calls a native Rust function.
- pub const fn call(hook: ConstructorClassHook) -> InterfaceConstructorBehavior {
- InterfaceConstructorBehavior {
+ pub const fn call(hook: ConstructorClassHook) -> Self {
+ InterfaceConstructorBehavior(ClassOps {
+ addProperty: None,
+ delProperty: None,
+ getProperty: None,
+ setProperty: None,
+ enumerate: None,
+ resolve: None,
+ mayResolve: None,
+ finalize: None,
call: Some(non_new_constructor),
construct: Some(hook),
- }
+ hasInstance: Some(has_instance_hook),
+ trace: None,
+ })
}
}
@@ -318,7 +229,7 @@ pub unsafe fn create_noncallback_interface_object(
pub unsafe fn create_named_constructors(
cx: *mut JSContext,
global: HandleObject,
- named_constructors: &[(NonNullJSNative, &[u8], u32)],
+ named_constructors: &[(ConstructorClassHook, &[u8], u32)],
interface_prototype_object: HandleObject) {
rooted!(in(cx) let mut constructor = ptr::null_mut());
@@ -346,6 +257,107 @@ pub unsafe fn create_named_constructors(
}
}
+unsafe fn create_object(
+ cx: *mut JSContext,
+ proto: HandleObject,
+ class: &'static JSClass,
+ methods: &[Guard<&'static [JSFunctionSpec]>],
+ properties: &[Guard<&'static [JSPropertySpec]>],
+ constants: &[Guard<&[ConstantSpec]>],
+ rval: MutableHandleObject) {
+ rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
+ assert!(!rval.ptr.is_null());
+ define_guarded_methods(cx, rval.handle(), methods);
+ define_guarded_properties(cx, rval.handle(), properties);
+ define_guarded_constants(cx, rval.handle(), constants);
+}
+
+/// Conditionally define constants on an object.
+pub unsafe fn define_guarded_constants(
+ cx: *mut JSContext,
+ obj: HandleObject,
+ constants: &[Guard<&[ConstantSpec]>]) {
+ for guard in constants {
+ if let Some(specs) = guard.expose(cx, obj) {
+ define_constants(cx, obj, specs);
+ }
+ }
+}
+
+/// Conditionally define methods on an object.
+pub unsafe fn define_guarded_methods(
+ cx: *mut JSContext,
+ obj: HandleObject,
+ methods: &[Guard<&'static [JSFunctionSpec]>]) {
+ for guard in methods {
+ if let Some(specs) = guard.expose(cx, obj) {
+ define_methods(cx, obj, specs).unwrap();
+ }
+ }
+}
+
+/// Conditionally define properties on an object.
+pub unsafe fn define_guarded_properties(
+ cx: *mut JSContext,
+ obj: HandleObject,
+ properties: &[Guard<&'static [JSPropertySpec]>]) {
+ for guard in properties {
+ if let Some(specs) = guard.expose(cx, obj) {
+ define_properties(cx, obj, specs).unwrap();
+ }
+ }
+}
+
+/// Returns whether an interface with exposure set given by `globals` should
+/// be exposed in the global object `obj`.
+pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
+ let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0);
+ let dom_class = get_dom_class(unwrapped).unwrap();
+ globals.contains(dom_class.global)
+}
+
+unsafe fn define_on_global_object(
+ cx: *mut JSContext,
+ global: HandleObject,
+ name: &[u8],
+ obj: HandleObject) {
+ assert!(*name.last().unwrap() == b'\0');
+ assert!(JS_DefineProperty1(cx,
+ global,
+ name.as_ptr() as *const libc::c_char,
+ obj,
+ JSPROP_RESOLVING,
+ None, None));
+}
+
+const OBJECT_OPS: ObjectOps = ObjectOps {
+ lookupProperty: None,
+ defineProperty: None,
+ hasProperty: None,
+ getProperty: None,
+ setProperty: None,
+ getOwnPropertyDescriptor: None,
+ deleteProperty: None,
+ watch: None,
+ unwatch: None,
+ getElements: None,
+ enumerate: None,
+ funToString: Some(fun_to_string_hook),
+};
+
+unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
+ obj: HandleObject,
+ _indent: u32)
+ -> *mut JSString {
+ let js_class = JS_GetClass(obj.get());
+ assert!(!js_class.is_null());
+ let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
+ assert!(!repr.is_empty());
+ let ret = JS_NewStringCopyN(cx, repr.as_ptr() as *const libc::c_char, repr.len());
+ assert!(!ret.is_null());
+ ret
+}
+
/// Hook for instanceof on interface objects.
unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
obj: HandleObject,
@@ -405,21 +417,6 @@ unsafe fn has_instance(
Err(())
}
-unsafe fn create_object(
- cx: *mut JSContext,
- proto: HandleObject,
- class: &'static JSClass,
- methods: &[Guard<&'static [JSFunctionSpec]>],
- properties: &[Guard<&'static [JSPropertySpec]>],
- constants: &[Guard<&[ConstantSpec]>],
- rval: MutableHandleObject) {
- rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
- assert!(!rval.ptr.is_null());
- define_guarded_methods(cx, rval.handle(), methods);
- define_guarded_properties(cx, rval.handle(), properties);
- define_guarded_constants(cx, rval.handle(), constants);
-}
-
unsafe fn create_unscopable_object(
cx: *mut JSContext,
names: &[&[u8]],
@@ -436,42 +433,6 @@ unsafe fn create_unscopable_object(
}
}
-/// Conditionally define constants on an object.
-pub unsafe fn define_guarded_constants(
- cx: *mut JSContext,
- obj: HandleObject,
- constants: &[Guard<&[ConstantSpec]>]) {
- for guard in constants {
- if let Some(specs) = guard.expose(cx, obj) {
- define_constants(cx, obj, specs);
- }
- }
-}
-
-/// Conditionally define methods on an object.
-pub unsafe fn define_guarded_methods(
- cx: *mut JSContext,
- obj: HandleObject,
- methods: &[Guard<&'static [JSFunctionSpec]>]) {
- for guard in methods {
- if let Some(specs) = guard.expose(cx, obj) {
- define_methods(cx, obj, specs).unwrap();
- }
- }
-}
-
-/// Conditionally define properties on an object.
-pub unsafe fn define_guarded_properties(
- cx: *mut JSContext,
- obj: HandleObject,
- properties: &[Guard<&'static [JSPropertySpec]>]) {
- for guard in properties {
- if let Some(specs) = guard.expose(cx, obj) {
- define_properties(cx, obj, specs).unwrap();
- }
- }
-}
-
unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &[u8]) {
assert!(*name.last().unwrap() == b'\0');
rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char));
@@ -493,20 +454,6 @@ unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) {
None, None));
}
-unsafe fn define_on_global_object(
- cx: *mut JSContext,
- global: HandleObject,
- name: &[u8],
- obj: HandleObject) {
- assert!(*name.last().unwrap() == b'\0');
- assert!(JS_DefineProperty1(cx,
- global,
- name.as_ptr() as *const libc::c_char,
- obj,
- JSPROP_RESOLVING,
- None, None));
-}
-
unsafe extern "C" fn invalid_constructor(
cx: *mut JSContext,
_argc: libc::c_uint,
@@ -524,11 +471,3 @@ unsafe extern "C" fn non_new_constructor(
throw_type_error(cx, "This constructor needs to be called with `new`.");
false
}
-
-/// Returns whether an interface with exposure set given by `globals` should
-/// be exposed in the global object `obj`.
-pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
- let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0);
- let dom_class = get_dom_class(unwrapped).unwrap();
- globals.contains(dom_class.global)
-}