aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/interface.rs
diff options
context:
space:
mode:
authoryvt <i@yvt.jp>2021-07-10 17:24:27 +0900
committeryvt <i@yvt.jp>2021-07-10 17:55:42 +0900
commit01a7de50ab1843d85295f9dccad7f4c099e7208c (patch)
treeee53fb6e8889deb7b880ee969e6c662e6128d210 /components/script/dom/bindings/interface.rs
parentff8d2cdbbfc7a9dc7f38b7dd47cb350fde39388f (diff)
parent94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (diff)
downloadservo-01a7de50ab1843d85295f9dccad7f4c099e7208c.tar.gz
servo-01a7de50ab1843d85295f9dccad7f4c099e7208c.zip
Merge remote-tracking branch 'upstream/master' into feat-cow-infra
`tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html` was reverted to the upstream version.
Diffstat (limited to 'components/script/dom/bindings/interface.rs')
-rw-r--r--components/script/dom/bindings/interface.rs637
1 files changed, 347 insertions, 290 deletions
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs
index 3138c00cb89..e982a001fb0 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script/dom/bindings/interface.rs
@@ -1,42 +1,52 @@
/* 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/. */
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Machinery to initialise interface prototype objects and interface objects.
-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};
+use crate::dom::bindings::codegen::InterfaceObjectMap::Globals;
+use crate::dom::bindings::codegen::PrototypeList;
+use crate::dom::bindings::constant::{define_constants, ConstantSpec};
+use crate::dom::bindings::conversions::{get_dom_class, DOM_OBJECT_SLOT};
+use crate::dom::bindings::guard::Guard;
+use crate::dom::bindings::utils::{ProtoOrIfaceArray, DOM_PROTOTYPE_SLOT};
+use crate::script_runtime::JSContext as SafeJSContext;
use dom::window::Window;
use js::error::throw_type_error;
-use js::glue::{CreateRustJSPrincipal, 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, 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};
-use js::jsapi::{JS_GetFunctionObject, JS_GetPrototype};
-use js::jsapi::{JS_LinkConstructorAndPrototype, JS_NewFunction, JS_NewGlobalObject};
-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::glue::UncheckedUnwrapObject;
+use js::jsapi::GetWellKnownSymbol;
+use js::jsapi::HandleObject as RawHandleObject;
+use js::jsapi::{jsid, JSClass, JSClassOps};
+use js::jsapi::{
+ Compartment, CompartmentSpecifier, IsSharableCompartment, IsSystemCompartment,
+ JS_IterateCompartments, JS::CompartmentIterResult,
+};
+use js::jsapi::{JSAutoRealm, JSContext, JSFunctionSpec, JSObject, JSFUN_CONSTRUCTOR};
+use js::jsapi::{JSPropertySpec, JSString, JSTracer, JS_AtomizeAndPinString};
+use js::jsapi::{JS_GetFunctionObject, JS_NewFunction, JS_NewGlobalObject};
+use js::jsapi::{JS_NewObject, JS_NewPlainObject};
+use js::jsapi::{JS_NewStringCopyN, JS_SetReservedSlot};
+use js::jsapi::{ObjectOps, OnNewGlobalHookOption, SymbolCode};
use js::jsapi::{TrueHandleValue, Value};
+use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING};
use js::jsval::{JSVal, PrivateValue};
+use js::rust::wrappers::JS_FireOnNewGlobalObject;
+use js::rust::wrappers::RUST_SYMBOL_TO_JSID;
+use js::rust::wrappers::{JS_DefineProperty, JS_DefineProperty5};
+use js::rust::wrappers::{JS_DefineProperty3, JS_DefineProperty4, JS_DefinePropertyById5};
+use js::rust::wrappers::{JS_LinkConstructorAndPrototype, JS_NewObjectWithGivenProto};
use js::rust::{define_methods, define_properties, get_object_class};
+use js::rust::{HandleObject, HandleValue, MutableHandleObject, RealmOptions};
use libc;
use servo_url::MutableOrigin;
+use std::convert::TryFrom;
use std::ptr;
/// The class of a non-callback interface object.
-#[derive(Copy, Clone)]
+#[derive(Clone, Copy)]
pub struct NonCallbackInterfaceObjectClass {
- /// The SpiderMonkey Class structure.
- pub class: Class,
+ /// The SpiderMonkey class structure.
+ pub class: JSClass,
/// The prototype id of that interface, used in the hasInstance hook.
pub proto_id: PrototypeList::ID,
/// The prototype depth of that interface, used in the hasInstance hook.
@@ -49,18 +59,19 @@ unsafe impl Sync for NonCallbackInterfaceObjectClass {}
impl NonCallbackInterfaceObjectClass {
/// Create a new `NonCallbackInterfaceObjectClass` structure.
- pub const fn new(constructor_behavior: &'static InterfaceConstructorBehavior,
- string_rep: &'static [u8],
- proto_id: PrototypeList::ID,
- proto_depth: u16)
- -> NonCallbackInterfaceObjectClass {
+ pub const fn new(
+ constructor_behavior: &'static InterfaceConstructorBehavior,
+ string_rep: &'static [u8],
+ proto_id: PrototypeList::ID,
+ proto_depth: u16,
+ ) -> NonCallbackInterfaceObjectClass {
NonCallbackInterfaceObjectClass {
- class: Class {
+ class: JSClass {
name: b"Function\0" as *const _ as *const libc::c_char,
flags: 0,
cOps: &constructor_behavior.0,
- spec: ptr::null(),
- ext: ptr::null(),
+ spec: 0 as *const _,
+ ext: 0 as *const _,
oOps: &OBJECT_OPS,
},
proto_id: proto_id,
@@ -71,9 +82,7 @@ impl NonCallbackInterfaceObjectClass {
/// cast own reference to `JSClass` reference
pub fn as_jsclass(&self) -> &JSClass {
- unsafe {
- &*(self as *const _ as *const JSClass)
- }
+ unsafe { &*(self as *const _ as *const JSClass) }
}
}
@@ -82,263 +91,363 @@ 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(ClassOps);
+pub struct InterfaceConstructorBehavior(JSClassOps);
impl InterfaceConstructorBehavior {
/// An interface constructor that unconditionally throws a type error.
pub const fn throw() -> Self {
- InterfaceConstructorBehavior(ClassOps {
+ InterfaceConstructorBehavior(JSClassOps {
addProperty: None,
delProperty: None,
- getProperty: None,
- setProperty: None,
enumerate: None,
+ newEnumerate: None,
resolve: None,
mayResolve: None,
finalize: None,
call: Some(invalid_constructor),
construct: Some(invalid_constructor),
- hasInstance: Some(has_instance_hook),
+ hasInstance: None, // heycam/webidl#356
trace: None,
})
}
/// An interface constructor that calls a native Rust function.
pub const fn call(hook: ConstructorClassHook) -> Self {
- InterfaceConstructorBehavior(ClassOps {
+ InterfaceConstructorBehavior(JSClassOps {
addProperty: None,
delProperty: None,
- getProperty: None,
- setProperty: None,
enumerate: None,
+ newEnumerate: None,
resolve: None,
mayResolve: None,
finalize: None,
call: Some(non_new_constructor),
construct: Some(hook),
- hasInstance: Some(has_instance_hook),
+ hasInstance: None, // heycam/webidl#356
trace: None,
})
}
}
/// A trace hook.
-pub type TraceHook =
- unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
+pub type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
/// Create a global object with the given class.
pub unsafe fn create_global_object(
- cx: *mut JSContext,
- class: &'static JSClass,
- private: *const libc::c_void,
- trace: TraceHook,
- rval: MutableHandleObject,
- origin: &MutableOrigin) {
+ cx: SafeJSContext,
+ class: &'static JSClass,
+ private: *const libc::c_void,
+ trace: TraceHook,
+ mut rval: MutableHandleObject,
+ origin: &MutableOrigin,
+) {
assert!(rval.is_null());
- let mut options = CompartmentOptions::default();
- options.behaviors_.version_ = JSVersion::JSVERSION_ECMA_5;
+ let mut options = RealmOptions::default();
options.creationOptions_.traceGlobal_ = Some(trace);
- options.creationOptions_.sharedMemoryAndAtomics_ = true;
+ options.creationOptions_.sharedMemoryAndAtomics_ = false;
+ options.creationOptions_.streams_ = true;
+ select_compartment(cx, &mut options);
let origin = Box::new(origin.clone());
- let mut principal = CreateRustJSPrincipal(Box::into_raw(origin) as *const ::libc::c_void,
- None,
- None);
-
- rval.set(JS_NewGlobalObject(cx,
- class,
- principal,
- OnNewGlobalHookOption::DontFireOnNewGlobalHook,
- &options));
+ let mut principal =
+ CreateRustJSPrincipal(Box::into_raw(origin) as *const ::libc::c_void, None, None);
+
+ rval.set(JS_NewGlobalObject(
+ *cx,
+ class,
+ principal,
+ OnNewGlobalHookOption::DontFireOnNewGlobalHook,
+ &*options,
+ ));
assert!(!rval.is_null());
// Initialize the reserved slots before doing anything that can GC, to
// avoid getting trace hooks called on a partially initialized object.
- JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, PrivateValue(private));
+ let private_val = PrivateValue(private);
+ JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, &private_val);
let proto_array: Box<ProtoOrIfaceArray> =
- box [0 as *mut JSObject; PrototypeList::PROTO_OR_IFACE_LENGTH];
- JS_SetReservedSlot(rval.get(),
- DOM_PROTOTYPE_SLOT,
- PrivateValue(Box::into_raw(proto_array) as *const libc::c_void));
+ Box::new([0 as *mut JSObject; PrototypeList::PROTO_OR_IFACE_LENGTH]);
+ let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void);
+ JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val);
- let _ac = JSAutoCompartment::new(cx, rval.get());
- JS_FireOnNewGlobalObject(cx, rval.handle());
+ let _ac = JSAutoRealm::new(*cx, rval.get());
+ JS_FireOnNewGlobalObject(*cx, rval.handle());
+}
+
+/// Choose the compartment to create a new global object in.
+fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) {
+ type Data = *mut Compartment;
+ unsafe extern "C" fn callback(
+ _cx: *mut JSContext,
+ data: *mut libc::c_void,
+ compartment: *mut Compartment,
+ ) -> CompartmentIterResult {
+ let data = data as *mut Data;
+
+ if !IsSharableCompartment(compartment) || IsSystemCompartment(compartment) {
+ return CompartmentIterResult::KeepGoing;
+ }
+
+ // Choose any sharable, non-system compartment in this context to allow
+ // same-agent documents to share JS and DOM objects.
+ *data = compartment;
+ CompartmentIterResult::Stop
+ }
+
+ let mut compartment: Data = ptr::null_mut();
+ unsafe {
+ JS_IterateCompartments(
+ *cx,
+ (&mut compartment) as *mut Data as *mut libc::c_void,
+ Some(callback),
+ );
+ }
+
+ if compartment.is_null() {
+ options.creationOptions_.compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
+ } else {
+ options.creationOptions_.compSpec_ = CompartmentSpecifier::ExistingCompartment;
+ options.creationOptions_.__bindgen_anon_1.comp_ = compartment;
+ }
}
/// Create and define the interface object of a callback interface.
-pub unsafe fn create_callback_interface_object(
- cx: *mut JSContext,
- global: HandleObject,
- constants: &[Guard<&[ConstantSpec]>],
- name: &[u8],
- rval: MutableHandleObject) {
+pub fn create_callback_interface_object(
+ cx: SafeJSContext,
+ global: HandleObject,
+ constants: &[Guard<&[ConstantSpec]>],
+ name: &[u8],
+ mut rval: MutableHandleObject,
+) {
assert!(!constants.is_empty());
- rval.set(JS_NewObject(cx, ptr::null()));
- assert!(!rval.ptr.is_null());
- define_guarded_constants(cx, rval.handle(), constants);
+ unsafe {
+ rval.set(JS_NewObject(*cx, ptr::null()));
+ }
+ assert!(!rval.is_null());
+ define_guarded_constants(cx, rval.handle(), constants, global);
define_name(cx, rval.handle(), name);
define_on_global_object(cx, global, name, rval.handle());
}
/// Create the interface prototype object of a non-callback interface.
-pub unsafe fn create_interface_prototype_object(
- cx: *mut JSContext,
- proto: HandleObject,
- class: &'static JSClass,
- regular_methods: &[Guard<&'static [JSFunctionSpec]>],
- regular_properties: &[Guard<&'static [JSPropertySpec]>],
- constants: &[Guard<&[ConstantSpec]>],
- unscopable_names: &[&[u8]],
- rval: MutableHandleObject) {
- create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
+pub fn create_interface_prototype_object(
+ cx: SafeJSContext,
+ global: HandleObject,
+ proto: HandleObject,
+ class: &'static JSClass,
+ regular_methods: &[Guard<&'static [JSFunctionSpec]>],
+ regular_properties: &[Guard<&'static [JSPropertySpec]>],
+ constants: &[Guard<&[ConstantSpec]>],
+ unscopable_names: &[&[u8]],
+ rval: MutableHandleObject,
+) {
+ create_object(
+ cx,
+ global,
+ proto,
+ class,
+ regular_methods,
+ regular_properties,
+ constants,
+ rval,
+ );
if !unscopable_names.is_empty() {
- rooted!(in(cx) let mut unscopable_obj = ptr::null_mut());
+ rooted!(in(*cx) let mut unscopable_obj = ptr::null_mut::<JSObject>());
create_unscopable_object(cx, unscopable_names, unscopable_obj.handle_mut());
-
- let unscopable_symbol = GetWellKnownSymbol(cx, SymbolCode::unscopables);
- assert!(!unscopable_symbol.is_null());
-
- rooted!(in(cx) let unscopable_id = RUST_SYMBOL_TO_JSID(unscopable_symbol));
- assert!(JS_DefinePropertyById3(
- cx, rval.handle(), unscopable_id.handle(), unscopable_obj.handle(),
- JSPROP_READONLY, None, None))
+ unsafe {
+ let unscopable_symbol = GetWellKnownSymbol(*cx, SymbolCode::unscopables);
+ assert!(!unscopable_symbol.is_null());
+
+ rooted!(in(*cx) let mut unscopable_id: jsid);
+ RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut());
+
+ assert!(JS_DefinePropertyById5(
+ *cx,
+ rval.handle(),
+ unscopable_id.handle(),
+ unscopable_obj.handle(),
+ JSPROP_READONLY as u32
+ ))
+ }
}
}
/// Create and define the interface object of a non-callback interface.
-pub unsafe fn create_noncallback_interface_object(
- cx: *mut JSContext,
- global: HandleObject,
- proto: HandleObject,
- class: &'static NonCallbackInterfaceObjectClass,
- static_methods: &[Guard<&'static [JSFunctionSpec]>],
- static_properties: &[Guard<&'static [JSPropertySpec]>],
- constants: &[Guard<&[ConstantSpec]>],
- interface_prototype_object: HandleObject,
- name: &[u8],
- length: u32,
- rval: MutableHandleObject) {
- create_object(cx,
- proto,
- class.as_jsclass(),
- static_methods,
- static_properties,
- constants,
- rval);
- assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object));
+pub fn create_noncallback_interface_object(
+ cx: SafeJSContext,
+ global: HandleObject,
+ proto: HandleObject,
+ class: &'static NonCallbackInterfaceObjectClass,
+ static_methods: &[Guard<&'static [JSFunctionSpec]>],
+ static_properties: &[Guard<&'static [JSPropertySpec]>],
+ constants: &[Guard<&[ConstantSpec]>],
+ interface_prototype_object: HandleObject,
+ name: &[u8],
+ length: u32,
+ legacy_window_alias_names: &[&[u8]],
+ rval: MutableHandleObject,
+) {
+ create_object(
+ cx,
+ global,
+ proto,
+ class.as_jsclass(),
+ static_methods,
+ static_properties,
+ constants,
+ rval,
+ );
+ unsafe {
+ assert!(JS_LinkConstructorAndPrototype(
+ *cx,
+ rval.handle(),
+ interface_prototype_object
+ ));
+ }
define_name(cx, rval.handle(), name);
- define_length(cx, rval.handle(), length);
+ define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
define_on_global_object(cx, global, name, rval.handle());
+
+ if is_exposed_in(global, Globals::WINDOW) {
+ for legacy_window_alias in legacy_window_alias_names {
+ define_on_global_object(cx, global, legacy_window_alias, rval.handle());
+ }
+ }
}
/// Create and define the named constructors of a non-callback interface.
-pub unsafe fn create_named_constructors(
- cx: *mut JSContext,
- global: HandleObject,
- named_constructors: &[(ConstructorClassHook, &[u8], u32)],
- interface_prototype_object: HandleObject) {
- rooted!(in(cx) let mut constructor = ptr::null_mut());
+pub fn create_named_constructors(
+ cx: SafeJSContext,
+ global: HandleObject,
+ named_constructors: &[(ConstructorClassHook, &[u8], u32)],
+ interface_prototype_object: HandleObject,
+) {
+ rooted!(in(*cx) let mut constructor = ptr::null_mut::<JSObject>());
for &(native, name, arity) in named_constructors {
- assert!(*name.last().unwrap() == b'\0');
-
- let fun = JS_NewFunction(cx,
- Some(native),
- arity,
- JSFUN_CONSTRUCTOR,
- name.as_ptr() as *const libc::c_char);
- assert!(!fun.is_null());
- constructor.set(JS_GetFunctionObject(fun));
- assert!(!constructor.is_null());
-
- assert!(JS_DefineProperty1(cx,
- constructor.handle(),
- b"prototype\0".as_ptr() as *const libc::c_char,
- interface_prototype_object,
- JSPROP_PERMANENT | JSPROP_READONLY,
- None,
- None));
+ assert_eq!(*name.last().unwrap(), b'\0');
+
+ unsafe {
+ let fun = JS_NewFunction(
+ *cx,
+ Some(native),
+ arity,
+ JSFUN_CONSTRUCTOR,
+ name.as_ptr() as *const libc::c_char,
+ );
+ assert!(!fun.is_null());
+ constructor.set(JS_GetFunctionObject(fun));
+ assert!(!constructor.is_null());
+
+ assert!(JS_DefineProperty3(
+ *cx,
+ constructor.handle(),
+ b"prototype\0".as_ptr() as *const libc::c_char,
+ interface_prototype_object,
+ (JSPROP_PERMANENT | JSPROP_READONLY) as u32
+ ));
+ }
define_on_global_object(cx, global, name, constructor.handle());
}
}
/// Create a new object with a unique type.
-pub 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);
+pub fn create_object(
+ cx: SafeJSContext,
+ global: HandleObject,
+ proto: HandleObject,
+ class: &'static JSClass,
+ methods: &[Guard<&'static [JSFunctionSpec]>],
+ properties: &[Guard<&'static [JSPropertySpec]>],
+ constants: &[Guard<&[ConstantSpec]>],
+ mut rval: MutableHandleObject,
+) {
+ unsafe {
+ rval.set(JS_NewObjectWithGivenProto(*cx, class, proto));
+ }
+ assert!(!rval.is_null());
+ define_guarded_methods(cx, rval.handle(), methods, global);
+ define_guarded_properties(cx, rval.handle(), properties, global);
+ define_guarded_constants(cx, rval.handle(), constants, global);
}
/// Conditionally define constants on an object.
-pub unsafe fn define_guarded_constants(
- cx: *mut JSContext,
- obj: HandleObject,
- constants: &[Guard<&[ConstantSpec]>]) {
+pub fn define_guarded_constants(
+ cx: SafeJSContext,
+ obj: HandleObject,
+ constants: &[Guard<&[ConstantSpec]>],
+ global: HandleObject,
+) {
for guard in constants {
- if let Some(specs) = guard.expose(cx, obj) {
+ if let Some(specs) = guard.expose(cx, obj, global) {
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]>]) {
+pub fn define_guarded_methods(
+ cx: SafeJSContext,
+ obj: HandleObject,
+ methods: &[Guard<&'static [JSFunctionSpec]>],
+ global: HandleObject,
+) {
for guard in methods {
- if let Some(specs) = guard.expose(cx, obj) {
- define_methods(cx, obj, specs).unwrap();
+ if let Some(specs) = guard.expose(cx, obj, global) {
+ unsafe {
+ 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]>]) {
+pub fn define_guarded_properties(
+ cx: SafeJSContext,
+ obj: HandleObject,
+ properties: &[Guard<&'static [JSPropertySpec]>],
+ global: HandleObject,
+) {
for guard in properties {
- if let Some(specs) = guard.expose(cx, obj) {
- define_properties(cx, obj, specs).unwrap();
+ if let Some(specs) = guard.expose(cx, obj, global) {
+ unsafe {
+ 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)
+pub fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
+ unsafe {
+ let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0);
+ let dom_class = get_dom_class(unwrapped).unwrap();
+ globals.contains(dom_class.global)
+ }
}
/// Define a property with a given name on the global object. Should be called
/// through the resolve hook.
-pub 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));
+pub fn define_on_global_object(
+ cx: SafeJSContext,
+ global: HandleObject,
+ name: &[u8],
+ obj: HandleObject,
+) {
+ assert_eq!(*name.last().unwrap(), b'\0');
+ unsafe {
+ assert!(JS_DefineProperty3(
+ *cx,
+ global,
+ name.as_ptr() as *const libc::c_char,
+ obj,
+ JSPROP_RESOLVING
+ ));
+ }
}
const OBJECT_OPS: ObjectOps = ObjectOps {
@@ -349,17 +458,15 @@ const OBJECT_OPS: ObjectOps = ObjectOps {
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 {
+unsafe extern "C" fn fun_to_string_hook(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ _is_to_source: bool,
+) -> *mut JSString {
let js_class = get_object_class(obj.get());
assert!(!js_class.is_null());
let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
@@ -369,116 +476,66 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
ret
}
-/// Hook for instanceof on interface objects.
-unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
- obj: HandleObject,
- value: MutableHandleValue,
- rval: *mut bool) -> bool {
- match has_instance(cx, obj, value.handle()) {
- Ok(result) => {
- *rval = result;
- true
+fn create_unscopable_object(cx: SafeJSContext, names: &[&[u8]], mut rval: MutableHandleObject) {
+ assert!(!names.is_empty());
+ assert!(rval.is_null());
+ unsafe {
+ rval.set(JS_NewPlainObject(*cx));
+ assert!(!rval.is_null());
+ for &name in names {
+ assert_eq!(*name.last().unwrap(), b'\0');
+ assert!(JS_DefineProperty(
+ *cx,
+ rval.handle(),
+ name.as_ptr() as *const libc::c_char,
+ HandleValue::from_raw(TrueHandleValue),
+ JSPROP_READONLY as u32,
+ ));
}
- Err(()) => false,
}
}
-/// Return whether a value is an instance of a given prototype.
-/// http://heycam.github.io/webidl/#es-interface-hasinstance
-unsafe fn has_instance(
- cx: *mut JSContext,
- interface_object: HandleObject,
- value: HandleValue)
- -> Result<bool, ()> {
- if !value.is_object() {
- // Step 1.
- return Ok(false);
+fn define_name(cx: SafeJSContext, obj: HandleObject, name: &[u8]) {
+ assert_eq!(*name.last().unwrap(), b'\0');
+ unsafe {
+ rooted!(in(*cx) let name = JS_AtomizeAndPinString(*cx, name.as_ptr() as *const libc::c_char));
+ assert!(!name.is_null());
+ assert!(JS_DefineProperty4(
+ *cx,
+ obj,
+ b"name\0".as_ptr() as *const libc::c_char,
+ name.handle().into(),
+ JSPROP_READONLY as u32
+ ));
}
- rooted!(in(cx) let mut value = value.to_object());
-
- let js_class = get_object_class(interface_object.get());
- let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass);
-
- if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(value.get(),
- /* stopAtWindowProxy = */ 0)) {
- if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id {
- // Step 4.
- return Ok(true);
- }
- }
-
- // Step 2.
- let global = GetGlobalForObjectCrossCompartment(interface_object.get());
- assert!(!global.is_null());
- let proto_or_iface_array = get_proto_or_iface_array(global);
- rooted!(in(cx) let prototype = (*proto_or_iface_array)[object_class.proto_id as usize]);
- assert!(!prototype.is_null());
- // Step 3 only concern legacy callback interface objects (i.e. NodeFilter).
-
- while JS_GetPrototype(cx, value.handle(), value.handle_mut()) {
- if value.is_null() {
- // Step 5.2.
- return Ok(false);
- } else if value.get() as *const _ == prototype.get() {
- // Step 5.3.
- return Ok(true);
- }
- }
- // JS_GetPrototype threw an exception.
- Err(())
}
-unsafe fn create_unscopable_object(
- cx: *mut JSContext,
- names: &[&[u8]],
- rval: MutableHandleObject) {
- assert!(!names.is_empty());
- assert!(rval.is_null());
- rval.set(JS_NewPlainObject(cx));
- assert!(!rval.ptr.is_null());
- for &name in names {
- assert!(*name.last().unwrap() == b'\0');
- assert!(JS_DefineProperty(
- cx, rval.handle(), name.as_ptr() as *const libc::c_char, TrueHandleValue,
- JSPROP_READONLY, None, None));
+fn define_length(cx: SafeJSContext, obj: HandleObject, length: i32) {
+ unsafe {
+ assert!(JS_DefineProperty5(
+ *cx,
+ obj,
+ b"length\0".as_ptr() as *const libc::c_char,
+ length,
+ JSPROP_READONLY as u32
+ ));
}
}
-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));
- assert!(!name.is_null());
- assert!(JS_DefineProperty2(cx,
- obj,
- b"name\0".as_ptr() as *const libc::c_char,
- name.handle(),
- JSPROP_READONLY,
- None, None));
-}
-
-unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) {
- assert!(JS_DefineProperty4(cx,
- obj,
- b"length\0".as_ptr() as *const libc::c_char,
- length,
- JSPROP_READONLY,
- None, None));
-}
-
unsafe extern "C" fn invalid_constructor(
- cx: *mut JSContext,
- _argc: libc::c_uint,
- _vp: *mut JSVal)
- -> bool {
+ cx: *mut JSContext,
+ _argc: libc::c_uint,
+ _vp: *mut JSVal,
+) -> bool {
throw_type_error(cx, "Illegal constructor.");
false
}
unsafe extern "C" fn non_new_constructor(
- cx: *mut JSContext,
- _argc: libc::c_uint,
- _vp: *mut JSVal)
- -> bool {
+ cx: *mut JSContext,
+ _argc: libc::c_uint,
+ _vp: *mut JSVal,
+) -> bool {
throw_type_error(cx, "This constructor needs to be called with `new`.");
false
}