mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
More miscellaneous script splitting changes (#36220)
* script: Move HasParent to script_bindings and update imports for InheritTypes. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make principal creation generic over DOM interface. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Move a bunch of proxy-related code to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make some proxy-related code generic over the DOM interface. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Move DomSlice to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Move some utility bindings code to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make enumerating and resolving globals generic over the DOM interface. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make realm helpers generic over the DOM interface. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Move implementations on concrete DOM types to concrete bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make additional codegen helpers generic over the DOM interface. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make iterator creation generic over the DOM interface. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Make reporting an exception a generic operation. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Move AsCCharPtrPtr to script_bindings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Formatting. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Address clippy warnings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
971490084e
commit
b445053a7c
33 changed files with 806 additions and 628 deletions
|
@ -5,6 +5,9 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use script_bindings::codegen::InheritTypes::{
|
||||
AudioNodeTypeId, AudioScheduledSourceNodeTypeId, EventTargetTypeId,
|
||||
};
|
||||
use servo_media::audio::graph::NodeId;
|
||||
use servo_media::audio::node::{
|
||||
AudioNodeInit, AudioNodeMessage, ChannelCountMode as ServoMediaChannelCountMode, ChannelInfo,
|
||||
|
@ -17,9 +20,6 @@ use crate::dom::baseaudiocontext::BaseAudioContext;
|
|||
use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
|
||||
AudioNodeMethods, AudioNodeOptions, ChannelCountMode, ChannelInterpretation,
|
||||
};
|
||||
use crate::dom::bindings::codegen::InheritTypes::{
|
||||
AudioNodeTypeId, AudioScheduledSourceNodeTypeId, EventTargetTypeId,
|
||||
};
|
||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
|
|
|
@ -16,14 +16,15 @@ use js::jsval::{JSVal, ObjectValue, UndefinedValue};
|
|||
use js::rust::wrappers::{JS_GetProperty, JS_WrapObject};
|
||||
use js::rust::{MutableHandleValue, Runtime};
|
||||
use script_bindings::interfaces::DocumentHelpers;
|
||||
use script_bindings::utils::AsCCharPtrPtr;
|
||||
|
||||
use crate::DomTypes;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
|
||||
use crate::dom::bindings::error::{Error, Fallible, report_pending_exception};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::settings_stack::{GenericAutoEntryScript, GenericAutoIncumbentScript};
|
||||
use crate::dom::bindings::utils::AsCCharPtrPtr;
|
||||
use crate::dom::bindings::utils::DomHelpers;
|
||||
use crate::dom::globalscope::GlobalScopeHelpers;
|
||||
use crate::realms::{InRealm, enter_realm};
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
|
@ -281,7 +282,12 @@ impl<D: DomTypes> Drop for CallSetup<D> {
|
|||
}
|
||||
if self.handling == ExceptionHandling::Report {
|
||||
let ar = enter_realm(&*self.exception_global);
|
||||
report_pending_exception(self.cx, true, InRealm::Entered(&ar), CanGc::note());
|
||||
<D as DomHelpers<D>>::report_pending_exception(
|
||||
self.cx,
|
||||
true,
|
||||
InRealm::Entered(&ar),
|
||||
CanGc::note(),
|
||||
);
|
||||
}
|
||||
drop(self.incumbent_script.take());
|
||||
drop(self.entry_script.take().unwrap());
|
||||
|
|
|
@ -107,6 +107,7 @@ pub(crate) mod module {
|
|||
};
|
||||
pub(crate) use script_bindings::interfaces::*;
|
||||
pub(crate) use script_bindings::record::Record;
|
||||
pub(crate) use script_bindings::reflector::DomObject;
|
||||
pub(crate) use servo_config::pref;
|
||||
|
||||
pub(crate) use super::base::*;
|
||||
|
@ -140,7 +141,7 @@ pub(crate) mod module {
|
|||
define_guarded_properties, get_desired_proto, get_per_interface_object_handle,
|
||||
is_exposed_in,
|
||||
};
|
||||
pub(crate) use crate::dom::bindings::iterable::{Iterable, IteratorType};
|
||||
pub(crate) use crate::dom::bindings::iterable::{Iterable, IterableIterator, IteratorType};
|
||||
pub(crate) use crate::dom::bindings::like::{Maplike, Setlike};
|
||||
pub(crate) use crate::dom::bindings::namespace::{
|
||||
NamespaceObjectClass, create_namespace_object,
|
||||
|
|
|
@ -3,11 +3,4 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pub(crate) use script_bindings::codegen::InheritTypes::*;
|
||||
pub(crate) use script_bindings::inheritance::Castable;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub(crate) trait HasParent {
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
type Parent;
|
||||
fn as_parent(&self) -> &Self::Parent;
|
||||
}
|
||||
pub(crate) use script_bindings::inheritance::{Castable, HasParent};
|
||||
|
|
|
@ -135,7 +135,7 @@ impl InterfaceConstructorBehavior {
|
|||
pub(crate) type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
|
||||
|
||||
/// Create a global object with the given class.
|
||||
pub(crate) unsafe fn create_global_object(
|
||||
pub(crate) unsafe fn create_global_object<D: DomTypes>(
|
||||
cx: SafeJSContext,
|
||||
class: &'static JSClass,
|
||||
private: *const libc::c_void,
|
||||
|
@ -150,7 +150,7 @@ pub(crate) unsafe fn create_global_object(
|
|||
options.creationOptions_.sharedMemoryAndAtomics_ = false;
|
||||
select_compartment(cx, &mut options);
|
||||
|
||||
let principal = ServoJSPrincipals::new(origin);
|
||||
let principal = ServoJSPrincipals::new::<D>(origin);
|
||||
|
||||
rval.set(JS_NewGlobalObject(
|
||||
*cx,
|
||||
|
|
|
@ -26,10 +26,11 @@ use crate::dom::bindings::codegen::Bindings::IterableIteratorBinding::{
|
|||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{
|
||||
DomGlobalGeneric, DomObjectIteratorWrap, DomObjectWrap, Reflector, reflect_dom_object,
|
||||
DomGlobalGeneric, DomObjectIteratorWrap, DomObjectWrap, Reflector,
|
||||
};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, Root};
|
||||
use crate::dom::bindings::trace::{JSTraceable, NoTrace, RootedTraceableBox};
|
||||
use crate::dom::bindings::utils::DomHelpers;
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
|
||||
|
@ -79,7 +80,7 @@ impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlob
|
|||
index: Cell::new(0),
|
||||
_marker: NoTrace(PhantomData),
|
||||
});
|
||||
reflect_dom_object(iterator, &*iterable.global_(realm), CanGc::note())
|
||||
<D as DomHelpers<D>>::reflect_dom_object(iterator, &*iterable.global_(realm), CanGc::note())
|
||||
}
|
||||
|
||||
/// Return the next value from the iterable object.
|
||||
|
|
|
@ -191,7 +191,6 @@ pub(crate) mod codegen {
|
|||
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InterfaceObjectMap.rs"));
|
||||
pub(crate) use script_bindings::codegen::Globals::Globals;
|
||||
}
|
||||
pub(crate) use script_bindings::codegen::InheritTypes;
|
||||
#[allow(dead_code)]
|
||||
pub(crate) mod ConcreteInheritTypes {
|
||||
include!(concat!(
|
||||
|
|
|
@ -19,16 +19,21 @@ use js::rust::Runtime;
|
|||
use servo_url::MutableOrigin;
|
||||
|
||||
use super::structuredclone::StructuredCloneTags;
|
||||
use crate::dom::bindings::utils::DomHelpers;
|
||||
use crate::{DomTypeHolder, DomTypes};
|
||||
|
||||
/// An owned reference to Servo's `JSPrincipals` instance.
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct ServoJSPrincipals(NonNull<JSPrincipals>);
|
||||
|
||||
impl ServoJSPrincipals {
|
||||
pub(crate) fn new(origin: &MutableOrigin) -> Self {
|
||||
pub(crate) fn new<D: DomTypes>(origin: &MutableOrigin) -> Self {
|
||||
unsafe {
|
||||
let private: Box<MutableOrigin> = Box::new(origin.clone());
|
||||
let raw = CreateRustJSPrincipals(&PRINCIPALS_CALLBACKS, Box::into_raw(private) as _);
|
||||
let raw = CreateRustJSPrincipals(
|
||||
<D as DomHelpers<D>>::principals_callbacks(),
|
||||
Box::into_raw(private) as _,
|
||||
);
|
||||
// The created `JSPrincipals` object has an initial reference
|
||||
// count of zero, so the following code will set it to one
|
||||
Self::from_raw_nonnull(NonNull::new_unchecked(raw))
|
||||
|
@ -175,14 +180,14 @@ pub(crate) unsafe extern "C" fn read_jsprincipal(
|
|||
let Ok(origin) = bincode::deserialize(&bytes[..]) else {
|
||||
return false;
|
||||
};
|
||||
let principal = ServoJSPrincipals::new(&origin);
|
||||
let principal = ServoJSPrincipals::new::<DomTypeHolder>(&origin);
|
||||
*principals = principal.as_raw();
|
||||
// we transferred ownership of principal to the caller
|
||||
std::mem::forget(principal);
|
||||
true
|
||||
}
|
||||
|
||||
const PRINCIPALS_CALLBACKS: JSPrincipalsCallbacks = JSPrincipalsCallbacks {
|
||||
pub(crate) const PRINCIPALS_CALLBACKS: JSPrincipalsCallbacks = JSPrincipalsCallbacks {
|
||||
write: Some(write_jsprincipal),
|
||||
isSystemOrAddonPrincipal: Some(principals_is_system_or_addon_principal),
|
||||
};
|
||||
|
|
|
@ -6,199 +6,31 @@
|
|||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr;
|
||||
|
||||
use js::conversions::ToJSValConvertible;
|
||||
use js::glue::{
|
||||
GetProxyHandler, GetProxyHandlerFamily, GetProxyPrivate, InvokeGetOwnPropertyDescriptor,
|
||||
SetProxyPrivate,
|
||||
};
|
||||
use js::glue::{GetProxyHandler, InvokeGetOwnPropertyDescriptor};
|
||||
use js::jsapi;
|
||||
use js::jsapi::{
|
||||
DOMProxyShadowsResult, GetObjectRealmOrNull, GetRealmPrincipals, GetStaticPrototype,
|
||||
GetWellKnownSymbol, Handle as RawHandle, HandleId as RawHandleId,
|
||||
HandleObject as RawHandleObject, HandleValue as RawHandleValue, JS_AtomizeAndPinString,
|
||||
JS_DefinePropertyById, JS_GetOwnPropertyDescriptorById, JS_IsExceptionPending, JSAutoRealm,
|
||||
JSContext, JSErrNum, JSFunctionSpec, JSObject, JSPropertySpec,
|
||||
MutableHandle as RawMutableHandle, MutableHandleIdVector as RawMutableHandleIdVector,
|
||||
GetObjectRealmOrNull, GetRealmPrincipals, HandleId as RawHandleId,
|
||||
HandleObject as RawHandleObject, HandleValue as RawHandleValue, JS_IsExceptionPending,
|
||||
JSAutoRealm, JSContext, JSObject, MutableHandle as RawMutableHandle,
|
||||
MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue,
|
||||
ObjectOpResult, PropertyDescriptor, SetDOMProxyInformation, SymbolCode, jsid,
|
||||
};
|
||||
use js::jsid::SymbolId;
|
||||
use js::jsval::{ObjectValue, UndefinedValue};
|
||||
use js::rust::wrappers::{
|
||||
AppendToIdVector, JS_AlreadyHasOwnPropertyById, JS_NewObjectWithGivenProto,
|
||||
RUST_INTERNED_STRING_TO_JSID, SetDataPropertyDescriptor,
|
||||
};
|
||||
use js::rust::{
|
||||
Handle, HandleObject, HandleValue, MutableHandle, MutableHandleObject, get_context_realm,
|
||||
ObjectOpResult, PropertyDescriptor,
|
||||
};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::{HandleObject, HandleValue, MutableHandle, MutableHandleObject, get_context_realm};
|
||||
pub(crate) use script_bindings::proxyhandler::*;
|
||||
|
||||
use crate::dom::bindings::conversions::{is_dom_proxy, jsid_to_string, jsstring_to_str};
|
||||
use crate::dom::bindings::error::{Error, throw_dom_exception};
|
||||
use crate::DomTypes;
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::principals::ServoJSPrincipalsRef;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::bindings::utils::delete_property_by_id;
|
||||
use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers};
|
||||
use crate::dom::bindings::utils::DomHelpers;
|
||||
use crate::dom::globalscope::GlobalScopeHelpers;
|
||||
use crate::realms::{AlreadyInRealm, InRealm};
|
||||
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||
|
||||
/// Determine if this id shadows any existing properties for this proxy.
|
||||
pub(crate) unsafe extern "C" fn shadow_check_callback(
|
||||
cx: *mut JSContext,
|
||||
object: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
) -> DOMProxyShadowsResult {
|
||||
// TODO: support OverrideBuiltins when #12978 is fixed.
|
||||
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
get_expando_object(object, expando.handle_mut());
|
||||
if !expando.get().is_null() {
|
||||
let mut has_own = false;
|
||||
let raw_id = Handle::from_raw(id);
|
||||
|
||||
if !JS_AlreadyHasOwnPropertyById(cx, expando.handle(), raw_id, &mut has_own) {
|
||||
return DOMProxyShadowsResult::ShadowCheckFailed;
|
||||
}
|
||||
|
||||
if has_own {
|
||||
return DOMProxyShadowsResult::ShadowsViaDirectExpando;
|
||||
}
|
||||
}
|
||||
|
||||
// Our expando, if any, didn't shadow, so we're not shadowing at all.
|
||||
DOMProxyShadowsResult::DoesntShadow
|
||||
}
|
||||
|
||||
/// Initialize the infrastructure for DOM proxy objects.
|
||||
pub(crate) unsafe fn init() {
|
||||
SetDOMProxyInformation(
|
||||
GetProxyHandlerFamily(),
|
||||
Some(shadow_check_callback),
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Defines an expando on the given `proxy`.
|
||||
pub(crate) unsafe extern "C" fn define_property(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
desc: RawHandle<PropertyDescriptor>,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
ensure_expando_object(cx, proxy, expando.handle_mut());
|
||||
JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result)
|
||||
}
|
||||
|
||||
/// Deletes an expando off the given `proxy`.
|
||||
pub(crate) unsafe extern "C" fn delete(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
bp: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
get_expando_object(proxy, expando.handle_mut());
|
||||
if expando.is_null() {
|
||||
(*bp).code_ = 0 /* OkCode */;
|
||||
return true;
|
||||
}
|
||||
|
||||
delete_property_by_id(cx, expando.handle(), Handle::from_raw(id), bp)
|
||||
}
|
||||
|
||||
/// Controls whether the Extensible bit can be changed
|
||||
pub(crate) unsafe extern "C" fn prevent_extensions(
|
||||
_cx: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
|
||||
true
|
||||
}
|
||||
|
||||
/// Reports whether the object is Extensible
|
||||
pub(crate) unsafe extern "C" fn is_extensible(
|
||||
_cx: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
succeeded: *mut bool,
|
||||
) -> bool {
|
||||
*succeeded = true;
|
||||
true
|
||||
}
|
||||
|
||||
/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as
|
||||
/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior
|
||||
/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s
|
||||
/// prototype in `proto`. Otherwise set `*isOrdinary` to false. In case of
|
||||
/// error, both outparams have unspecified value.
|
||||
///
|
||||
/// This implementation always handles the case of the ordinary
|
||||
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
|
||||
/// necessary for maybe-cross-origin objects.
|
||||
pub(crate) unsafe extern "C" fn get_prototype_if_ordinary(
|
||||
_: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
is_ordinary: *mut bool,
|
||||
proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
*is_ordinary = true;
|
||||
proto.set(GetStaticPrototype(proxy.get()));
|
||||
true
|
||||
}
|
||||
|
||||
/// Get the expando object, or null if there is none.
|
||||
pub(crate) unsafe fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandleObject) {
|
||||
assert!(is_dom_proxy(obj.get()));
|
||||
let val = &mut UndefinedValue();
|
||||
GetProxyPrivate(obj.get(), val);
|
||||
expando.set(if val.is_undefined() {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
val.to_object()
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the expando object, or create it if it doesn't exist yet.
|
||||
/// Fails on JSAPI failure.
|
||||
pub(crate) unsafe fn ensure_expando_object(
|
||||
cx: *mut JSContext,
|
||||
obj: RawHandleObject,
|
||||
mut expando: MutableHandleObject,
|
||||
) {
|
||||
assert!(is_dom_proxy(obj.get()));
|
||||
get_expando_object(obj, expando.reborrow());
|
||||
if expando.is_null() {
|
||||
expando.set(JS_NewObjectWithGivenProto(
|
||||
cx,
|
||||
ptr::null_mut(),
|
||||
HandleObject::null(),
|
||||
));
|
||||
assert!(!expando.is_null());
|
||||
|
||||
SetProxyPrivate(obj.get(), &ObjectValue(expando.get()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the property descriptor's object to `obj` and set it to enumerable,
|
||||
/// and writable if `readonly` is true.
|
||||
pub(crate) fn set_property_descriptor(
|
||||
desc: MutableHandle<PropertyDescriptor>,
|
||||
value: HandleValue,
|
||||
attrs: u32,
|
||||
is_none: &mut bool,
|
||||
) {
|
||||
unsafe {
|
||||
SetDataPropertyDescriptor(desc, value, attrs);
|
||||
}
|
||||
*is_none = false;
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#isplatformobjectsameorigin-(-o-)>
|
||||
pub(crate) unsafe fn is_platform_object_same_origin(
|
||||
cx: SafeJSContext,
|
||||
|
@ -239,7 +71,7 @@ pub(crate) unsafe fn is_platform_object_same_origin(
|
|||
/// What this function does corresponds to the operations in
|
||||
/// <https://html.spec.whatwg.org/multipage/#the-location-interface> denoted as
|
||||
/// "Throw a `SecurityError` DOMException".
|
||||
pub(crate) unsafe fn report_cross_origin_denial(
|
||||
pub(crate) unsafe fn report_cross_origin_denial<D: DomTypes>(
|
||||
cx: SafeJSContext,
|
||||
id: RawHandleId,
|
||||
access: &str,
|
||||
|
@ -251,75 +83,17 @@ pub(crate) unsafe fn report_cross_origin_denial(
|
|||
);
|
||||
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
|
||||
if !JS_IsExceptionPending(*cx) {
|
||||
let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
|
||||
let global = D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
|
||||
// TODO: include `id` and `access` in the exception message
|
||||
throw_dom_exception(cx, &global, Error::Security, CanGc::note());
|
||||
<D as DomHelpers<D>>::throw_dom_exception(cx, &global, Error::Security, CanGc::note());
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
unsafe fn id_to_source(cx: SafeJSContext, id: RawHandleId) -> Option<DOMString> {
|
||||
rooted!(in(*cx) let mut value = UndefinedValue());
|
||||
rooted!(in(*cx) let mut jsstr = ptr::null_mut::<jsapi::JSString>());
|
||||
jsapi::JS_IdToValue(*cx, id.get(), value.handle_mut().into())
|
||||
.then(|| {
|
||||
jsstr.set(jsapi::JS_ValueToSource(*cx, value.handle().into()));
|
||||
jsstr.get()
|
||||
})
|
||||
.and_then(ptr::NonNull::new)
|
||||
.map(|jsstr| jsstring_to_str(*cx, jsstr))
|
||||
}
|
||||
|
||||
/// Property and method specs that correspond to the elements of
|
||||
/// [`CrossOriginProperties(O)`].
|
||||
///
|
||||
/// [`CrossOriginProperties(O)`]: https://html.spec.whatwg.org/multipage/#crossoriginproperties-(-o-)
|
||||
pub(crate) struct CrossOriginProperties {
|
||||
pub(crate) attributes: &'static [JSPropertySpec],
|
||||
pub(crate) methods: &'static [JSFunctionSpec],
|
||||
}
|
||||
|
||||
impl CrossOriginProperties {
|
||||
/// Enumerate the property keys defined by `self`.
|
||||
fn keys(&self) -> impl Iterator<Item = *const c_char> + '_ {
|
||||
// Safety: All cross-origin property keys are strings, not symbols
|
||||
self.attributes
|
||||
.iter()
|
||||
.map(|spec| unsafe { spec.name.string_ })
|
||||
.chain(self.methods.iter().map(|spec| unsafe { spec.name.string_ }))
|
||||
.filter(|ptr| !ptr.is_null())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginOwnPropertyKeys`].
|
||||
///
|
||||
/// [`CrossOriginOwnPropertyKeys`]: https://html.spec.whatwg.org/multipage/#crossoriginownpropertykeys-(-o-)
|
||||
pub(crate) unsafe fn cross_origin_own_property_keys(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
props: RawMutableHandleIdVector,
|
||||
) -> bool {
|
||||
// > 2. For each `e` of `! CrossOriginProperties(O)`, append
|
||||
// > `e.[[Property]]` to `keys`.
|
||||
for key in cross_origin_properties.keys() {
|
||||
rooted!(in(*cx) let rooted = JS_AtomizeAndPinString(*cx, key));
|
||||
rooted!(in(*cx) let mut rooted_jsid: jsid);
|
||||
RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), rooted_jsid.handle_mut());
|
||||
AppendToIdVector(props, rooted_jsid.handle());
|
||||
}
|
||||
|
||||
// > 3. Return the concatenation of `keys` and `« "then", @@toStringTag,
|
||||
// > @@hasInstance, @@isConcatSpreadable »`.
|
||||
append_cross_origin_allowlisted_prop_keys(cx, props);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of `[[Set]]` for [`Location`].
|
||||
///
|
||||
/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-set
|
||||
pub(crate) unsafe extern "C" fn maybe_cross_origin_set_rawcx(
|
||||
pub(crate) unsafe extern "C" fn maybe_cross_origin_set_rawcx<D: DomTypes>(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
|
@ -329,8 +103,8 @@ pub(crate) unsafe extern "C" fn maybe_cross_origin_set_rawcx(
|
|||
) -> bool {
|
||||
let cx = SafeJSContext::from_ptr(cx);
|
||||
|
||||
if !is_platform_object_same_origin(cx, proxy) {
|
||||
return cross_origin_set(cx, proxy, id, v, receiver, result);
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
return cross_origin_set::<D>(cx, proxy, id, v, receiver, result);
|
||||
}
|
||||
|
||||
// Safe to enter the Realm of proxy now.
|
||||
|
@ -362,21 +136,10 @@ pub(crate) unsafe extern "C" fn maybe_cross_origin_set_rawcx(
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
|
||||
_: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
is_ordinary: *mut bool,
|
||||
_proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
// We have a custom `[[GetPrototypeOf]]`, so return `false`
|
||||
*is_ordinary = false;
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of `[[GetPrototypeOf]]` for [`Location`].
|
||||
///
|
||||
/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-getprototypeof
|
||||
pub(crate) unsafe fn maybe_cross_origin_get_prototype<D: crate::DomTypes>(
|
||||
pub(crate) unsafe fn maybe_cross_origin_get_prototype<D: DomTypes>(
|
||||
cx: SafeJSContext,
|
||||
proxy: RawHandleObject,
|
||||
get_proto_object: unsafe fn(cx: SafeJSContext, global: HandleObject, rval: MutableHandleObject),
|
||||
|
@ -399,46 +162,13 @@ pub(crate) unsafe fn maybe_cross_origin_get_prototype<D: crate::DomTypes>(
|
|||
true
|
||||
}
|
||||
|
||||
/// Implementation of `[[SetPrototypeOf]]` for [`Location`] and [`WindowProxy`].
|
||||
///
|
||||
/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-setprototypeof
|
||||
/// [`WindowProxy`]: https://html.spec.whatwg.org/multipage/#windowproxy-setprototypeof
|
||||
pub(crate) unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
proto: RawHandleObject,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
// > 1. Return `! SetImmutablePrototype(this, V)`.
|
||||
//
|
||||
// <https://tc39.es/ecma262/#sec-set-immutable-prototype>:
|
||||
//
|
||||
// > 1. Assert: Either `Type(V)` is Object or `Type(V)` is Null.
|
||||
//
|
||||
// > 2. Let current be `? O.[[GetPrototypeOf]]()`.
|
||||
rooted!(in(cx) let mut current = ptr::null_mut::<JSObject>());
|
||||
if !jsapi::GetObjectProto(cx, proxy, current.handle_mut().into()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// > 3. If `SameValue(V, current)` is true, return true.
|
||||
if proto.get() == current.get() {
|
||||
(*result).code_ = 0 /* OkCode */;
|
||||
return true;
|
||||
}
|
||||
|
||||
// > 4. Return false.
|
||||
(*result).code_ = JSErrNum::JSMSG_CANT_SET_PROTO as usize;
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginGet`].
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object.
|
||||
///
|
||||
/// [`CrossOriginGet`]: https://html.spec.whatwg.org/multipage/#crossoriginget-(-o,-p,-receiver-)
|
||||
pub(crate) unsafe fn cross_origin_get(
|
||||
pub(crate) unsafe fn cross_origin_get<D: DomTypes>(
|
||||
cx: SafeJSContext,
|
||||
proxy: RawHandleObject,
|
||||
receiver: RawHandleValue,
|
||||
|
@ -482,7 +212,7 @@ pub(crate) unsafe fn cross_origin_get(
|
|||
rooted!(in(*cx) let mut getter = ptr::null_mut::<JSObject>());
|
||||
get_getter_object(&descriptor, getter.handle_mut().into());
|
||||
if getter.get().is_null() {
|
||||
return report_cross_origin_denial(cx, id, "get");
|
||||
return report_cross_origin_denial::<D>(cx, id, "get");
|
||||
}
|
||||
|
||||
rooted!(in(*cx) let mut getter_jsval = UndefinedValue());
|
||||
|
@ -504,7 +234,7 @@ pub(crate) unsafe fn cross_origin_get(
|
|||
/// for a maybe-cross-origin object.
|
||||
///
|
||||
/// [`CrossOriginSet`]: https://html.spec.whatwg.org/multipage/#crossoriginset-(-o,-p,-v,-receiver-)
|
||||
pub(crate) unsafe fn cross_origin_set(
|
||||
pub(crate) unsafe fn cross_origin_set<D: DomTypes>(
|
||||
cx: SafeJSContext,
|
||||
proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
|
@ -539,7 +269,7 @@ pub(crate) unsafe fn cross_origin_set(
|
|||
get_setter_object(&descriptor, setter.handle_mut().into());
|
||||
if setter.get().is_null() {
|
||||
// > 4. Throw a "SecurityError" DOMException.
|
||||
return report_cross_origin_denial(cx, id, "set");
|
||||
return report_cross_origin_denial::<D>(cx, id, "set");
|
||||
}
|
||||
|
||||
rooted!(in(*cx) let mut setter_jsval = UndefinedValue());
|
||||
|
@ -568,86 +298,13 @@ pub(crate) unsafe fn cross_origin_set(
|
|||
true
|
||||
}
|
||||
|
||||
unsafe fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
|
||||
if d.hasGetter_() {
|
||||
out.set(d.getter_);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_setter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
|
||||
if d.hasSetter_() {
|
||||
out.set(d.setter_);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#sec-isaccessordescriptor>
|
||||
fn is_accessor_descriptor(d: &PropertyDescriptor) -> bool {
|
||||
d.hasSetter_() || d.hasGetter_()
|
||||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#sec-isdatadescriptor>
|
||||
fn is_data_descriptor(d: &PropertyDescriptor) -> bool {
|
||||
d.hasWritable_() || d.hasValue_()
|
||||
}
|
||||
|
||||
/// Evaluate `CrossOriginGetOwnPropertyHelper(proxy, id) != null`.
|
||||
/// SpiderMonkey-specific.
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object.
|
||||
pub(crate) unsafe fn cross_origin_has_own(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
id: RawHandleId,
|
||||
bp: *mut bool,
|
||||
) -> bool {
|
||||
// TODO: Once we have the slot for the holder, it'd be more efficient to
|
||||
// use `ensure_cross_origin_property_holder`. We'll need `_proxy` to
|
||||
// do that.
|
||||
*bp = jsid_to_string(*cx, Handle::from_raw(id)).is_some_and(|key| {
|
||||
cross_origin_properties.keys().any(|defined_key| {
|
||||
let defined_key = CStr::from_ptr(defined_key);
|
||||
defined_key.to_bytes() == key.as_bytes()
|
||||
})
|
||||
});
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginGetOwnPropertyHelper`].
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object.
|
||||
///
|
||||
/// [`CrossOriginGetOwnPropertyHelper`]: https://html.spec.whatwg.org/multipage/#crossorigingetownpropertyhelper-(-o,-p-)
|
||||
pub(crate) unsafe fn cross_origin_get_own_property_helper(
|
||||
cx: SafeJSContext,
|
||||
proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
id: RawHandleId,
|
||||
desc: RawMutableHandle<PropertyDescriptor>,
|
||||
is_none: &mut bool,
|
||||
) -> bool {
|
||||
rooted!(in(*cx) let mut holder = ptr::null_mut::<JSObject>());
|
||||
|
||||
ensure_cross_origin_property_holder(
|
||||
cx,
|
||||
proxy,
|
||||
cross_origin_properties,
|
||||
holder.handle_mut().into(),
|
||||
);
|
||||
|
||||
JS_GetOwnPropertyDescriptorById(*cx, holder.handle().into(), id, desc, is_none)
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginPropertyFallback`].
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object.
|
||||
///
|
||||
/// [`CrossOriginPropertyFallback`]: https://html.spec.whatwg.org/multipage/#crossoriginpropertyfallback-(-p-)
|
||||
pub(crate) unsafe fn cross_origin_property_fallback(
|
||||
pub(crate) unsafe fn cross_origin_property_fallback<D: DomTypes>(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
|
@ -671,96 +328,5 @@ pub(crate) unsafe fn cross_origin_property_fallback(
|
|||
}
|
||||
|
||||
// > 2. Throw a `SecurityError` `DOMException`.
|
||||
report_cross_origin_denial(cx, id, "access")
|
||||
}
|
||||
|
||||
const ALLOWLISTED_SYMBOL_CODES: &[SymbolCode] = &[
|
||||
SymbolCode::toStringTag,
|
||||
SymbolCode::hasInstance,
|
||||
SymbolCode::isConcatSpreadable,
|
||||
];
|
||||
|
||||
unsafe fn is_cross_origin_allowlisted_prop(cx: SafeJSContext, id: RawHandleId) -> bool {
|
||||
if jsid_to_string(*cx, Handle::from_raw(id)).is_some_and(|st| st == "then") {
|
||||
return true;
|
||||
}
|
||||
|
||||
rooted!(in(*cx) let mut allowed_id: jsid);
|
||||
ALLOWLISTED_SYMBOL_CODES.iter().any(|&allowed_code| {
|
||||
allowed_id.set(SymbolId(GetWellKnownSymbol(*cx, allowed_code)));
|
||||
// `jsid`s containing `JS::Symbol *` can be compared by
|
||||
// referential equality
|
||||
allowed_id.get().asBits_ == id.asBits_
|
||||
})
|
||||
}
|
||||
|
||||
/// Append `« "then", @@toStringTag, @@hasInstance, @@isConcatSpreadable »` to
|
||||
/// `props`. This is used to implement [`CrossOriginOwnPropertyKeys`].
|
||||
///
|
||||
/// [`CrossOriginOwnPropertyKeys`]: https://html.spec.whatwg.org/multipage/#crossoriginownpropertykeys-(-o-)
|
||||
unsafe fn append_cross_origin_allowlisted_prop_keys(
|
||||
cx: SafeJSContext,
|
||||
props: RawMutableHandleIdVector,
|
||||
) {
|
||||
rooted!(in(*cx) let mut id: jsid);
|
||||
|
||||
let jsstring = JS_AtomizeAndPinString(*cx, c"then".as_ptr());
|
||||
rooted!(in(*cx) let rooted = jsstring);
|
||||
RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), id.handle_mut());
|
||||
AppendToIdVector(props, id.handle());
|
||||
|
||||
for &allowed_code in ALLOWLISTED_SYMBOL_CODES.iter() {
|
||||
id.set(SymbolId(GetWellKnownSymbol(*cx, allowed_code)));
|
||||
AppendToIdVector(props, id.handle());
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the holder for cross-origin properties for the current global of the
|
||||
/// `JSContext`, creating one and storing it in a slot of the proxy object if it
|
||||
/// doesn't exist yet.
|
||||
///
|
||||
/// This essentially creates a cache of [`CrossOriginGetOwnPropertyHelper`]'s
|
||||
/// results for all property keys.
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object. The `out_holder` return value will always
|
||||
/// be in the Realm of `cx`.
|
||||
///
|
||||
/// [`CrossOriginGetOwnPropertyHelper`]: https://html.spec.whatwg.org/multipage/#crossorigingetownpropertyhelper-(-o,-p-)
|
||||
unsafe fn ensure_cross_origin_property_holder(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
out_holder: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
// TODO: We don't have the slot to store the holder yet. For now,
|
||||
// the holder is constructed every time this function is called,
|
||||
// which is not only inefficient but also deviates from the
|
||||
// specification in a subtle yet observable way.
|
||||
|
||||
// Create a holder for the current Realm
|
||||
out_holder.set(jsapi::JS_NewObjectWithGivenProto(
|
||||
*cx,
|
||||
ptr::null_mut(),
|
||||
RawHandleObject::null(),
|
||||
));
|
||||
|
||||
if out_holder.get().is_null() ||
|
||||
!jsapi::JS_DefineProperties(
|
||||
*cx,
|
||||
out_holder.handle(),
|
||||
cross_origin_properties.attributes.as_ptr(),
|
||||
) ||
|
||||
!jsapi::JS_DefineFunctions(
|
||||
*cx,
|
||||
out_holder.handle(),
|
||||
cross_origin_properties.methods.as_ptr(),
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Store the holder in the slot that we don't have yet.
|
||||
|
||||
true
|
||||
report_cross_origin_denial::<D>(cx, id, "access")
|
||||
}
|
||||
|
|
|
@ -57,26 +57,6 @@ impl Drop for ThreadLocalStackRoots<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a slice of references to DOM objects.
|
||||
pub(crate) trait DomSlice<T>
|
||||
where
|
||||
T: JSTraceable + DomObject,
|
||||
{
|
||||
/// Returns the slice of `T` references.
|
||||
fn r(&self) -> &[&T];
|
||||
}
|
||||
|
||||
impl<T> DomSlice<T> for [Dom<T>]
|
||||
where
|
||||
T: JSTraceable + DomObject,
|
||||
{
|
||||
#[inline]
|
||||
fn r(&self) -> &[&T] {
|
||||
let _ = mem::transmute::<Dom<T>, &T>;
|
||||
unsafe { &*(self as *const [Dom<T>] as *const [&T]) }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ToLayout<T> {
|
||||
/// Returns `LayoutDom<T>` containing the same pointer.
|
||||
///
|
||||
|
|
|
@ -5,29 +5,34 @@
|
|||
//! Various utilities to glue JavaScript and the DOM implementation together.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::os::raw::c_char;
|
||||
use std::thread::LocalKey;
|
||||
use std::{ptr, slice};
|
||||
|
||||
use js::conversions::ToJSValConvertible;
|
||||
use js::glue::{IsWrapper, UnwrapObjectDynamic, UnwrapObjectStatic};
|
||||
use js::glue::{IsWrapper, JSPrincipalsCallbacks, UnwrapObjectDynamic, UnwrapObjectStatic};
|
||||
use js::jsapi::{
|
||||
CallArgs, DOMCallbacks, HandleId as RawHandleId, HandleObject as RawHandleObject, Heap,
|
||||
CallArgs, DOMCallbacks, HandleId as RawHandleId, HandleObject as RawHandleObject,
|
||||
JS_DeprecatedStringHasLatin1Chars, JS_EnumerateStandardClasses, JS_FreezeObject,
|
||||
JS_GetLatin1StringCharsAndLength, JS_IsGlobalObject, JS_ResolveStandardClass, JSContext,
|
||||
JSObject, JSTracer, MutableHandleIdVector as RawMutableHandleIdVector,
|
||||
JSObject, MutableHandleIdVector as RawMutableHandleIdVector,
|
||||
};
|
||||
use js::rust::{Handle, HandleObject, MutableHandleValue, get_object_class, is_dom_class};
|
||||
|
||||
use crate::DomTypes;
|
||||
use crate::dom::bindings::codegen::{InterfaceObjectMap, PrototypeList};
|
||||
use crate::dom::bindings::constructor::call_html_constructor;
|
||||
use crate::dom::bindings::constructor::{
|
||||
call_html_constructor, pop_current_element_queue, push_new_element_queue,
|
||||
};
|
||||
use crate::dom::bindings::conversions::DerivedFrom;
|
||||
use crate::dom::bindings::error::{Error, throw_dom_exception};
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::error::{Error, report_pending_exception, throw_dom_exception};
|
||||
use crate::dom::bindings::principals::PRINCIPALS_CALLBACKS;
|
||||
use crate::dom::bindings::proxyhandler::is_platform_object_same_origin;
|
||||
use crate::dom::bindings::reflector::{DomObject, DomObjectWrap, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::settings_stack::{self, StackEntry};
|
||||
use crate::dom::bindings::trace::trace_object;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::windowproxy::WindowProxyHandler;
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
|
@ -100,22 +105,8 @@ fn is_platform_object(
|
|||
}
|
||||
}
|
||||
|
||||
/// Trace the resources held by reserved slots of a global object
|
||||
pub(crate) unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
|
||||
let array = get_proto_or_iface_array(obj);
|
||||
for proto in (*array).iter() {
|
||||
if !proto.is_null() {
|
||||
trace_object(
|
||||
tracer,
|
||||
"prototype",
|
||||
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumerate lazy properties of a global object.
|
||||
pub(crate) unsafe extern "C" fn enumerate_global(
|
||||
pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
|
||||
cx: *mut JSContext,
|
||||
obj: RawHandleObject,
|
||||
_props: RawMutableHandleIdVector,
|
||||
|
@ -125,14 +116,14 @@ pub(crate) unsafe extern "C" fn enumerate_global(
|
|||
if !JS_EnumerateStandardClasses(cx, obj) {
|
||||
return false;
|
||||
}
|
||||
for init_fun in InterfaceObjectMap::MAP.values() {
|
||||
for init_fun in <D as DomHelpers<D>>::interface_map().values() {
|
||||
init_fun(SafeJSContext::from_ptr(cx), Handle::from_raw(obj));
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Resolve a lazy global property, for interface objects and named constructors.
|
||||
pub(crate) unsafe extern "C" fn resolve_global(
|
||||
pub(crate) unsafe extern "C" fn resolve_global<D: DomTypes>(
|
||||
cx: *mut JSContext,
|
||||
obj: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
|
@ -160,7 +151,7 @@ pub(crate) unsafe extern "C" fn resolve_global(
|
|||
assert!(!ptr.is_null());
|
||||
let bytes = slice::from_raw_parts(ptr, length);
|
||||
|
||||
if let Some(init_fun) = InterfaceObjectMap::MAP.get(bytes) {
|
||||
if let Some(init_fun) = <D as DomHelpers<D>>::interface_map().get(bytes) {
|
||||
init_fun(SafeJSContext::from_ptr(cx), Handle::from_raw(obj));
|
||||
*rval = true;
|
||||
} else {
|
||||
|
@ -184,30 +175,14 @@ pub(crate) const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
|
|||
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
|
||||
};
|
||||
|
||||
// Generic method for returning libc::c_void from caller
|
||||
pub(crate) trait AsVoidPtr {
|
||||
fn as_void_ptr(&self) -> *const libc::c_void;
|
||||
}
|
||||
impl<T> AsVoidPtr for T {
|
||||
fn as_void_ptr(&self) -> *const libc::c_void {
|
||||
self as *const T as *const libc::c_void
|
||||
}
|
||||
}
|
||||
|
||||
// Generic method for returning c_char from caller
|
||||
pub(crate) trait AsCCharPtrPtr {
|
||||
fn as_c_char_ptr(&self) -> *const c_char;
|
||||
}
|
||||
|
||||
impl AsCCharPtrPtr for [u8] {
|
||||
fn as_c_char_ptr(&self) -> *const c_char {
|
||||
self as *const [u8] as *const c_char
|
||||
}
|
||||
}
|
||||
|
||||
/// Operations that must be invoked from the generated bindings.
|
||||
pub(crate) trait DomHelpers<D: DomTypes> {
|
||||
fn throw_dom_exception(cx: SafeJSContext, global: &D::GlobalScope, result: Error);
|
||||
fn throw_dom_exception(
|
||||
cx: SafeJSContext,
|
||||
global: &D::GlobalScope,
|
||||
result: Error,
|
||||
can_gc: CanGc,
|
||||
);
|
||||
|
||||
unsafe fn call_html_constructor<T: DerivedFrom<D::Element> + DomObject>(
|
||||
cx: SafeJSContext,
|
||||
|
@ -219,6 +194,27 @@ pub(crate) trait DomHelpers<D: DomTypes> {
|
|||
) -> bool;
|
||||
|
||||
fn settings_stack() -> &'static LocalKey<RefCell<Vec<StackEntry<D>>>>;
|
||||
|
||||
fn principals_callbacks() -> &'static JSPrincipalsCallbacks;
|
||||
|
||||
fn is_platform_object_same_origin(cx: SafeJSContext, obj: RawHandleObject) -> bool;
|
||||
|
||||
fn interface_map() -> &'static phf::Map<&'static [u8], for<'a> fn(SafeJSContext, HandleObject)>;
|
||||
|
||||
fn push_new_element_queue();
|
||||
fn pop_current_element_queue(can_gc: CanGc);
|
||||
|
||||
fn reflect_dom_object<T, U>(obj: Box<T>, global: &U, can_gc: CanGc) -> DomRoot<T>
|
||||
where
|
||||
T: DomObject + DomObjectWrap<D>,
|
||||
U: DerivedFrom<D::GlobalScope>;
|
||||
|
||||
fn report_pending_exception(
|
||||
cx: SafeJSContext,
|
||||
dispatch_event: bool,
|
||||
realm: InRealm,
|
||||
can_gc: CanGc,
|
||||
);
|
||||
}
|
||||
|
||||
impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
|
||||
|
@ -226,8 +222,9 @@ impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
|
|||
cx: SafeJSContext,
|
||||
global: &<crate::DomTypeHolder as DomTypes>::GlobalScope,
|
||||
result: Error,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
throw_dom_exception(cx, global, result, CanGc::note())
|
||||
throw_dom_exception(cx, global, result, can_gc)
|
||||
}
|
||||
|
||||
unsafe fn call_html_constructor<
|
||||
|
@ -246,4 +243,41 @@ impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
|
|||
fn settings_stack() -> &'static LocalKey<RefCell<Vec<StackEntry<crate::DomTypeHolder>>>> {
|
||||
&settings_stack::STACK
|
||||
}
|
||||
|
||||
fn principals_callbacks() -> &'static JSPrincipalsCallbacks {
|
||||
&PRINCIPALS_CALLBACKS
|
||||
}
|
||||
|
||||
fn is_platform_object_same_origin(cx: SafeJSContext, obj: RawHandleObject) -> bool {
|
||||
unsafe { is_platform_object_same_origin(cx, obj) }
|
||||
}
|
||||
|
||||
fn interface_map() -> &'static phf::Map<&'static [u8], for<'a> fn(SafeJSContext, HandleObject)>
|
||||
{
|
||||
&InterfaceObjectMap::MAP
|
||||
}
|
||||
|
||||
fn push_new_element_queue() {
|
||||
push_new_element_queue()
|
||||
}
|
||||
fn pop_current_element_queue(can_gc: CanGc) {
|
||||
pop_current_element_queue(can_gc)
|
||||
}
|
||||
|
||||
fn reflect_dom_object<T, U>(obj: Box<T>, global: &U, can_gc: CanGc) -> DomRoot<T>
|
||||
where
|
||||
T: DomObject + DomObjectWrap<crate::DomTypeHolder>,
|
||||
U: DerivedFrom<GlobalScope>,
|
||||
{
|
||||
reflect_dom_object(obj, global, can_gc)
|
||||
}
|
||||
|
||||
fn report_pending_exception(
|
||||
cx: SafeJSContext,
|
||||
dispatch_event: bool,
|
||||
realm: InRealm,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
report_pending_exception(cx, dispatch_event, realm, can_gc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
|
|||
// https://w3c.github.io/FileAPI/#text-method-algo
|
||||
fn Text(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
let global = self.global();
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
let id = self.get_blob_url_id();
|
||||
global.read_file_async(
|
||||
|
@ -266,7 +266,7 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
|
|||
// https://w3c.github.io/FileAPI/#arraybuffer-method-algo
|
||||
fn ArrayBuffer(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
let global = self.global();
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
|
||||
let id = self.get_blob_url_id();
|
||||
|
|
|
@ -300,7 +300,7 @@ where
|
|||
T: AsyncBluetoothListener + DomObject + 'static,
|
||||
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID>,
|
||||
{
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
|
||||
let result_uuid = if let Some(u) = uuid {
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
use std::cell::LazyCell;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use script_bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId, TextTypeId};
|
||||
|
||||
use crate::dom::bindings::cell::{DomRefCell, Ref};
|
||||
use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
|
||||
use crate::dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId, TextTypeId};
|
||||
use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
|
||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
|
|
|
@ -41,7 +41,7 @@ impl ClipboardEventType {
|
|||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct ClipboardEvent {
|
||||
pub(crate) struct ClipboardEvent {
|
||||
event: Event,
|
||||
clipboard_data: MutNullableDom<DataTransfer>,
|
||||
}
|
||||
|
|
|
@ -4384,7 +4384,7 @@ impl Document {
|
|||
// https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
|
||||
pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
|
||||
// Step 1
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
let mut error = false;
|
||||
|
||||
|
@ -4452,7 +4452,7 @@ impl Document {
|
|||
pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
let global = self.global();
|
||||
// Step 1
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
// Step 2
|
||||
if self.fullscreen_element.get().is_none() {
|
||||
|
|
|
@ -2696,7 +2696,7 @@ impl GlobalScope {
|
|||
options: &ImageBitmapOptions,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
if options.resizeWidth.is_some_and(|w| w == 0) {
|
||||
p.reject_error(Error::InvalidState, can_gc);
|
||||
|
|
|
@ -27,6 +27,9 @@ use net_traits::{
|
|||
ResourceTimingType,
|
||||
};
|
||||
use pixels::Image;
|
||||
use script_bindings::codegen::InheritTypes::{
|
||||
ElementTypeId, HTMLElementTypeId, HTMLMediaElementTypeId, NodeTypeId,
|
||||
};
|
||||
use script_layout_interface::MediaFrame;
|
||||
use servo_config::pref;
|
||||
use servo_media::player::audio::AudioRenderer;
|
||||
|
@ -60,9 +63,6 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
|||
use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode};
|
||||
use crate::dom::bindings::codegen::Bindings::URLBinding::URLMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
|
||||
use crate::dom::bindings::codegen::InheritTypes::{
|
||||
ElementTypeId, HTMLElementTypeId, HTMLMediaElementTypeId, NodeTypeId,
|
||||
};
|
||||
use crate::dom::bindings::codegen::UnionTypes::{
|
||||
MediaStreamOrBlob, VideoTrackOrAudioTrackOrTextTrack,
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ use dom_struct::dom_struct;
|
|||
use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
|
||||
use js::gc::RootedVec;
|
||||
use js::rust::HandleObject;
|
||||
use script_bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId};
|
||||
|
||||
use crate::ScriptThread;
|
||||
use crate::dom::attr::Attr;
|
||||
|
@ -19,7 +20,6 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Bindi
|
|||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
||||
ShadowRootMode, SlotAssignmentMode,
|
||||
};
|
||||
use crate::dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId};
|
||||
use crate::dom::bindings::codegen::UnionTypes::ElementOrText;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
|
@ -35,7 +35,7 @@ use crate::script_runtime::CanGc;
|
|||
|
||||
/// <https://html.spec.whatwg.org/multipage/#the-slot-element>
|
||||
#[dom_struct]
|
||||
pub struct HTMLSlotElement {
|
||||
pub(crate) struct HTMLSlotElement {
|
||||
htmlelement: HTMLElement,
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#slot-assigned-nodes>
|
||||
|
|
|
@ -79,7 +79,7 @@ impl MediaDevicesMethods<crate::DomTypeHolder> for MediaDevices {
|
|||
/// <https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices>
|
||||
fn EnumerateDevices(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
// Step 1.
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
|
||||
|
||||
// Step 2.
|
||||
|
|
|
@ -205,6 +205,7 @@
|
|||
#[macro_use]
|
||||
pub(crate) mod macros;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) mod types {
|
||||
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InterfaceTypes.rs"));
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ use js::rust::HandleObject;
|
|||
use libc::{self, c_void, uintptr_t};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use pixels::{Image, ImageMetadata};
|
||||
use script_bindings::codegen::InheritTypes::DocumentFragmentTypeId;
|
||||
use script_layout_interface::{
|
||||
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType, QueryMsg,
|
||||
SVGSVGData, StyleData, TrustedNodeAddress,
|
||||
|
@ -71,7 +72,6 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
|||
ShadowRootMode, SlotAssignmentMode,
|
||||
};
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId;
|
||||
use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
|
||||
use crate::dom::bindings::conversions::{self, DerivedFrom};
|
||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
|
|
|
@ -95,7 +95,7 @@ impl Permissions {
|
|||
let p = match promise {
|
||||
Some(promise) => promise,
|
||||
None => {
|
||||
let in_realm_proof = AlreadyInRealm::assert();
|
||||
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
|
||||
Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc)
|
||||
},
|
||||
};
|
||||
|
|
|
@ -57,6 +57,7 @@ use num_traits::ToPrimitive;
|
|||
use profile_traits::ipc as ProfiledIpc;
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||
use script_bindings::interfaces::WindowHelpers;
|
||||
use script_layout_interface::{
|
||||
FragmentType, Layout, PendingImageState, QueryMsg, Reflow, ReflowGoal, ReflowRequest,
|
||||
TrustedNodeAddress, combine_id_with_fragment_type,
|
||||
|
@ -3122,3 +3123,13 @@ unsafe extern "C" fn dump_js_stack(cx: *mut RawJSContext) {
|
|||
DumpJSStack(cx, true, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowHelpers for Window {
|
||||
fn create_named_properties_object(
|
||||
cx: JSContext,
|
||||
proto: HandleObject,
|
||||
object: MutableHandleObject,
|
||||
) {
|
||||
Self::create_named_properties_object(cx, proto, object)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,18 @@
|
|||
|
||||
use js::jsapi::{GetCurrentRealmOrNull, JSAutoRealm};
|
||||
|
||||
use crate::DomTypes;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::globalscope::GlobalScopeHelpers;
|
||||
use crate::script_runtime::JSContext;
|
||||
|
||||
pub(crate) struct AlreadyInRealm(());
|
||||
|
||||
impl AlreadyInRealm {
|
||||
#![allow(unsafe_code)]
|
||||
pub(crate) fn assert() -> AlreadyInRealm {
|
||||
pub(crate) fn assert<D: DomTypes>() -> AlreadyInRealm {
|
||||
unsafe {
|
||||
assert!(!GetCurrentRealmOrNull(*GlobalScope::get_cx()).is_null());
|
||||
assert!(!GetCurrentRealmOrNull(*D::GlobalScope::get_cx()).is_null());
|
||||
}
|
||||
AlreadyInRealm(())
|
||||
}
|
||||
|
@ -55,9 +56,13 @@ impl InRealm<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enter_realm(object: &impl DomObject) -> JSAutoRealm {
|
||||
pub(crate) fn enter_realm_generic<D: DomTypes>(object: &impl DomObject) -> JSAutoRealm {
|
||||
JSAutoRealm::new(
|
||||
*GlobalScope::get_cx(),
|
||||
*D::GlobalScope::get_cx(),
|
||||
object.reflector().get_jsobject().get(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn enter_realm(object: &impl DomObject) -> JSAutoRealm {
|
||||
enter_realm_generic::<crate::DomTypeHolder>(object)
|
||||
}
|
||||
|
|
|
@ -588,6 +588,7 @@ DOMInterfaces = {
|
|||
'Window': {
|
||||
'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap'],
|
||||
'inRealms': ['Fetch', 'GetOpener'],
|
||||
'additionalTraits': ['script_bindings::interfaces::WindowHelpers'],
|
||||
},
|
||||
|
||||
'WindowProxy' : {
|
||||
|
|
|
@ -2279,8 +2279,6 @@ class CGImports(CGWrapper):
|
|||
if t.isInterface() or t.isNamespace():
|
||||
name = getIdentifier(t).name
|
||||
descriptor = descriptorProvider.getDescriptor(name)
|
||||
if name != 'GlobalScope':
|
||||
extras += [descriptor.path]
|
||||
parentName = descriptor.getParentName()
|
||||
while parentName:
|
||||
descriptor = descriptorProvider.getDescriptor(parentName)
|
||||
|
@ -2289,7 +2287,7 @@ class CGImports(CGWrapper):
|
|||
elif t.isType() and t.isRecord():
|
||||
extras += ['script_bindings::record::Record']
|
||||
elif isinstance(t, IDLPromiseType):
|
||||
extras += ['crate::dom::promise::Promise']
|
||||
pass
|
||||
else:
|
||||
if t.isEnum():
|
||||
extras += [f'{getModuleFromObject(t)}::{getIdentifier(t).name}Values']
|
||||
|
@ -2339,15 +2337,15 @@ def DOMClassTypeId(desc):
|
|||
inner = ""
|
||||
if desc.hasDescendants():
|
||||
if desc.interface.getExtendedAttribute("Abstract"):
|
||||
return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { abstract_: () }"
|
||||
return "script_bindings::codegen::InheritTypes::TopTypeId { abstract_: () }"
|
||||
name = desc.interface.identifier.name
|
||||
inner = f"(crate::dom::bindings::codegen::InheritTypes::{name}TypeId::{name})"
|
||||
inner = f"(script_bindings::codegen::InheritTypes::{name}TypeId::{name})"
|
||||
elif len(protochain) == 1:
|
||||
return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { alone: () }"
|
||||
return "script_bindings::codegen::InheritTypes::TopTypeId { alone: () }"
|
||||
reversed_protochain = list(reversed(protochain))
|
||||
for (child, parent) in zip(reversed_protochain, reversed_protochain[1:]):
|
||||
inner = f"(crate::dom::bindings::codegen::InheritTypes::{parent}TypeId::{child}{inner})"
|
||||
return f"crate::dom::bindings::codegen::InheritTypes::TopTypeId {{ {protochain[0].lower()}: {inner} }}"
|
||||
inner = f"(script_bindings::codegen::InheritTypes::{parent}TypeId::{child}{inner})"
|
||||
return f"script_bindings::codegen::InheritTypes::TopTypeId {{ {protochain[0].lower()}: {inner} }}"
|
||||
|
||||
|
||||
def DOMClass(descriptor):
|
||||
|
@ -2398,10 +2396,10 @@ class CGDOMJSClass(CGThing):
|
|||
}
|
||||
if self.descriptor.isGlobal():
|
||||
assert not self.descriptor.weakReferenceable
|
||||
args["enumerateHook"] = "Some(enumerate_global)"
|
||||
args["enumerateHook"] = "Some(enumerate_global::<D>)"
|
||||
args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL | JSCLASS_FOREGROUND_FINALIZE"
|
||||
args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
|
||||
args["resolveHook"] = "Some(resolve_global)"
|
||||
args["resolveHook"] = "Some(resolve_global::<D>)"
|
||||
args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook"
|
||||
elif self.descriptor.weakReferenceable:
|
||||
args["slots"] = "2"
|
||||
|
@ -2423,7 +2421,7 @@ pub(crate) fn init_class_ops<D: DomTypes>() {{
|
|||
}});
|
||||
}}
|
||||
|
||||
static Class: ThreadUnsafeOnceLock<DOMJSClass> = ThreadUnsafeOnceLock::new();
|
||||
pub(crate) static Class: ThreadUnsafeOnceLock<DOMJSClass> = ThreadUnsafeOnceLock::new();
|
||||
|
||||
pub(crate) fn init_domjs_class<D: DomTypes>() {{
|
||||
init_class_ops::<D>();
|
||||
|
@ -3185,7 +3183,7 @@ let raw = Root::new(MaybeUnreflectedDom::from_box(object));
|
|||
let origin = (*raw.as_ptr()).upcast::<D::GlobalScope>().origin();
|
||||
|
||||
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
|
||||
create_global_object(
|
||||
create_global_object::<D>(
|
||||
cx,
|
||||
&Class.get().base,
|
||||
raw.as_ptr() as *const libc::c_void,
|
||||
|
@ -3229,14 +3227,15 @@ class CGIDLInterface(CGThing):
|
|||
def define(self):
|
||||
interface = self.descriptor.interface
|
||||
name = interface.identifier.name
|
||||
bindingModule = f"crate::dom::bindings::codegen::GenericBindings::{toBindingPath(self.descriptor)}"
|
||||
if (interface.getUserData("hasConcreteDescendant", False)
|
||||
or interface.getUserData("hasProxyDescendant", False)):
|
||||
depth = self.descriptor.prototypeDepth
|
||||
check = f"class.interface_chain[{depth}] == PrototypeList::ID::{name}"
|
||||
elif self.descriptor.proxy:
|
||||
check = "ptr::eq(class, unsafe { Class.get() })"
|
||||
check = f"ptr::eq(class, unsafe {{ {bindingModule}::Class.get() }})"
|
||||
else:
|
||||
check = "ptr::eq(class, unsafe { &Class.get().dom_class })"
|
||||
check = f"ptr::eq(class, unsafe {{ &{bindingModule}::Class.get().dom_class }})"
|
||||
return f"""
|
||||
impl IDLInterface for {name} {{
|
||||
#[inline]
|
||||
|
@ -3279,6 +3278,7 @@ class CGDomObjectWrap(CGThing):
|
|||
|
||||
def define(self):
|
||||
ifaceName = self.descriptor.interface.identifier.name
|
||||
bindingModule = f"crate::dom::bindings::codegen::GenericBindings::{toBindingPath(self.descriptor)}"
|
||||
return f"""
|
||||
impl DomObjectWrap<crate::DomTypeHolder> for {firstCap(ifaceName)} {{
|
||||
const WRAP: unsafe fn(
|
||||
|
@ -3287,7 +3287,7 @@ impl DomObjectWrap<crate::DomTypeHolder> for {firstCap(ifaceName)} {{
|
|||
Option<HandleObject>,
|
||||
Box<Self>,
|
||||
CanGc,
|
||||
) -> Root<Dom<Self>> = Wrap::<crate::DomTypeHolder>;
|
||||
) -> Root<Dom<Self>> = {bindingModule}::Wrap::<crate::DomTypeHolder>;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
@ -3303,6 +3303,7 @@ class CGDomObjectIteratorWrap(CGThing):
|
|||
def define(self):
|
||||
assert self.descriptor.interface.isIteratorInterface()
|
||||
name = self.descriptor.interface.iterableInterface.identifier.name
|
||||
bindingModule = f"crate::dom::bindings::codegen::GenericBindings::{toBindingPath(self.descriptor)}"
|
||||
return f"""
|
||||
impl DomObjectIteratorWrap<crate::DomTypeHolder> for {name} {{
|
||||
const ITER_WRAP: unsafe fn(
|
||||
|
@ -3311,7 +3312,7 @@ impl DomObjectIteratorWrap<crate::DomTypeHolder> for {name} {{
|
|||
Option<HandleObject>,
|
||||
Box<IterableIterator<crate::DomTypeHolder, Self>>,
|
||||
CanGc,
|
||||
) -> Root<Dom<IterableIterator<crate::DomTypeHolder, Self>>> = Wrap::<crate::DomTypeHolder>;
|
||||
) -> Root<Dom<IterableIterator<crate::DomTypeHolder, Self>>> = {bindingModule}::Wrap::<crate::DomTypeHolder>;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
@ -3516,7 +3517,7 @@ assert!(!prototype_proto.is_null());""")]
|
|||
assert not self.haveUnscopables
|
||||
code.append(CGGeneric(f"""
|
||||
rooted!(in(*cx) let mut prototype_proto_proto = prototype_proto.get());
|
||||
dom::types::{name}::create_named_properties_object(cx, prototype_proto_proto.handle(), prototype_proto.handle_mut());
|
||||
D::{name}::create_named_properties_object(cx, prototype_proto_proto.handle(), prototype_proto.handle_mut());
|
||||
assert!(!prototype_proto.is_null());"""))
|
||||
|
||||
properties = {
|
||||
|
@ -3797,7 +3798,7 @@ class CGDefineProxyHandler(CGAbstractMethod):
|
|||
# `[[Set]]` (https://heycam.github.io/webidl/#legacy-platform-object-set) (yet).
|
||||
assert not self.descriptor.operations['IndexedGetter']
|
||||
assert not self.descriptor.operations['NamedGetter']
|
||||
customSet = 'Some(proxyhandler::maybe_cross_origin_set_rawcx)'
|
||||
customSet = 'Some(proxyhandler::maybe_cross_origin_set_rawcx::<D>)'
|
||||
|
||||
getOwnEnumerablePropertyKeys = "own_property_keys::<D>"
|
||||
if self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties") or \
|
||||
|
@ -3944,7 +3945,7 @@ class CGCallGenerator(CGThing):
|
|||
call = CGList([call, CGWrapper(args, pre="(", post=")")])
|
||||
|
||||
if hasCEReactions:
|
||||
self.cgRoot.append(CGGeneric("push_new_element_queue();\n"))
|
||||
self.cgRoot.append(CGGeneric("<D as DomHelpers<D>>::push_new_element_queue();\n"))
|
||||
|
||||
self.cgRoot.append(CGList([
|
||||
CGGeneric("let result: "),
|
||||
|
@ -3955,7 +3956,7 @@ class CGCallGenerator(CGThing):
|
|||
]))
|
||||
|
||||
if hasCEReactions:
|
||||
self.cgRoot.append(CGGeneric("pop_current_element_queue(CanGc::note());\n"))
|
||||
self.cgRoot.append(CGGeneric("<D as DomHelpers<D>>::pop_current_element_queue(CanGc::note());\n"))
|
||||
|
||||
if isFallible:
|
||||
if static:
|
||||
|
@ -3967,7 +3968,7 @@ class CGCallGenerator(CGThing):
|
|||
"let result = match result {\n"
|
||||
" Ok(result) => result,\n"
|
||||
" Err(e) => {\n"
|
||||
f" <D as DomHelpers<D>>::throw_dom_exception(cx, {glob}, e);\n"
|
||||
f" <D as DomHelpers<D>>::throw_dom_exception(cx, {glob}, e, CanGc::note());\n"
|
||||
f" return{errorResult};\n"
|
||||
" },\n"
|
||||
"};"))
|
||||
|
@ -5911,14 +5912,14 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
get += dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
if !proxyhandler::cross_origin_get_own_property_helper(
|
||||
cx, proxy, CROSS_ORIGIN_PROPERTIES.get(), id, desc, &mut *is_none
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if *is_none {
|
||||
return proxyhandler::cross_origin_property_fallback(cx, proxy, id, desc, &mut *is_none);
|
||||
return proxyhandler::cross_origin_property_fallback::<D>(cx, proxy, id, desc, &mut *is_none);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -6033,8 +6034,8 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
set += dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::report_cross_origin_denial(cx, id, "define");
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::report_cross_origin_denial::<D>(cx, id, "define");
|
||||
}
|
||||
|
||||
// Safe to enter the Realm of proxy now.
|
||||
|
@ -6092,8 +6093,8 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
set += dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::report_cross_origin_denial(cx, id, "delete");
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::report_cross_origin_denial::<D>(cx, id, "delete");
|
||||
}
|
||||
|
||||
// Safe to enter the Realm of proxy now.
|
||||
|
@ -6131,7 +6132,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
body += dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::cross_origin_own_property_keys(
|
||||
cx, proxy, CROSS_ORIGIN_PROPERTIES.get(), props
|
||||
);
|
||||
|
@ -6204,7 +6205,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
body += dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
// There are no enumerable cross-origin props, so we're done.
|
||||
return true;
|
||||
}
|
||||
|
@ -6255,7 +6256,7 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
indexed += dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::cross_origin_has_own(
|
||||
cx, proxy, CROSS_ORIGIN_PROPERTIES.get(), id, bp
|
||||
);
|
||||
|
@ -6328,8 +6329,8 @@ class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
|
|||
if self.descriptor.isMaybeCrossOriginObject():
|
||||
maybeCrossOriginGet = dedent(
|
||||
"""
|
||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::cross_origin_get(cx, proxy, receiver, id, vp);
|
||||
if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
|
||||
return proxyhandler::cross_origin_get::<D>(cx, proxy, receiver, id, vp);
|
||||
}
|
||||
|
||||
// Safe to enter the Realm of proxy now.
|
||||
|
@ -6589,7 +6590,7 @@ class CGDOMJSProxyHandlerDOMClass(CGThing):
|
|||
|
||||
def define(self):
|
||||
return f"""
|
||||
static Class: ThreadUnsafeOnceLock<DOMClass> = ThreadUnsafeOnceLock::new();
|
||||
pub(crate) static Class: ThreadUnsafeOnceLock<DOMClass> = ThreadUnsafeOnceLock::new();
|
||||
|
||||
pub(crate) fn init_proxy_handler_dom_class<D: DomTypes>() {{
|
||||
Class.set({DOMClass(self.descriptor)});
|
||||
|
@ -6990,18 +6991,11 @@ class CGDescriptor(CGThing):
|
|||
pass
|
||||
else:
|
||||
cgThings.append(CGDOMJSClass(descriptor))
|
||||
if not descriptor.interface.isIteratorInterface():
|
||||
cgThings.append(CGAssertInheritance(descriptor))
|
||||
pass
|
||||
|
||||
if descriptor.isGlobal():
|
||||
cgThings.append(CGWrapGlobalMethod(descriptor, properties))
|
||||
else:
|
||||
cgThings.append(CGWrapMethod(descriptor))
|
||||
if descriptor.interface.isIteratorInterface():
|
||||
cgThings.append(CGDomObjectIteratorWrap(descriptor))
|
||||
else:
|
||||
cgThings.append(CGDomObjectWrap(descriptor))
|
||||
reexports.append('Wrap')
|
||||
|
||||
haveUnscopables = False
|
||||
|
@ -7013,16 +7007,6 @@ class CGDescriptor(CGThing):
|
|||
CGIndenter(CGList([CGGeneric(str_to_cstr(name)) for
|
||||
name in unscopableNames], ",\n")),
|
||||
CGGeneric("];\n")], "\n"))
|
||||
if (
|
||||
(descriptor.concrete or descriptor.hasDescendants())
|
||||
and not descriptor.interface.isIteratorInterface()
|
||||
):
|
||||
cgThings.append(CGIDLInterface(descriptor))
|
||||
if descriptor.interface.isIteratorInterface():
|
||||
cgThings.append(CGIteratorDerives(descriptor))
|
||||
|
||||
if descriptor.weakReferenceable:
|
||||
cgThings.append(CGWeakReferenceableTrait(descriptor))
|
||||
|
||||
if not descriptor.interface.isCallback():
|
||||
interfaceTrait = CGInterfaceTrait(descriptor, config.getDescriptorProvider())
|
||||
|
@ -7590,6 +7574,27 @@ class CGConcreteBindingRoot(CGThing):
|
|||
f"pub(crate) use {originalBinding}::{firstCap(ifaceName)}_Binding as {firstCap(ifaceName)}_Binding;"
|
||||
),
|
||||
]
|
||||
|
||||
if d.concrete:
|
||||
if not d.interface.isIteratorInterface():
|
||||
cgthings.append(CGAssertInheritance(d))
|
||||
else:
|
||||
cgthings.append(CGIteratorDerives(d))
|
||||
|
||||
if (
|
||||
(d.concrete or d.hasDescendants())
|
||||
and not d.interface.isIteratorInterface()
|
||||
):
|
||||
cgthings.append(CGIDLInterface(d))
|
||||
|
||||
if d.interface.isIteratorInterface():
|
||||
cgthings.append(CGDomObjectIteratorWrap(d))
|
||||
elif d.concrete and not d.isGlobal():
|
||||
cgthings.append(CGDomObjectWrap(d))
|
||||
|
||||
if d.weakReferenceable:
|
||||
cgthings.append(CGWeakReferenceableTrait(d))
|
||||
|
||||
if not d.interface.isCallback():
|
||||
traitName = f"{ifaceName}Methods"
|
||||
cgthings += [
|
||||
|
@ -7625,7 +7630,7 @@ pub(crate) fn GetConstructorObject(
|
|||
curr = CGImports(curr, descriptors=[], callbacks=[],
|
||||
dictionaries=[], enums=[], typedefs=[],
|
||||
imports=[
|
||||
'crate::dom::bindings::import::base::*',
|
||||
'crate::dom::bindings::import::module::*',
|
||||
'crate::dom::types::*'],
|
||||
config=config)
|
||||
|
||||
|
|
|
@ -51,3 +51,10 @@ pub trait Castable: IDLInterface + DomObject + Sized {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait HasParent {
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
type Parent;
|
||||
fn as_parent(&self) -> &Self::Parent;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use js::rust::HandleObject;
|
||||
use js::rust::{HandleObject, MutableHandleObject};
|
||||
|
||||
use crate::script_runtime::JSContext;
|
||||
|
||||
|
@ -22,3 +22,11 @@ pub trait TestBindingHelpers {
|
|||
pub trait WebGL2RenderingContextHelpers {
|
||||
fn is_webgl2_enabled(cx: JSContext, global: HandleObject) -> bool;
|
||||
}
|
||||
|
||||
pub trait WindowHelpers {
|
||||
fn create_named_properties_object(
|
||||
cx: JSContext,
|
||||
proto: HandleObject,
|
||||
object: MutableHandleObject,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ pub mod iterable;
|
|||
pub mod like;
|
||||
pub mod lock;
|
||||
pub mod num;
|
||||
pub mod proxyhandler;
|
||||
pub mod record;
|
||||
pub mod reflector;
|
||||
pub mod root;
|
||||
|
|
494
components/script_bindings/proxyhandler.rs
Normal file
494
components/script_bindings/proxyhandler.rs
Normal file
|
@ -0,0 +1,494 @@
|
|||
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Utilities for the implementation of JSAPI proxy handlers.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr;
|
||||
|
||||
use js::glue::{GetProxyHandlerFamily, GetProxyPrivate, SetProxyPrivate};
|
||||
use js::jsapi::{
|
||||
DOMProxyShadowsResult, GetStaticPrototype, GetWellKnownSymbol, Handle as RawHandle,
|
||||
HandleId as RawHandleId, HandleObject as RawHandleObject, JS_AtomizeAndPinString,
|
||||
JS_DefinePropertyById, JS_GetOwnPropertyDescriptorById, JSContext, JSErrNum, JSFunctionSpec,
|
||||
JSObject, JSPropertySpec, MutableHandle as RawMutableHandle,
|
||||
MutableHandleIdVector as RawMutableHandleIdVector,
|
||||
MutableHandleObject as RawMutableHandleObject, ObjectOpResult, PropertyDescriptor,
|
||||
SetDOMProxyInformation, SymbolCode, jsid,
|
||||
};
|
||||
use js::jsid::SymbolId;
|
||||
use js::jsval::{ObjectValue, UndefinedValue};
|
||||
use js::rust::wrappers::{
|
||||
AppendToIdVector, JS_AlreadyHasOwnPropertyById, JS_NewObjectWithGivenProto,
|
||||
RUST_INTERNED_STRING_TO_JSID, SetDataPropertyDescriptor,
|
||||
};
|
||||
use js::rust::{Handle, HandleObject, HandleValue, MutableHandle, MutableHandleObject};
|
||||
use js::{jsapi, rooted};
|
||||
|
||||
use crate::conversions::{is_dom_proxy, jsid_to_string, jsstring_to_str};
|
||||
use crate::script_runtime::JSContext as SafeJSContext;
|
||||
use crate::str::DOMString;
|
||||
use crate::utils::delete_property_by_id;
|
||||
|
||||
/// Determine if this id shadows any existing properties for this proxy.
|
||||
///
|
||||
/// # Safety
|
||||
/// `cx` must point to a valid, non-null JSContext.
|
||||
pub unsafe extern "C" fn shadow_check_callback(
|
||||
cx: *mut JSContext,
|
||||
object: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
) -> DOMProxyShadowsResult {
|
||||
// TODO: support OverrideBuiltins when #12978 is fixed.
|
||||
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
get_expando_object(object, expando.handle_mut());
|
||||
if !expando.get().is_null() {
|
||||
let mut has_own = false;
|
||||
let raw_id = Handle::from_raw(id);
|
||||
|
||||
if !JS_AlreadyHasOwnPropertyById(cx, expando.handle(), raw_id, &mut has_own) {
|
||||
return DOMProxyShadowsResult::ShadowCheckFailed;
|
||||
}
|
||||
|
||||
if has_own {
|
||||
return DOMProxyShadowsResult::ShadowsViaDirectExpando;
|
||||
}
|
||||
}
|
||||
|
||||
// Our expando, if any, didn't shadow, so we're not shadowing at all.
|
||||
DOMProxyShadowsResult::DoesntShadow
|
||||
}
|
||||
|
||||
/// Initialize the infrastructure for DOM proxy objects.
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
SetDOMProxyInformation(
|
||||
GetProxyHandlerFamily(),
|
||||
Some(shadow_check_callback),
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines an expando on the given `proxy`.
|
||||
///
|
||||
/// # Safety
|
||||
/// `cx` must point to a valid, non-null JSContext.
|
||||
/// `result` must point to a valid, non-null ObjectOpResult.
|
||||
pub unsafe extern "C" fn define_property(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
desc: RawHandle<PropertyDescriptor>,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
ensure_expando_object(cx, proxy, expando.handle_mut());
|
||||
JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result)
|
||||
}
|
||||
|
||||
/// Deletes an expando off the given `proxy`.
|
||||
///
|
||||
/// # Safety
|
||||
/// `cx` must point to a valid, non-null JSContext.
|
||||
/// `bp` must point to a valid, non-null ObjectOpResult.
|
||||
pub unsafe extern "C" fn delete(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
bp: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
get_expando_object(proxy, expando.handle_mut());
|
||||
if expando.is_null() {
|
||||
(*bp).code_ = 0 /* OkCode */;
|
||||
return true;
|
||||
}
|
||||
|
||||
delete_property_by_id(cx, expando.handle(), Handle::from_raw(id), bp)
|
||||
}
|
||||
|
||||
/// Controls whether the Extensible bit can be changed
|
||||
///
|
||||
/// # Safety
|
||||
/// `result` must point to a valid, non-null ObjectOpResult.
|
||||
pub unsafe extern "C" fn prevent_extensions(
|
||||
_cx: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
|
||||
true
|
||||
}
|
||||
|
||||
/// Reports whether the object is Extensible
|
||||
///
|
||||
/// # Safety
|
||||
/// `succeeded` must point to a valid, non-null bool.
|
||||
pub unsafe extern "C" fn is_extensible(
|
||||
_cx: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
succeeded: *mut bool,
|
||||
) -> bool {
|
||||
*succeeded = true;
|
||||
true
|
||||
}
|
||||
|
||||
/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as
|
||||
/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior
|
||||
/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s
|
||||
/// prototype in `proto`. Otherwise set `*isOrdinary` to false. In case of
|
||||
/// error, both outparams have unspecified value.
|
||||
///
|
||||
/// This implementation always handles the case of the ordinary
|
||||
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
|
||||
/// necessary for maybe-cross-origin objects.
|
||||
///
|
||||
/// # Safety
|
||||
/// `is_ordinary` must point to a valid, non-null bool.
|
||||
pub unsafe extern "C" fn get_prototype_if_ordinary(
|
||||
_: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
is_ordinary: *mut bool,
|
||||
proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
*is_ordinary = true;
|
||||
proto.set(GetStaticPrototype(proxy.get()));
|
||||
true
|
||||
}
|
||||
|
||||
/// Get the expando object, or null if there is none.
|
||||
pub fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandleObject) {
|
||||
unsafe {
|
||||
assert!(is_dom_proxy(obj.get()));
|
||||
let val = &mut UndefinedValue();
|
||||
GetProxyPrivate(obj.get(), val);
|
||||
expando.set(if val.is_undefined() {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
val.to_object()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the expando object, or create it if it doesn't exist yet.
|
||||
/// Fails on JSAPI failure.
|
||||
///
|
||||
/// # Safety
|
||||
/// `cx` must point to a valid, non-null JSContext.
|
||||
pub unsafe fn ensure_expando_object(
|
||||
cx: *mut JSContext,
|
||||
obj: RawHandleObject,
|
||||
mut expando: MutableHandleObject,
|
||||
) {
|
||||
assert!(is_dom_proxy(obj.get()));
|
||||
get_expando_object(obj, expando.reborrow());
|
||||
if expando.is_null() {
|
||||
expando.set(JS_NewObjectWithGivenProto(
|
||||
cx,
|
||||
ptr::null_mut(),
|
||||
HandleObject::null(),
|
||||
));
|
||||
assert!(!expando.is_null());
|
||||
|
||||
SetProxyPrivate(obj.get(), &ObjectValue(expando.get()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the property descriptor's object to `obj` and set it to enumerable,
|
||||
/// and writable if `readonly` is true.
|
||||
pub fn set_property_descriptor(
|
||||
desc: MutableHandle<PropertyDescriptor>,
|
||||
value: HandleValue,
|
||||
attrs: u32,
|
||||
is_none: &mut bool,
|
||||
) {
|
||||
unsafe {
|
||||
SetDataPropertyDescriptor(desc, value, attrs);
|
||||
}
|
||||
*is_none = false;
|
||||
}
|
||||
|
||||
pub fn id_to_source(cx: SafeJSContext, id: RawHandleId) -> Option<DOMString> {
|
||||
unsafe {
|
||||
rooted!(in(*cx) let mut value = UndefinedValue());
|
||||
rooted!(in(*cx) let mut jsstr = ptr::null_mut::<jsapi::JSString>());
|
||||
jsapi::JS_IdToValue(*cx, id.get(), value.handle_mut().into())
|
||||
.then(|| {
|
||||
jsstr.set(jsapi::JS_ValueToSource(*cx, value.handle().into()));
|
||||
jsstr.get()
|
||||
})
|
||||
.and_then(ptr::NonNull::new)
|
||||
.map(|jsstr| jsstring_to_str(*cx, jsstr))
|
||||
}
|
||||
}
|
||||
|
||||
/// Property and method specs that correspond to the elements of
|
||||
/// [`CrossOriginProperties(O)`].
|
||||
///
|
||||
/// [`CrossOriginProperties(O)`]: https://html.spec.whatwg.org/multipage/#crossoriginproperties-(-o-)
|
||||
pub struct CrossOriginProperties {
|
||||
pub attributes: &'static [JSPropertySpec],
|
||||
pub methods: &'static [JSFunctionSpec],
|
||||
}
|
||||
|
||||
impl CrossOriginProperties {
|
||||
/// Enumerate the property keys defined by `self`.
|
||||
fn keys(&self) -> impl Iterator<Item = *const c_char> + '_ {
|
||||
// Safety: All cross-origin property keys are strings, not symbols
|
||||
self.attributes
|
||||
.iter()
|
||||
.map(|spec| unsafe { spec.name.string_ })
|
||||
.chain(self.methods.iter().map(|spec| unsafe { spec.name.string_ }))
|
||||
.filter(|ptr| !ptr.is_null())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginOwnPropertyKeys`].
|
||||
///
|
||||
/// [`CrossOriginOwnPropertyKeys`]: https://html.spec.whatwg.org/multipage/#crossoriginownpropertykeys-(-o-)
|
||||
pub fn cross_origin_own_property_keys(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
props: RawMutableHandleIdVector,
|
||||
) -> bool {
|
||||
// > 2. For each `e` of `! CrossOriginProperties(O)`, append
|
||||
// > `e.[[Property]]` to `keys`.
|
||||
for key in cross_origin_properties.keys() {
|
||||
unsafe {
|
||||
rooted!(in(*cx) let rooted = JS_AtomizeAndPinString(*cx, key));
|
||||
rooted!(in(*cx) let mut rooted_jsid: jsid);
|
||||
RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), rooted_jsid.handle_mut());
|
||||
AppendToIdVector(props, rooted_jsid.handle());
|
||||
}
|
||||
}
|
||||
|
||||
// > 3. Return the concatenation of `keys` and `« "then", @@toStringTag,
|
||||
// > @@hasInstance, @@isConcatSpreadable »`.
|
||||
append_cross_origin_allowlisted_prop_keys(cx, props);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `is_ordinary` must point to a valid, non-null bool.
|
||||
pub unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
|
||||
_: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
is_ordinary: *mut bool,
|
||||
_proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
// We have a custom `[[GetPrototypeOf]]`, so return `false`
|
||||
*is_ordinary = false;
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of `[[SetPrototypeOf]]` for [`Location`] and [`WindowProxy`].
|
||||
///
|
||||
/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-setprototypeof
|
||||
/// [`WindowProxy`]: https://html.spec.whatwg.org/multipage/#windowproxy-setprototypeof
|
||||
///
|
||||
/// # Safety
|
||||
/// `result` must point to a valid, non-null ObjectOpResult.
|
||||
pub unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
proto: RawHandleObject,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
// > 1. Return `! SetImmutablePrototype(this, V)`.
|
||||
//
|
||||
// <https://tc39.es/ecma262/#sec-set-immutable-prototype>:
|
||||
//
|
||||
// > 1. Assert: Either `Type(V)` is Object or `Type(V)` is Null.
|
||||
//
|
||||
// > 2. Let current be `? O.[[GetPrototypeOf]]()`.
|
||||
rooted!(in(cx) let mut current = ptr::null_mut::<JSObject>());
|
||||
if !jsapi::GetObjectProto(cx, proxy, current.handle_mut().into()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// > 3. If `SameValue(V, current)` is true, return true.
|
||||
if proto.get() == current.get() {
|
||||
(*result).code_ = 0 /* OkCode */;
|
||||
return true;
|
||||
}
|
||||
|
||||
// > 4. Return false.
|
||||
(*result).code_ = JSErrNum::JSMSG_CANT_SET_PROTO as usize;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
|
||||
if d.hasGetter_() {
|
||||
out.set(d.getter_);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_setter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
|
||||
if d.hasSetter_() {
|
||||
out.set(d.setter_);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#sec-isaccessordescriptor>
|
||||
pub fn is_accessor_descriptor(d: &PropertyDescriptor) -> bool {
|
||||
d.hasSetter_() || d.hasGetter_()
|
||||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#sec-isdatadescriptor>
|
||||
pub fn is_data_descriptor(d: &PropertyDescriptor) -> bool {
|
||||
d.hasWritable_() || d.hasValue_()
|
||||
}
|
||||
|
||||
/// Evaluate `CrossOriginGetOwnPropertyHelper(proxy, id) != null`.
|
||||
/// SpiderMonkey-specific.
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object.
|
||||
///
|
||||
/// # Safety
|
||||
/// `bp` must point to a valid, non-null bool.
|
||||
pub unsafe fn cross_origin_has_own(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
id: RawHandleId,
|
||||
bp: *mut bool,
|
||||
) -> bool {
|
||||
// TODO: Once we have the slot for the holder, it'd be more efficient to
|
||||
// use `ensure_cross_origin_property_holder`. We'll need `_proxy` to
|
||||
// do that.
|
||||
*bp = jsid_to_string(*cx, Handle::from_raw(id)).is_some_and(|key| {
|
||||
cross_origin_properties.keys().any(|defined_key| {
|
||||
let defined_key = CStr::from_ptr(defined_key);
|
||||
defined_key.to_bytes() == key.as_bytes()
|
||||
})
|
||||
});
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginGetOwnPropertyHelper`].
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object.
|
||||
///
|
||||
/// [`CrossOriginGetOwnPropertyHelper`]: https://html.spec.whatwg.org/multipage/#crossorigingetownpropertyhelper-(-o,-p-)
|
||||
pub fn cross_origin_get_own_property_helper(
|
||||
cx: SafeJSContext,
|
||||
proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
id: RawHandleId,
|
||||
desc: RawMutableHandle<PropertyDescriptor>,
|
||||
is_none: &mut bool,
|
||||
) -> bool {
|
||||
rooted!(in(*cx) let mut holder = ptr::null_mut::<JSObject>());
|
||||
|
||||
ensure_cross_origin_property_holder(
|
||||
cx,
|
||||
proxy,
|
||||
cross_origin_properties,
|
||||
holder.handle_mut().into(),
|
||||
);
|
||||
|
||||
unsafe { JS_GetOwnPropertyDescriptorById(*cx, holder.handle().into(), id, desc, is_none) }
|
||||
}
|
||||
|
||||
const ALLOWLISTED_SYMBOL_CODES: &[SymbolCode] = &[
|
||||
SymbolCode::toStringTag,
|
||||
SymbolCode::hasInstance,
|
||||
SymbolCode::isConcatSpreadable,
|
||||
];
|
||||
|
||||
pub fn is_cross_origin_allowlisted_prop(cx: SafeJSContext, id: RawHandleId) -> bool {
|
||||
unsafe {
|
||||
if jsid_to_string(*cx, Handle::from_raw(id)).is_some_and(|st| st == "then") {
|
||||
return true;
|
||||
}
|
||||
|
||||
rooted!(in(*cx) let mut allowed_id: jsid);
|
||||
ALLOWLISTED_SYMBOL_CODES.iter().any(|&allowed_code| {
|
||||
allowed_id.set(SymbolId(GetWellKnownSymbol(*cx, allowed_code)));
|
||||
// `jsid`s containing `JS::Symbol *` can be compared by
|
||||
// referential equality
|
||||
allowed_id.get().asBits_ == id.asBits_
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Append `« "then", @@toStringTag, @@hasInstance, @@isConcatSpreadable »` to
|
||||
/// `props`. This is used to implement [`CrossOriginOwnPropertyKeys`].
|
||||
///
|
||||
/// [`CrossOriginOwnPropertyKeys`]: https://html.spec.whatwg.org/multipage/#crossoriginownpropertykeys-(-o-)
|
||||
fn append_cross_origin_allowlisted_prop_keys(cx: SafeJSContext, props: RawMutableHandleIdVector) {
|
||||
unsafe {
|
||||
rooted!(in(*cx) let mut id: jsid);
|
||||
|
||||
let jsstring = JS_AtomizeAndPinString(*cx, c"then".as_ptr());
|
||||
rooted!(in(*cx) let rooted = jsstring);
|
||||
RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), id.handle_mut());
|
||||
AppendToIdVector(props, id.handle());
|
||||
|
||||
for &allowed_code in ALLOWLISTED_SYMBOL_CODES.iter() {
|
||||
id.set(SymbolId(GetWellKnownSymbol(*cx, allowed_code)));
|
||||
AppendToIdVector(props, id.handle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the holder for cross-origin properties for the current global of the
|
||||
/// `JSContext`, creating one and storing it in a slot of the proxy object if it
|
||||
/// doesn't exist yet.
|
||||
///
|
||||
/// This essentially creates a cache of [`CrossOriginGetOwnPropertyHelper`]'s
|
||||
/// results for all property keys.
|
||||
///
|
||||
/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
|
||||
/// for a maybe-cross-origin object. The `out_holder` return value will always
|
||||
/// be in the Realm of `cx`.
|
||||
///
|
||||
/// [`CrossOriginGetOwnPropertyHelper`]: https://html.spec.whatwg.org/multipage/#crossorigingetownpropertyhelper-(-o,-p-)
|
||||
fn ensure_cross_origin_property_holder(
|
||||
cx: SafeJSContext,
|
||||
_proxy: RawHandleObject,
|
||||
cross_origin_properties: &'static CrossOriginProperties,
|
||||
out_holder: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
// TODO: We don't have the slot to store the holder yet. For now,
|
||||
// the holder is constructed every time this function is called,
|
||||
// which is not only inefficient but also deviates from the
|
||||
// specification in a subtle yet observable way.
|
||||
|
||||
// Create a holder for the current Realm
|
||||
unsafe {
|
||||
out_holder.set(jsapi::JS_NewObjectWithGivenProto(
|
||||
*cx,
|
||||
ptr::null_mut(),
|
||||
RawHandleObject::null(),
|
||||
));
|
||||
|
||||
if out_holder.get().is_null() ||
|
||||
!jsapi::JS_DefineProperties(
|
||||
*cx,
|
||||
out_holder.handle(),
|
||||
cross_origin_properties.attributes.as_ptr(),
|
||||
) ||
|
||||
!jsapi::JS_DefineFunctions(
|
||||
*cx,
|
||||
out_holder.handle(),
|
||||
cross_origin_properties.methods.as_ptr(),
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Store the holder in the slot that we don't have yet.
|
||||
|
||||
true
|
||||
}
|
|
@ -440,3 +440,23 @@ pub unsafe fn trace_roots(tracer: *mut JSTracer) {
|
|||
pub fn assert_in_script() {
|
||||
debug_assert!(thread_state::get().is_script());
|
||||
}
|
||||
|
||||
/// Get a slice of references to DOM objects.
|
||||
pub trait DomSlice<T>
|
||||
where
|
||||
T: JSTraceable + DomObject,
|
||||
{
|
||||
/// Returns the slice of `T` references.
|
||||
fn r(&self) -> &[&T];
|
||||
}
|
||||
|
||||
impl<T> DomSlice<T> for [Dom<T>]
|
||||
where
|
||||
T: JSTraceable + DomObject,
|
||||
{
|
||||
#[inline]
|
||||
fn r(&self) -> &[&T] {
|
||||
let _ = mem::transmute::<Dom<T>, &T>;
|
||||
unsafe { &*(self as *const [Dom<T>] as *const [&T]) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_void;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use js::conversions::ToJSValConvertible;
|
||||
|
@ -13,9 +13,9 @@ use js::glue::{
|
|||
};
|
||||
use js::jsapi::{
|
||||
AtomToLinearString, CallArgs, ExceptionStackBehavior, GetLinearStringCharAt,
|
||||
GetLinearStringLength, GetNonCCWObjectGlobal, HandleObject as RawHandleObject,
|
||||
GetLinearStringLength, GetNonCCWObjectGlobal, HandleObject as RawHandleObject, Heap,
|
||||
JS_ClearPendingException, JS_IsExceptionPending, JSAtom, JSContext, JSJitInfo, JSObject,
|
||||
MutableHandleValue as RawMutableHandleValue, ObjectOpResult, StringIsArrayIndex,
|
||||
JSTracer, MutableHandleValue as RawMutableHandleValue, ObjectOpResult, StringIsArrayIndex,
|
||||
};
|
||||
use js::jsval::{JSVal, UndefinedValue};
|
||||
use js::rust::wrappers::{
|
||||
|
@ -36,6 +36,7 @@ use crate::conversions::{PrototypeCheck, jsstring_to_str, private_from_proto_che
|
|||
use crate::error::throw_invalid_this;
|
||||
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||
use crate::str::DOMString;
|
||||
use crate::trace::trace_object;
|
||||
|
||||
/// The struct that holds inheritance information for DOM object reflectors.
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -526,3 +527,42 @@ pub unsafe fn exception_to_promise(
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Trace the resources held by reserved slots of a global object
|
||||
///
|
||||
/// # Safety
|
||||
/// `tracer` must point to a valid, non-null JSTracer.
|
||||
/// `obj` must point to a valid, non-null JSObject.
|
||||
pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
|
||||
let array = get_proto_or_iface_array(obj);
|
||||
for proto in (*array).iter() {
|
||||
if !proto.is_null() {
|
||||
trace_object(
|
||||
tracer,
|
||||
"prototype",
|
||||
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generic method for returning libc::c_void from caller
|
||||
pub trait AsVoidPtr {
|
||||
fn as_void_ptr(&self) -> *const libc::c_void;
|
||||
}
|
||||
impl<T> AsVoidPtr for T {
|
||||
fn as_void_ptr(&self) -> *const libc::c_void {
|
||||
self as *const T as *const libc::c_void
|
||||
}
|
||||
}
|
||||
|
||||
// Generic method for returning c_char from caller
|
||||
pub trait AsCCharPtrPtr {
|
||||
fn as_c_char_ptr(&self) -> *const c_char;
|
||||
}
|
||||
|
||||
impl AsCCharPtrPtr for [u8] {
|
||||
fn as_c_char_ptr(&self) -> *const c_char {
|
||||
self as *const [u8] as *const c_char
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue