aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock6
-rw-r--r--components/script/Cargo.toml2
-rw-r--r--components/script/dom/bindings/callback.rs295
-rw-r--r--components/script/dom/bindings/constructor.rs51
-rw-r--r--components/script/dom/bindings/conversions.rs97
-rw-r--r--components/script/dom/bindings/import.rs159
-rw-r--r--components/script/dom/bindings/iterable.rs180
-rw-r--r--components/script/dom/bindings/mod.rs33
-rw-r--r--components/script/dom/bindings/principals.rs123
-rw-r--r--components/script/dom/bindings/proxyhandler.rs292
-rw-r--r--components/script/dom/bindings/reflector.rs69
-rw-r--r--components/script/dom/bindings/settings_stack.rs143
-rw-r--r--components/script/dom/bindings/trace.rs70
-rw-r--r--components/script/dom/bindings/utils.rs111
-rw-r--r--components/script/dom/bindings/weakref.rs2
-rw-r--r--components/script/dom/globalscope.rs25
-rw-r--r--components/script/dom/promise.rs10
-rw-r--r--components/script/lib.rs4
-rw-r--r--components/script/realms.rs65
-rw-r--r--components/script/webdriver_handlers.rs4
-rw-r--r--components/script_bindings/Cargo.toml7
-rw-r--r--components/script_bindings/callback.rs297
-rw-r--r--components/script_bindings/codegen/Bindings.conf14
-rw-r--r--components/script_bindings/codegen/CodegenRust.py140
-rw-r--r--components/script_bindings/codegen/Configuration.py8
-rw-r--r--components/script_bindings/constructor.rs37
-rw-r--r--components/script_bindings/conversions.rs90
-rw-r--r--components/script_bindings/finalize.rs6
-rw-r--r--components/script_bindings/guard.rs (renamed from components/script/dom/bindings/guard.rs)6
-rw-r--r--components/script_bindings/import.rs137
-rw-r--r--components/script_bindings/interface.rs (renamed from components/script/dom/bindings/interface.rs)19
-rw-r--r--components/script_bindings/interfaces.rs91
-rw-r--r--components/script_bindings/iterable.rs170
-rw-r--r--components/script_bindings/lib.rs45
-rw-r--r--components/script_bindings/mem.rs (renamed from components/script/mem.rs)0
-rw-r--r--components/script_bindings/namespace.rs (renamed from components/script/dom/bindings/namespace.rs)6
-rw-r--r--components/script_bindings/principals.rs128
-rw-r--r--components/script_bindings/proxyhandler.rs334
-rw-r--r--components/script_bindings/realms.rs64
-rw-r--r--components/script_bindings/reflector.rs59
-rw-r--r--components/script_bindings/settings_stack.rs142
-rw-r--r--components/script_bindings/trace.rs109
-rw-r--r--components/script_bindings/utils.rs103
-rw-r--r--components/script_bindings/weakref.rs2
44 files changed, 1929 insertions, 1826 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 413b869acd5..0a5615b0af6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6391,6 +6391,9 @@ dependencies = [
"bitflags 2.9.0",
"crossbeam-channel",
"cssparser",
+ "deny_public_fields",
+ "dom_struct",
+ "domobject_derive",
"html5ever",
"indexmap",
"jstraceable_derive",
@@ -6400,6 +6403,7 @@ dependencies = [
"mozjs",
"num-traits",
"parking_lot",
+ "phf",
"phf_codegen",
"phf_shared",
"regex",
@@ -6407,10 +6411,12 @@ dependencies = [
"servo_arc",
"servo_config",
"servo_malloc_size_of",
+ "servo_url",
"smallvec",
"stylo",
"stylo_atoms",
"tendril",
+ "tracing",
"webxr-api",
"xml5ever",
]
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 07dacd3735f..7158c15d117 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -18,7 +18,7 @@ crown = ['js/crown']
debugmozjs = ['js/debugmozjs']
jitspew = ['js/jitspew']
profilemozjs = ['js/profilemozjs']
-tracing = ["dep:tracing"]
+tracing = ["dep:tracing", "script_bindings/tracing"]
webgl_backtrace = ["canvas_traits/webgl_backtrace"]
js_backtrace = []
refcell_backtrace = ["accountable-refcell"]
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs
deleted file mode 100644
index 6a54255822f..00000000000
--- a/components/script/dom/bindings/callback.rs
+++ /dev/null
@@ -1,295 +0,0 @@
-/* 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/. */
-
-//! Base classes to work with IDL callbacks.
-
-use std::default::Default;
-use std::ffi::CString;
-use std::mem::drop;
-use std::rc::Rc;
-
-use js::jsapi::{
- AddRawValueRoot, EnterRealm, Heap, IsCallable, JSObject, LeaveRealm, Realm, RemoveRawValueRoot,
-};
-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};
-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::DomHelpers;
-use crate::dom::globalscope::GlobalScopeHelpers;
-use crate::realms::{InRealm, enter_realm};
-use crate::script_runtime::{CanGc, JSContext};
-
-/// The exception handling used for a call.
-#[derive(Clone, Copy, PartialEq)]
-pub(crate) enum ExceptionHandling {
- /// Report any exception and don't throw it to the caller code.
- Report,
- /// Throw any exception to the caller code.
- Rethrow,
-}
-
-/// A common base class for representing IDL callback function and
-/// callback interface types.
-#[derive(JSTraceable)]
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-pub(crate) struct CallbackObject<D: DomTypes> {
- /// The underlying `JSObject`.
- callback: Heap<*mut JSObject>,
- permanent_js_root: Heap<JSVal>,
-
- /// The ["callback context"], that is, the global to use as incumbent
- /// global when calling the callback.
- ///
- /// Looking at the WebIDL standard, it appears as though there would always
- /// be a value here, but [sometimes] callback functions are created by
- /// hand-waving without defining the value of the callback context, and
- /// without any JavaScript code on the stack to grab an incumbent global
- /// from.
- ///
- /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
- /// [sometimes]: https://github.com/whatwg/html/issues/2248
- incumbent: Option<Dom<D::GlobalScope>>,
-}
-
-impl<D: DomTypes> CallbackObject<D> {
- #[cfg_attr(crown, allow(crown::unrooted_must_root))]
- // These are used by the bindings and do not need `default()` functions.
- #[allow(clippy::new_without_default)]
- fn new() -> Self {
- Self {
- callback: Heap::default(),
- permanent_js_root: Heap::default(),
- incumbent: D::GlobalScope::incumbent().map(|i| Dom::from_ref(&*i)),
- }
- }
-
- pub(crate) fn get(&self) -> *mut JSObject {
- self.callback.get()
- }
-
- #[allow(unsafe_code)]
- unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) {
- self.callback.set(callback);
- self.permanent_js_root.set(ObjectValue(callback));
- assert!(AddRawValueRoot(
- *cx,
- self.permanent_js_root.get_unsafe(),
- b"CallbackObject::root\n".as_c_char_ptr()
- ));
- }
-}
-
-impl<D: DomTypes> Drop for CallbackObject<D> {
- #[allow(unsafe_code)]
- fn drop(&mut self) {
- unsafe {
- if let Some(cx) = Runtime::get() {
- RemoveRawValueRoot(cx.as_ptr(), self.permanent_js_root.get_unsafe());
- }
- }
- }
-}
-
-impl<D: DomTypes> PartialEq for CallbackObject<D> {
- fn eq(&self, other: &CallbackObject<D>) -> bool {
- self.callback.get() == other.callback.get()
- }
-}
-
-/// A trait to be implemented by concrete IDL callback function and
-/// callback interface types.
-pub(crate) trait CallbackContainer<D: DomTypes> {
- /// Create a new CallbackContainer object for the given `JSObject`.
- unsafe fn new(cx: JSContext, callback: *mut JSObject) -> Rc<Self>;
- /// Returns the underlying `CallbackObject`.
- fn callback_holder(&self) -> &CallbackObject<D>;
- /// Returns the underlying `JSObject`.
- fn callback(&self) -> *mut JSObject {
- self.callback_holder().get()
- }
- /// Returns the ["callback context"], that is, the global to use as
- /// incumbent global when calling the callback.
- ///
- /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
- fn incumbent(&self) -> Option<&D::GlobalScope> {
- self.callback_holder().incumbent.as_deref()
- }
-}
-
-/// A common base class for representing IDL callback function types.
-#[derive(JSTraceable, PartialEq)]
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-pub(crate) struct CallbackFunction<D: DomTypes> {
- object: CallbackObject<D>,
-}
-
-impl<D: DomTypes> CallbackFunction<D> {
- /// Create a new `CallbackFunction` for this object.
- #[cfg_attr(crown, allow(crown::unrooted_must_root))]
- // These are used by the bindings and do not need `default()` functions.
- #[allow(clippy::new_without_default)]
- pub(crate) fn new() -> Self {
- Self {
- object: CallbackObject::new(),
- }
- }
-
- /// Returns the underlying `CallbackObject`.
- pub(crate) fn callback_holder(&self) -> &CallbackObject<D> {
- &self.object
- }
-
- /// Initialize the callback function with a value.
- /// Should be called once this object is done moving.
- pub(crate) unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) {
- self.object.init(cx, callback);
- }
-}
-
-/// A common base class for representing IDL callback interface types.
-#[derive(JSTraceable, PartialEq)]
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-pub(crate) struct CallbackInterface<D: DomTypes> {
- object: CallbackObject<D>,
-}
-
-impl<D: DomTypes> CallbackInterface<D> {
- /// Create a new CallbackInterface object for the given `JSObject`.
- // These are used by the bindings and do not need `default()` functions.
- #[allow(clippy::new_without_default)]
- pub(crate) fn new() -> Self {
- Self {
- object: CallbackObject::new(),
- }
- }
-
- /// Returns the underlying `CallbackObject`.
- pub(crate) fn callback_holder(&self) -> &CallbackObject<D> {
- &self.object
- }
-
- /// Initialize the callback function with a value.
- /// Should be called once this object is done moving.
- pub(crate) unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) {
- self.object.init(cx, callback);
- }
-
- /// Returns the property with the given `name`, if it is a callable object,
- /// or an error otherwise.
- pub(crate) fn get_callable_property(&self, cx: JSContext, name: &str) -> Fallible<JSVal> {
- rooted!(in(*cx) let mut callable = UndefinedValue());
- rooted!(in(*cx) let obj = self.callback_holder().get());
- unsafe {
- let c_name = CString::new(name).unwrap();
- if !JS_GetProperty(*cx, obj.handle(), c_name.as_ptr(), callable.handle_mut()) {
- return Err(Error::JSFailed);
- }
-
- if !callable.is_object() || !IsCallable(callable.to_object()) {
- return Err(Error::Type(format!(
- "The value of the {} property is not callable",
- name
- )));
- }
- }
- Ok(callable.get())
- }
-}
-
-pub(crate) use script_bindings::callback::ThisReflector;
-
-/// Wraps the reflector for `p` into the realm of `cx`.
-pub(crate) fn wrap_call_this_value<T: ThisReflector>(
- cx: JSContext,
- p: &T,
- mut rval: MutableHandleValue,
-) -> bool {
- rooted!(in(*cx) let mut obj = p.jsobject());
- assert!(!obj.is_null());
-
- unsafe {
- if !JS_WrapObject(*cx, obj.handle_mut()) {
- return false;
- }
- }
-
- rval.set(ObjectValue(*obj));
- true
-}
-
-/// A class that performs whatever setup we need to safely make a call while
-/// this class is on the stack. After `new` returns, the call is safe to make.
-pub(crate) struct CallSetup<D: DomTypes> {
- /// The global for reporting exceptions. This is the global object of the
- /// (possibly wrapped) callback object.
- exception_global: DomRoot<D::GlobalScope>,
- /// The `JSContext` used for the call.
- cx: JSContext,
- /// The realm we were in before the call.
- old_realm: *mut Realm,
- /// The exception handling used for the call.
- handling: ExceptionHandling,
- /// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
- /// steps 8 and 18.2.
- entry_script: Option<GenericAutoEntryScript<D>>,
- /// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
- /// steps 9 and 18.1.
- incumbent_script: Option<GenericAutoIncumbentScript<D>>,
-}
-
-impl<D: DomTypes> CallSetup<D> {
- /// Performs the setup needed to make a call.
- #[cfg_attr(crown, allow(crown::unrooted_must_root))]
- pub(crate) fn new<T: CallbackContainer<D>>(callback: &T, handling: ExceptionHandling) -> Self {
- let global = unsafe { D::GlobalScope::from_object(callback.callback()) };
- if let Some(window) = global.downcast::<D::Window>() {
- window.Document().ensure_safe_to_run_script_or_layout();
- }
- let cx = D::GlobalScope::get_cx();
-
- let aes = GenericAutoEntryScript::<D>::new(&global);
- let ais = callback.incumbent().map(GenericAutoIncumbentScript::new);
- CallSetup {
- exception_global: global,
- cx,
- old_realm: unsafe { EnterRealm(*cx, callback.callback()) },
- handling,
- entry_script: Some(aes),
- incumbent_script: ais,
- }
- }
-
- /// Returns the `JSContext` used for the call.
- pub(crate) fn get_context(&self) -> JSContext {
- self.cx
- }
-}
-
-impl<D: DomTypes> Drop for CallSetup<D> {
- fn drop(&mut self) {
- unsafe {
- LeaveRealm(*self.cx, self.old_realm);
- }
- if self.handling == ExceptionHandling::Report {
- let ar = enter_realm(&*self.exception_global);
- <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());
- }
-}
diff --git a/components/script/dom/bindings/constructor.rs b/components/script/dom/bindings/constructor.rs
index ae9305f0767..138dd4520d0 100644
--- a/components/script/dom/bindings/constructor.rs
+++ b/components/script/dom/bindings/constructor.rs
@@ -11,6 +11,7 @@ use js::glue::{UnwrapObjectDynamic, UnwrapObjectStatic};
use js::jsapi::{CallArgs, CurrentGlobalOrNull, JSAutoRealm, JSObject};
use js::rust::wrappers::{JS_SetPrototype, JS_WrapObject};
use js::rust::{HandleObject, MutableHandleObject, MutableHandleValue};
+use script_bindings::interface::get_desired_proto;
use super::utils::ProtoOrIfaceArray;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
@@ -40,9 +41,8 @@ use crate::dom::bindings::codegen::Bindings::{
};
use crate::dom::bindings::codegen::PrototypeList;
use crate::dom::bindings::conversions::DerivedFrom;
-use crate::dom::bindings::error::{Error, throw_constructor_without_new, throw_dom_exception};
+use crate::dom::bindings::error::{Error, throw_dom_exception};
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::interface::get_desired_proto;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
use crate::dom::create::create_native_html_element;
@@ -55,7 +55,7 @@ use crate::script_runtime::{CanGc, JSContext, JSContext as SafeJSContext};
use crate::script_thread::ScriptThread;
/// <https://html.spec.whatwg.org/multipage/#htmlconstructor>
-unsafe fn html_constructor(
+fn html_constructor(
cx: JSContext,
global: &GlobalScope,
call_args: &CallArgs,
@@ -75,7 +75,9 @@ unsafe fn html_constructor(
// The new_target might be a cross-compartment wrapper. Get the underlying object
// so we can do the spec's object-identity checks.
- rooted!(in(*cx) let new_target_unwrapped = UnwrapObjectDynamic(call_args.new_target().to_object(), *cx, true));
+ rooted!(in(*cx) let new_target_unwrapped = unsafe {
+ UnwrapObjectDynamic(call_args.new_target().to_object(), *cx, true)
+ });
if new_target_unwrapped.is_null() {
throw_dom_exception(
cx,
@@ -114,7 +116,7 @@ unsafe fn html_constructor(
// Step 4. Let isValue be null.
let mut is_value = None;
- rooted!(in(*cx) let callee = UnwrapObjectStatic(call_args.callee()));
+ rooted!(in(*cx) let callee = unsafe { UnwrapObjectStatic(call_args.callee()) });
if callee.is_null() {
throw_dom_exception(cx, global, Error::Security, can_gc);
return Err(());
@@ -123,7 +125,7 @@ unsafe fn html_constructor(
{
let _ac = JSAutoRealm::new(*cx, callee.get());
rooted!(in(*cx) let mut constructor = ptr::null_mut::<JSObject>());
- rooted!(in(*cx) let global_object = CurrentGlobalOrNull(*cx));
+ rooted!(in(*cx) let global_object = unsafe { CurrentGlobalOrNull(*cx) });
// Step 5. If definition's local name is equal to definition's name
// (i.e., definition is for an autonomous custom element):
@@ -233,13 +235,15 @@ unsafe fn html_constructor(
};
rooted!(in(*cx) let mut element = result.reflector().get_jsobject().get());
- if !JS_WrapObject(*cx, element.handle_mut()) {
- return Err(());
- }
+ unsafe {
+ if !JS_WrapObject(*cx, element.handle_mut()) {
+ return Err(());
+ }
- JS_SetPrototype(*cx, element.handle(), prototype.handle());
+ JS_SetPrototype(*cx, element.handle(), prototype.handle());
- result.to_jsval(*cx, MutableHandleValue::from_raw(call_args.rval()));
+ result.to_jsval(*cx, MutableHandleValue::from_raw(call_args.rval()));
+ }
Ok(())
}
@@ -395,7 +399,7 @@ pub(crate) fn push_new_element_queue() {
ScriptThread::push_new_element_queue();
}
-pub(crate) unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>(
+pub(crate) fn call_html_constructor<T: DerivedFrom<Element> + DomObject>(
cx: JSContext,
args: &CallArgs,
global: &GlobalScope,
@@ -418,26 +422,3 @@ pub(crate) unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>(
)
.is_ok()
}
-
-pub(crate) unsafe fn call_default_constructor<D: crate::DomTypes>(
- cx: JSContext,
- args: &CallArgs,
- global: &D::GlobalScope,
- proto_id: PrototypeList::ID,
- ctor_name: &str,
- creator: unsafe fn(JSContext, HandleObject, *mut ProtoOrIfaceArray),
- constructor: impl FnOnce(JSContext, &CallArgs, &D::GlobalScope, HandleObject) -> bool,
-) -> bool {
- if !args.is_constructing() {
- throw_constructor_without_new(cx, ctor_name);
- return false;
- }
-
- rooted!(in(*cx) let mut desired_proto = ptr::null_mut::<JSObject>());
- let proto_result = get_desired_proto(cx, args, proto_id, creator, desired_proto.handle_mut());
- if proto_result.is_err() {
- return false;
- }
-
- constructor(cx, args, global, desired_proto.handle())
-}
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index 0ea59e6ee83..f01357fda55 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -37,48 +37,15 @@ use std::ffi;
pub(crate) use js::conversions::{
ConversionBehavior, ConversionResult, FromJSValConvertible, ToJSValConvertible,
};
-use js::glue::GetProxyReservedSlot;
-use js::jsapi::{Heap, IsWindowProxy, JS_IsExceptionPending, JSContext, JSObject};
+use js::jsapi::{JS_IsExceptionPending, JSContext, JSObject};
use js::jsval::UndefinedValue;
-use js::rust::wrappers::{IsArrayObject, JS_GetProperty, JS_HasProperty};
-use js::rust::{HandleObject, HandleValue, MutableHandleValue};
-pub(crate) use script_bindings::conversions::*;
+use js::rust::wrappers::{JS_GetProperty, JS_HasProperty};
+use js::rust::{HandleObject, MutableHandleValue};
+pub(crate) use script_bindings::conversions::{is_dom_proxy, *};
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
-use crate::dom::bindings::trace::{JSTraceable, RootedTraceableBox};
-
-impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceableBox<T> {
- #[inline]
- unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
- let value = &**self;
- value.to_jsval(cx, rval);
- }
-}
-
-impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>>
-where
- T: FromJSValConvertible + js::rust::GCMethods + Copy,
- Heap<T>: JSTraceable + Default,
-{
- type Config = T::Config;
-
- unsafe fn from_jsval(
- cx: *mut JSContext,
- value: HandleValue,
- config: Self::Config,
- ) -> Result<ConversionResult<Self>, ()> {
- T::from_jsval(cx, value, config).map(|result| match result {
- ConversionResult::Success(inner) => {
- ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner)))
- },
- ConversionResult::Failure(msg) => ConversionResult::Failure(msg),
- })
- }
-}
-
-pub(crate) use script_bindings::conversions::is_dom_proxy;
/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper
/// around it first, and checking if the object is of the correct type.
@@ -104,43 +71,6 @@ where
unsafe { root_from_object(obj.get(), cx) }
}
-/// Returns whether `value` is an array-like object (Array, FileList,
-/// HTMLCollection, HTMLFormControlsCollection, HTMLOptionsCollection,
-/// NodeList).
-pub(crate) unsafe fn is_array_like<D: crate::DomTypes>(
- cx: *mut JSContext,
- value: HandleValue,
-) -> bool {
- let mut is_array = false;
- assert!(IsArrayObject(cx, value, &mut is_array));
- if is_array {
- return true;
- }
-
- let object: *mut JSObject = match FromJSValConvertible::from_jsval(cx, value, ()).unwrap() {
- ConversionResult::Success(object) => object,
- _ => return false,
- };
-
- if root_from_object::<D::FileList>(object, cx).is_ok() {
- return true;
- }
- if root_from_object::<D::HTMLCollection>(object, cx).is_ok() {
- return true;
- }
- if root_from_object::<D::HTMLFormControlsCollection>(object, cx).is_ok() {
- return true;
- }
- if root_from_object::<D::HTMLOptionsCollection>(object, cx).is_ok() {
- return true;
- }
- if root_from_object::<D::NodeList>(object, cx).is_ok() {
- return true;
- }
-
- false
-}
-
/// Get a property from a JS object.
pub(crate) unsafe fn get_property_jsval(
cx: *mut JSContext,
@@ -191,22 +121,3 @@ where
Err(()) => Err(Error::JSFailed),
}
}
-
-/// Get a `DomRoot<T>` for a WindowProxy accessible from a `HandleValue`.
-/// Caller is responsible for throwing a JS exception if needed in case of error.
-pub(crate) unsafe fn windowproxy_from_handlevalue<D: crate::DomTypes>(
- v: HandleValue,
- _cx: *mut JSContext,
-) -> Result<DomRoot<D::WindowProxy>, ()> {
- if !v.get().is_object() {
- return Err(());
- }
- let object = v.get().to_object();
- if !IsWindowProxy(object) {
- return Err(());
- }
- let mut value = UndefinedValue();
- GetProxyReservedSlot(object, 0, &mut value);
- let ptr = value.to_private() as *const D::WindowProxy;
- Ok(DomRoot::from_ref(&*ptr))
-}
diff --git a/components/script/dom/bindings/import.rs b/components/script/dom/bindings/import.rs
index 71ba5e4c994..5042eba1c05 100644
--- a/components/script/dom/bindings/import.rs
+++ b/components/script/dom/bindings/import.rs
@@ -2,169 +2,24 @@
* 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/. */
-#[allow(unused_imports)]
pub(crate) mod base {
pub(crate) use std::ptr;
- pub(crate) use std::rc::Rc;
- pub(crate) use js::error::throw_type_error;
- pub(crate) use js::jsapi::{
- CurrentGlobalOrNull, HandleValue as RawHandleValue, HandleValueArray, Heap, IsCallable,
- JS_NewObject, JSContext, JSObject,
- };
- pub(crate) use js::jsval::{JSVal, NullValue, ObjectOrNullValue, ObjectValue, UndefinedValue};
- pub(crate) use js::panic::maybe_resume_unwind;
- pub(crate) use js::rust::wrappers::{Call, JS_WrapValue};
- pub(crate) use js::rust::{HandleObject, HandleValue, MutableHandleObject, MutableHandleValue};
- pub(crate) use script_bindings::lock::ThreadUnsafeOnceLock;
+ pub(crate) use js::rust::{HandleObject, MutableHandleObject};
- pub(crate) use crate::dom::bindings::callback::{
- CallSetup, CallbackContainer, CallbackFunction, CallbackInterface, CallbackObject,
- ExceptionHandling, ThisReflector, wrap_call_this_value,
- };
- pub(crate) use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
- ChannelCountMode, ChannelCountModeValues, ChannelInterpretation,
- ChannelInterpretationValues,
- };
- pub(crate) use crate::dom::bindings::codegen::DomTypes::DomTypes;
- pub(crate) use crate::dom::bindings::codegen::{GenericUnionTypes, UnionTypes};
- pub(crate) use crate::dom::bindings::conversions::{
- ConversionBehavior, ConversionResult, FromJSValConvertible, StringificationBehavior,
- ToJSValConvertible, root_from_handlevalue,
- };
- pub(crate) use crate::dom::bindings::error::Error::JSFailed;
- pub(crate) use crate::dom::bindings::error::{Fallible, throw_dom_exception};
- pub(crate) use crate::dom::bindings::num::Finite;
- pub(crate) use crate::dom::bindings::proxyhandler::CrossOriginProperties;
- pub(crate) use crate::dom::bindings::reflector::{DomGlobalGeneric, DomObject};
- pub(crate) use crate::dom::bindings::root::DomRoot;
- pub(crate) use crate::dom::bindings::str::{ByteString, DOMString, USVString};
- pub(crate) use crate::dom::bindings::trace::RootedTraceableBox;
- pub(crate) use crate::dom::bindings::utils::{
- DomHelpers, get_dictionary_property, set_dictionary_property,
- };
- pub(crate) use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers};
- pub(crate) use crate::dom::promise::PromiseHelpers;
- pub(crate) use crate::realms::{AlreadyInRealm, InRealm};
pub(crate) use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
}
-#[allow(unused_imports)]
pub(crate) mod module {
- pub(crate) use std::cmp;
- pub(crate) use std::ffi::CString;
- pub(crate) use std::ptr::NonNull;
-
- pub(crate) use js::glue::{
- CreateProxyHandler, GetProxyReservedSlot, JS_GetReservedSlot, ProxyTraps,
- SetProxyReservedSlot,
- };
- pub(crate) use js::jsapi::{
- __BindgenBitfieldUnit, CallArgs, GCContext, GetRealmErrorPrototype,
- GetRealmFunctionPrototype, GetRealmIteratorPrototype, GetRealmObjectPrototype,
- GetWellKnownSymbol, Handle as RawHandle, HandleId as RawHandleId,
- HandleObject as RawHandleObject, JS_AtomizeAndPinString, JS_ForwardGetPropertyTo,
- JS_GetPropertyDescriptorById, JS_HasPropertyById, JS_NewPlainObject, JS_SetReservedSlot,
- JSAutoRealm, JSCLASS_FOREGROUND_FINALIZE, JSCLASS_RESERVED_SLOTS_SHIFT, JSClass,
- JSClassOps, JSFunctionSpec, JSITER_HIDDEN, JSITER_OWNONLY, JSITER_SYMBOLS,
- JSJitGetterCallArgs, JSJitInfo, JSJitInfo__bindgen_ty_1, JSJitInfo__bindgen_ty_2,
- JSJitInfo__bindgen_ty_3, JSJitInfo_AliasSet, JSJitInfo_ArgType, JSJitInfo_OpType,
- JSJitMethodCallArgs, JSJitSetterCallArgs, JSNativeWrapper, JSPROP_ENUMERATE,
- JSPROP_PERMANENT, JSPROP_READONLY, JSPropertySpec, JSPropertySpec_Accessor,
- JSPropertySpec_AccessorsOrValue, JSPropertySpec_AccessorsOrValue_Accessors,
- JSPropertySpec_Kind, JSPropertySpec_Name, JSPropertySpec_ValueWrapper,
- JSPropertySpec_ValueWrapper__bindgen_ty_1, JSPropertySpec_ValueWrapper_Type, JSTracer,
- JSTypedMethodJitInfo, JSValueType, MutableHandle as RawMutableHandle,
- MutableHandleIdVector as RawMutableHandleIdVector,
- MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue,
- ObjectOpResult, PropertyDescriptor, SymbolCode, UndefinedHandleValue, jsid,
- };
- pub(crate) use js::jsval::PrivateValue;
- pub(crate) use js::panic::wrap_panic;
- pub(crate) use js::rust::wrappers::{
- AppendToIdVector, Call, GetPropertyKeys, JS_CopyOwnPropertiesAndPrivateFields,
- JS_DefineProperty, JS_DefinePropertyById2, JS_GetProperty,
- JS_InitializePropertiesFromCompatibleNativeObject, JS_NewObjectWithGivenProto,
- JS_NewObjectWithoutMetadata, JS_SetImmutablePrototype, JS_SetProperty, JS_SetPrototype,
- JS_WrapObject, NewProxyObject, RUST_INTERNED_STRING_TO_JSID, RUST_SYMBOL_TO_JSID,
- int_to_jsid,
- };
- pub(crate) use js::rust::{
- CustomAutoRooterGuard, GCMethods, Handle, MutableHandle, get_context_realm,
- get_object_class, get_object_realm,
- };
- pub(crate) use js::typedarray::{
- ArrayBuffer, ArrayBufferView, Float32Array, Float64Array, Uint8Array, Uint8ClampedArray,
- };
- pub(crate) use js::{
- JS_CALLEE, JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL,
- JSCLASS_RESERVED_SLOTS_MASK, jsapi, typedarray,
- };
- pub(crate) use script_bindings::codegen::Globals::Globals;
- pub(crate) use script_bindings::constant::{ConstantSpec, ConstantVal};
- pub(crate) use script_bindings::finalize::{
- finalize_common, finalize_global, finalize_weak_referenceable,
- };
- 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 script_bindings::codegen::PrototypeList;
+ pub(crate) use script_bindings::conversions::IDLInterface;
+ pub(crate) use script_bindings::utils::DOMClass;
pub(crate) use super::base::*;
- pub(crate) use crate::dom::bindings::codegen::Bindings::AnalyserNodeBinding::AnalyserOptions;
- pub(crate) use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
- AudioNode_Binding, ChannelCountMode, ChannelCountModeValues, ChannelInterpretation,
- ChannelInterpretationValues,
- };
- pub(crate) use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTarget_Binding;
- pub(crate) use crate::dom::bindings::codegen::{
- InterfaceObjectMap, PrototypeList, RegisterBindings,
- };
- pub(crate) use crate::dom::bindings::constructor::{
- call_default_constructor, call_html_constructor, pop_current_element_queue,
- push_new_element_queue,
- };
- pub(crate) use crate::dom::bindings::conversions::{
- DOM_OBJECT_SLOT, IDLInterface, StringificationBehavior, ToJSValConvertible, is_array_like,
- jsid_to_string, native_from_handlevalue, native_from_object_static,
- };
- pub(crate) use crate::dom::bindings::error::{
- Error, ErrorResult, throw_constructor_without_new,
- };
- pub(crate) use crate::dom::bindings::guard::{Condition, Guard};
- pub(crate) use crate::dom::bindings::inheritance::Castable;
- pub(crate) use crate::dom::bindings::interface::{
- ConstructorClassHook, InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass,
- ProtoOrIfaceIndex, create_callback_interface_object, create_global_object,
- create_interface_prototype_object, create_named_constructors,
- create_noncallback_interface_object, define_dom_interface, define_guarded_methods,
- define_guarded_properties, get_desired_proto, get_per_interface_object_handle,
- is_exposed_in,
- };
- 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,
- };
- pub(crate) use crate::dom::bindings::proxyhandler;
- pub(crate) use crate::dom::bindings::proxyhandler::{
- ensure_expando_object, get_expando_object, set_property_descriptor,
- };
+ pub(crate) use crate::dom::bindings::iterable::IterableIterator;
pub(crate) use crate::dom::bindings::reflector::{
DomObjectIteratorWrap, DomObjectWrap, Reflector,
};
- pub(crate) use crate::dom::bindings::root::{Dom, DomSlice, MaybeUnreflectedDom, Root};
- pub(crate) use crate::dom::bindings::trace::JSTraceable;
- pub(crate) use crate::dom::bindings::utils::{
- AsVoidPtr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, DOMClass, DOMJSClass, JSCLASS_DOM_GLOBAL,
- ProtoOrIfaceArray, enumerate_global, exception_to_promise, generic_getter,
- generic_lenient_getter, generic_lenient_setter, generic_method, generic_setter,
- generic_static_promise_method, get_array_index_from_id, get_property_on_prototype,
- has_property_on_prototype, resolve_global, trace_global,
- };
- pub(crate) use crate::dom::bindings::weakref::{DOM_WEAK_SLOT, WeakReferenceable};
- pub(crate) use crate::dom::types::{AnalyserNode, AudioNode, BaseAudioContext, EventTarget};
- pub(crate) use crate::mem::malloc_size_of_including_raw_self;
- pub(crate) use crate::realms::{AlreadyInRealm, InRealm};
- pub(crate) use crate::script_runtime::CanGc;
+ pub(crate) use crate::dom::bindings::root::{Dom, Root};
+ pub(crate) use crate::dom::bindings::weakref::WeakReferenceable;
}
diff --git a/components/script/dom/bindings/iterable.rs b/components/script/dom/bindings/iterable.rs
deleted file mode 100644
index c81551f7960..00000000000
--- a/components/script/dom/bindings/iterable.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-/* 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/. */
-
-#![allow(unsafe_code)]
-
-//! Implementation of `iterable<...>` and `iterable<..., ...>` WebIDL declarations.
-
-use std::cell::Cell;
-use std::marker::PhantomData;
-use std::ptr;
-use std::ptr::NonNull;
-
-use dom_struct::dom_struct;
-use js::conversions::ToJSValConvertible;
-use js::jsapi::{Heap, JSObject};
-use js::jsval::UndefinedValue;
-use js::rust::{HandleObject, HandleValue, MutableHandleObject};
-use script_bindings::conversions::IDLInterface;
-pub(crate) use script_bindings::iterable::*;
-use script_bindings::utils::DOMClass;
-
-use crate::DomTypes;
-use crate::dom::bindings::codegen::Bindings::IterableIteratorBinding::{
- IterableKeyAndValueResult, IterableKeyOrValueResult,
-};
-use crate::dom::bindings::error::Fallible;
-use crate::dom::bindings::reflector::{
- 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};
-
-/// An iterator over the iterable entries of a given DOM interface.
-#[dom_struct]
-pub(crate) struct IterableIterator<
- D: DomTypes,
- T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>,
-> {
- reflector: Reflector,
- iterable: Dom<T>,
- type_: IteratorType,
- index: Cell<u32>,
- _marker: NoTrace<PhantomData<D>>,
-}
-
-impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable> IterableIterator<D, T> {
- pub fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope> {
- <Self as DomGlobalGeneric<D>>::global_(self, realm)
- }
-}
-
-impl<
- D: DomTypes,
- T: DomObjectIteratorWrap<D>
- + JSTraceable
- + Iterable
- + DomGlobalGeneric<D>
- + IDLInterface
- + IteratorDerives,
-> IDLInterface for IterableIterator<D, T>
-{
- fn derives(class: &'static DOMClass) -> bool {
- <T as IteratorDerives>::derives(class)
- }
-}
-
-impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>>
- IterableIterator<D, T>
-{
- /// Create a new iterator instance for the provided iterable DOM interface.
- pub(crate) fn new(iterable: &T, type_: IteratorType, realm: InRealm) -> DomRoot<Self> {
- let iterator = Box::new(IterableIterator {
- reflector: Reflector::new(),
- type_,
- iterable: Dom::from_ref(iterable),
- index: Cell::new(0),
- _marker: NoTrace(PhantomData),
- });
- <D as DomHelpers<D>>::reflect_dom_object(iterator, &*iterable.global_(realm), CanGc::note())
- }
-
- /// Return the next value from the iterable object.
- #[allow(non_snake_case)]
- pub(crate) fn Next(&self, cx: JSContext) -> Fallible<NonNull<JSObject>> {
- let index = self.index.get();
- rooted!(in(*cx) let mut value = UndefinedValue());
- rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
- let result = if index >= self.iterable.get_iterable_length() {
- dict_return(cx, rval.handle_mut(), true, value.handle())
- } else {
- match self.type_ {
- IteratorType::Keys => {
- unsafe {
- self.iterable
- .get_key_at_index(index)
- .to_jsval(*cx, value.handle_mut());
- }
- dict_return(cx, rval.handle_mut(), false, value.handle())
- },
- IteratorType::Values => {
- unsafe {
- self.iterable
- .get_value_at_index(index)
- .to_jsval(*cx, value.handle_mut());
- }
- dict_return(cx, rval.handle_mut(), false, value.handle())
- },
- IteratorType::Entries => {
- rooted!(in(*cx) let mut key = UndefinedValue());
- unsafe {
- self.iterable
- .get_key_at_index(index)
- .to_jsval(*cx, key.handle_mut());
- self.iterable
- .get_value_at_index(index)
- .to_jsval(*cx, value.handle_mut());
- }
- key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle())
- },
- }
- };
- self.index.set(index + 1);
- result.map(|_| NonNull::new(rval.get()).expect("got a null pointer"))
- }
-}
-
-impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>>
- DomObjectWrap<D> for IterableIterator<D, T>
-{
- const WRAP: unsafe fn(
- JSContext,
- &D::GlobalScope,
- Option<HandleObject>,
- Box<Self>,
- CanGc,
- ) -> Root<Dom<Self>> = T::ITER_WRAP;
-}
-
-fn dict_return(
- cx: JSContext,
- mut result: MutableHandleObject,
- done: bool,
- value: HandleValue,
-) -> Fallible<()> {
- let mut dict = IterableKeyOrValueResult::empty();
- dict.done = done;
- dict.value.set(value.get());
- rooted!(in(*cx) let mut dict_value = UndefinedValue());
- unsafe {
- dict.to_jsval(*cx, dict_value.handle_mut());
- }
- result.set(dict_value.to_object());
- Ok(())
-}
-
-fn key_and_value_return(
- cx: JSContext,
- mut result: MutableHandleObject,
- key: HandleValue,
- value: HandleValue,
-) -> Fallible<()> {
- let mut dict = IterableKeyAndValueResult::empty();
- dict.done = false;
- dict.value = Some(
- vec![key, value]
- .into_iter()
- .map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
- .collect(),
- );
- rooted!(in(*cx) let mut dict_value = UndefinedValue());
- unsafe {
- dict.to_jsval(*cx, dict_value.handle_mut());
- }
- result.set(dict_value.to_object());
- Ok(())
-}
diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs
index b4234e0cc39..ae9e26e8a54 100644
--- a/components/script/dom/bindings/mod.rs
+++ b/components/script/dom/bindings/mod.rs
@@ -135,7 +135,6 @@
#![deny(non_snake_case)]
pub(crate) mod buffer_source;
-pub(crate) mod callback;
#[allow(dead_code)]
pub(crate) mod cell;
pub(crate) mod constructor;
@@ -143,13 +142,9 @@ pub(crate) mod conversions;
pub(crate) mod error;
pub(crate) mod frozenarray;
pub(crate) mod function;
-pub(crate) mod guard;
pub(crate) mod import;
pub(crate) mod inheritance;
-pub(crate) mod interface;
-pub(crate) mod iterable;
pub(crate) mod like;
-pub(crate) mod namespace;
pub(crate) mod principals;
pub(crate) mod proxyhandler;
pub(crate) mod refcounted;
@@ -165,7 +160,7 @@ pub(crate) mod utils;
pub(crate) mod weakref;
pub(crate) mod xmlname;
-pub(crate) use script_bindings::num;
+pub(crate) use script_bindings::{callback, iterable, num};
/// Generated JS-Rust bindings.
#[allow(missing_docs, non_snake_case)]
@@ -173,13 +168,7 @@ pub(crate) mod codegen {
pub(crate) mod DomTypeHolder {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypeHolder.rs"));
}
- pub(crate) mod DomTypes {
- include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypes.rs"));
- }
- #[allow(dead_code)]
- pub(crate) mod GenericBindings {
- include!(concat!(env!("BINDINGS_OUT_DIR"), "/Bindings/mod.rs"));
- }
+ pub(crate) use script_bindings::codegen::GenericBindings;
#[allow(dead_code)]
pub(crate) mod Bindings {
include!(concat!(
@@ -189,30 +178,14 @@ pub(crate) mod codegen {
}
pub(crate) mod InterfaceObjectMap {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InterfaceObjectMap.rs"));
- pub(crate) use script_bindings::codegen::Globals::Globals;
}
- #[allow(dead_code)]
pub(crate) mod ConcreteInheritTypes {
include!(concat!(
env!("BINDINGS_OUT_DIR"),
"/ConcreteInheritTypes.rs"
));
}
- pub(crate) use script_bindings::codegen::PrototypeList;
- pub(crate) mod RegisterBindings {
- include!(concat!(env!("BINDINGS_OUT_DIR"), "/RegisterBindings.rs"));
- }
- #[allow(
- non_camel_case_types,
- unused_imports,
- unused_variables,
- clippy::large_enum_variant,
- clippy::upper_case_acronyms,
- clippy::enum_variant_names
- )]
- pub(crate) mod GenericUnionTypes {
- include!(concat!(env!("BINDINGS_OUT_DIR"), "/GenericUnionTypes.rs"));
- }
+ pub(crate) use script_bindings::codegen::{PrototypeList, RegisterBindings};
#[allow(dead_code)]
pub(crate) mod UnionTypes {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/UnionTypes.rs"));
diff --git a/components/script/dom/bindings/principals.rs b/components/script/dom/bindings/principals.rs
index e51a98e454a..0594b77022c 100644
--- a/components/script/dom/bindings/principals.rs
+++ b/components/script/dom/bindings/principals.rs
@@ -2,132 +2,17 @@
* 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 std::marker::PhantomData;
-use std::mem::ManuallyDrop;
-use std::ops::Deref;
use std::ptr::NonNull;
-use js::glue::{
- CreateRustJSPrincipals, DestroyRustJSPrincipals, GetRustJSPrincipalsPrivate,
- JSPrincipalsCallbacks,
-};
+use js::glue::{DestroyRustJSPrincipals, GetRustJSPrincipalsPrivate, JSPrincipalsCallbacks};
use js::jsapi::{
- JS_DropPrincipals, JS_HoldPrincipals, JS_ReadUint32Pair, JSContext, JSPrincipals,
- JSStructuredCloneReader, JSStructuredCloneWriter,
+ JS_ReadUint32Pair, JSContext, JSPrincipals, JSStructuredCloneReader, JSStructuredCloneWriter,
};
-use js::rust::Runtime;
+use script_bindings::principals::{ServoJSPrincipals, ServoJSPrincipalsRef};
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<D: DomTypes>(origin: &MutableOrigin) -> Self {
- unsafe {
- let private: Box<MutableOrigin> = Box::new(origin.clone());
- 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))
- }
- }
-
- /// Construct `Self` from a raw `*mut JSPrincipals`, incrementing its
- /// reference count.
- #[inline]
- pub(crate) unsafe fn from_raw_nonnull(raw: NonNull<JSPrincipals>) -> Self {
- JS_HoldPrincipals(raw.as_ptr());
- Self(raw)
- }
-
- #[inline]
- pub(crate) unsafe fn origin(&self) -> MutableOrigin {
- let origin = GetRustJSPrincipalsPrivate(self.0.as_ptr()) as *mut MutableOrigin;
- (*origin).clone()
- }
-
- #[inline]
- pub(crate) fn as_raw_nonnull(&self) -> NonNull<JSPrincipals> {
- self.0
- }
-
- #[inline]
- pub(crate) fn as_raw(&self) -> *mut JSPrincipals {
- self.0.as_ptr()
- }
-}
-
-impl Clone for ServoJSPrincipals {
- #[inline]
- fn clone(&self) -> Self {
- unsafe { Self::from_raw_nonnull(self.as_raw_nonnull()) }
- }
-}
-
-impl Drop for ServoJSPrincipals {
- #[inline]
- fn drop(&mut self) {
- if let Some(cx) = Runtime::get() {
- unsafe { JS_DropPrincipals(cx.as_ptr(), self.as_raw()) };
- }
- }
-}
-
-/// A borrowed reference to Servo's `JSPrincipals` instance. Does not update the
-/// reference count on creation and deletion.
-pub(crate) struct ServoJSPrincipalsRef<'a>(ManuallyDrop<ServoJSPrincipals>, PhantomData<&'a ()>);
-
-impl ServoJSPrincipalsRef<'_> {
- /// Construct `Self` from a raw `NonNull<JSPrincipals>`.
- ///
- /// # Safety
- ///
- /// `ServoJSPrincipalsRef` does not update the reference count of the
- /// wrapped `JSPrincipals` object. It's up to the caller to ensure the
- /// returned `ServoJSPrincipalsRef` object or any clones are not used past
- /// the lifetime of the wrapped object.
- #[inline]
- pub(crate) unsafe fn from_raw_nonnull(raw: NonNull<JSPrincipals>) -> Self {
- // Don't use `ServoJSPrincipals::from_raw_nonnull`; we don't want to
- // update the reference count
- Self(ManuallyDrop::new(ServoJSPrincipals(raw)), PhantomData)
- }
-
- /// Construct `Self` from a raw `*mut JSPrincipals`.
- ///
- /// # Safety
- ///
- /// The behavior is undefined if `raw` is null. See also
- /// [`Self::from_raw_nonnull`].
- #[inline]
- pub(crate) unsafe fn from_raw_unchecked(raw: *mut JSPrincipals) -> Self {
- Self::from_raw_nonnull(NonNull::new_unchecked(raw))
- }
-}
-
-impl Clone for ServoJSPrincipalsRef<'_> {
- #[inline]
- fn clone(&self) -> Self {
- Self(ManuallyDrop::new(ServoJSPrincipals(self.0.0)), PhantomData)
- }
-}
-
-impl Deref for ServoJSPrincipalsRef<'_> {
- type Target = ServoJSPrincipals;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
+use crate::DomTypeHolder;
#[allow(unused)]
pub(crate) unsafe extern "C" fn destroy_servo_jsprincipal(principals: *mut JSPrincipals) {
diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs
index 5dfe0839502..2e203a81fa9 100644
--- a/components/script/dom/bindings/proxyhandler.rs
+++ b/components/script/dom/bindings/proxyhandler.rs
@@ -6,30 +6,12 @@
#![deny(missing_docs)]
-use std::ptr;
-
-use js::conversions::ToJSValConvertible;
-use js::glue::{GetProxyHandler, InvokeGetOwnPropertyDescriptor};
-use js::jsapi;
-use js::jsapi::{
- 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,
-};
-use js::jsval::UndefinedValue;
-use js::rust::{HandleObject, HandleValue, MutableHandle, MutableHandleObject, get_context_realm};
+use js::jsapi::{GetObjectRealmOrNull, GetRealmPrincipals, HandleObject as RawHandleObject};
+use js::rust::get_context_realm;
+use script_bindings::principals::ServoJSPrincipalsRef;
pub(crate) use script_bindings::proxyhandler::*;
-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::utils::DomHelpers;
-use crate::dom::globalscope::GlobalScopeHelpers;
-use crate::realms::{AlreadyInRealm, InRealm};
-use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
+use crate::script_runtime::JSContext as SafeJSContext;
/// <https://html.spec.whatwg.org/multipage/#isplatformobjectsameorigin-(-o-)>
pub(crate) unsafe fn is_platform_object_same_origin(
@@ -64,269 +46,3 @@ pub(crate) unsafe fn is_platform_object_same_origin(
result
}
-
-/// Report a cross-origin denial for a property, Always returns `false`, so it
-/// can be used as `return report_cross_origin_denial(...);`.
-///
-/// 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<D: DomTypes>(
- cx: SafeJSContext,
- id: RawHandleId,
- access: &str,
-) -> bool {
- debug!(
- "permission denied to {} property {} on cross-origin object",
- access,
- id_to_source(cx, id).as_deref().unwrap_or("< error >"),
- );
- let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
- if !JS_IsExceptionPending(*cx) {
- let global = D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
- // TODO: include `id` and `access` in the exception message
- <D as DomHelpers<D>>::throw_dom_exception(cx, &global, Error::Security, CanGc::note());
- }
- false
-}
-
-/// 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<D: DomTypes>(
- cx: *mut JSContext,
- proxy: RawHandleObject,
- id: RawHandleId,
- v: RawHandleValue,
- receiver: RawHandleValue,
- result: *mut ObjectOpResult,
-) -> bool {
- let cx = SafeJSContext::from_ptr(cx);
-
- 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.
- let _ac = JSAutoRealm::new(*cx, proxy.get());
-
- // OrdinarySet
- // <https://tc39.es/ecma262/#sec-ordinaryset>
- rooted!(in(*cx) let mut own_desc = PropertyDescriptor::default());
- let mut is_none = false;
- if !InvokeGetOwnPropertyDescriptor(
- GetProxyHandler(*proxy),
- *cx,
- proxy,
- id,
- own_desc.handle_mut().into(),
- &mut is_none,
- ) {
- return false;
- }
-
- js::jsapi::SetPropertyIgnoringNamedGetter(
- *cx,
- proxy,
- id,
- v,
- receiver,
- own_desc.handle().into(),
- result,
- )
-}
-
-/// Implementation of `[[GetPrototypeOf]]` for [`Location`].
-///
-/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-getprototypeof
-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),
- proto: RawMutableHandleObject,
-) -> bool {
- // > 1. If ! IsPlatformObjectSameOrigin(this) is true, then return ! OrdinaryGetPrototypeOf(this).
- if is_platform_object_same_origin(cx, proxy) {
- let ac = JSAutoRealm::new(*cx, proxy.get());
- let global = D::GlobalScope::from_context(*cx, InRealm::Entered(&ac));
- get_proto_object(
- cx,
- global.reflector().get_jsobject(),
- MutableHandleObject::from_raw(proto),
- );
- return !proto.is_null();
- }
-
- // > 2. Return null.
- proto.set(ptr::null_mut());
- 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<D: DomTypes>(
- cx: SafeJSContext,
- proxy: RawHandleObject,
- receiver: RawHandleValue,
- id: RawHandleId,
- vp: RawMutableHandleValue,
-) -> bool {
- // > 1. Let `desc` be `? O.[[GetOwnProperty]](P)`.
- rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default());
- let mut is_none = false;
- if !InvokeGetOwnPropertyDescriptor(
- GetProxyHandler(*proxy),
- *cx,
- proxy,
- id,
- descriptor.handle_mut().into(),
- &mut is_none,
- ) {
- return false;
- }
-
- // > 2. Assert: `desc` is not undefined.
- assert!(
- !is_none,
- "Callees should throw in all cases when they are not finding \
- a property decriptor"
- );
-
- // > 3. If `! IsDataDescriptor(desc)` is true, then return `desc.[[Value]]`.
- if is_data_descriptor(&descriptor) {
- vp.set(descriptor.value_);
- return true;
- }
-
- // > 4. Assert: `IsAccessorDescriptor(desc)` is `true`.
- assert!(is_accessor_descriptor(&descriptor));
-
- // > 5. Let `getter` be `desc.[[Get]]`.
- // >
- // > 6. If `getter` is `undefined`, then throw a `SecurityError`
- // > `DOMException`.
- 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::<D>(cx, id, "get");
- }
-
- rooted!(in(*cx) let mut getter_jsval = UndefinedValue());
- getter.get().to_jsval(*cx, getter_jsval.handle_mut());
-
- // > 7. Return `? Call(getter, Receiver)`.
- jsapi::Call(
- *cx,
- receiver,
- getter_jsval.handle().into(),
- &jsapi::HandleValueArray::empty(),
- vp,
- )
-}
-
-/// Implementation of [`CrossOriginSet`].
-///
-/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
-/// 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<D: DomTypes>(
- cx: SafeJSContext,
- proxy: RawHandleObject,
- id: RawHandleId,
- v: RawHandleValue,
- receiver: RawHandleValue,
- result: *mut ObjectOpResult,
-) -> bool {
- // > 1. Let desc be ? O.[[GetOwnProperty]](P).
- rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default());
- let mut is_none = false;
- if !InvokeGetOwnPropertyDescriptor(
- GetProxyHandler(*proxy),
- *cx,
- proxy,
- id,
- descriptor.handle_mut().into(),
- &mut is_none,
- ) {
- return false;
- }
-
- // > 2. Assert: desc is not undefined.
- assert!(
- !is_none,
- "Callees should throw in all cases when they are not finding \
- a property decriptor"
- );
-
- // > 3. If desc.[[Set]] is present and its value is not undefined,
- // > then: [...]
- rooted!(in(*cx) let mut setter = ptr::null_mut::<JSObject>());
- get_setter_object(&descriptor, setter.handle_mut().into());
- if setter.get().is_null() {
- // > 4. Throw a "SecurityError" DOMException.
- return report_cross_origin_denial::<D>(cx, id, "set");
- }
-
- rooted!(in(*cx) let mut setter_jsval = UndefinedValue());
- setter.get().to_jsval(*cx, setter_jsval.handle_mut());
-
- // > 3.1. Perform ? Call(setter, Receiver, «V»).
- // >
- // > 3.2. Return true.
- rooted!(in(*cx) let mut ignored = UndefinedValue());
- if !jsapi::Call(
- *cx,
- receiver,
- setter_jsval.handle().into(),
- // FIXME: Our binding lacks `HandleValueArray(Handle<Value>)`
- // <https://searchfox.org/mozilla-central/rev/072710086ddfe25aa2962c8399fefb2304e8193b/js/public/ValueArray.h#54-55>
- &jsapi::HandleValueArray {
- length_: 1,
- elements_: v.ptr,
- },
- ignored.handle_mut().into(),
- ) {
- return false;
- }
-
- (*result).code_ = 0 /* OkCode */;
- true
-}
-
-/// 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<D: DomTypes>(
- cx: SafeJSContext,
- _proxy: RawHandleObject,
- id: RawHandleId,
- desc: RawMutableHandle<PropertyDescriptor>,
- is_none: &mut bool,
-) -> bool {
- assert!(*is_none, "why are we being called?");
-
- // > 1. If P is `then`, `@@toStringTag`, `@@hasInstance`, or
- // > `@@isConcatSpreadable`, then return `PropertyDescriptor{ [[Value]]:
- // > undefined, [[Writable]]: false, [[Enumerable]]: false,
- // > [[Configurable]]: true }`.
- if is_cross_origin_allowlisted_prop(cx, id) {
- set_property_descriptor(
- MutableHandle::from_raw(desc),
- HandleValue::undefined(),
- jsapi::JSPROP_READONLY as u32,
- is_none,
- );
- return true;
- }
-
- // > 2. Throw a `SecurityError` `DOMException`.
- report_cross_origin_denial::<D>(cx, id, "access")
-}
diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs
index 3593578a66f..0a5afbce487 100644
--- a/components/script/dom/bindings/reflector.rs
+++ b/components/script/dom/bindings/reflector.rs
@@ -5,15 +5,14 @@
//! The `Reflector` struct.
use js::rust::HandleObject;
+use script_bindings::interfaces::GlobalScopeHelpers;
use crate::DomTypes;
use crate::dom::bindings::conversions::DerivedFrom;
-use crate::dom::bindings::iterable::{Iterable, IterableIterator};
-use crate::dom::bindings::root::{Dom, DomRoot, Root};
-use crate::dom::bindings::trace::JSTraceable;
-use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers};
-use crate::realms::{AlreadyInRealm, InRealm};
-use crate::script_runtime::{CanGc, JSContext};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::globalscope::GlobalScope;
+use crate::realms::InRealm;
+use crate::script_runtime::CanGc;
/// Create the reflector for a new DOM object and yield ownership to the
/// reflector.
@@ -42,31 +41,6 @@ where
unsafe { T::WRAP(D::GlobalScope::get_cx(), global_scope, proto, obj, can_gc) }
}
-pub(crate) trait DomGlobalGeneric<D: DomTypes>: DomObject {
- /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this
- /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For
- /// `Node`s it's almost always better to use `NodeTraits::owning_global`.
- fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope>
- where
- Self: Sized,
- {
- D::GlobalScope::from_reflector(self, realm)
- }
-
- /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this
- /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For
- /// `Node`s it's almost always better to use `NodeTraits::owning_global`.
- fn global(&self) -> DomRoot<D::GlobalScope>
- where
- Self: Sized,
- {
- let realm = AlreadyInRealm::assert_for_cx(D::GlobalScope::get_cx());
- D::GlobalScope::from_reflector(self, InRealm::already(&realm))
- }
-}
-
-impl<D: DomTypes, T: DomObject> DomGlobalGeneric<D> for T {}
-
pub(crate) trait DomGlobal {
fn global_(&self, realm: InRealm) -> DomRoot<GlobalScope>;
fn global(&self) -> DomRoot<GlobalScope>;
@@ -81,35 +55,4 @@ impl<T: DomGlobalGeneric<crate::DomTypeHolder>> DomGlobal for T {
}
}
-pub(crate) use script_bindings::reflector::{DomObject, MutDomObject, Reflector};
-
-/// A trait to provide a function pointer to wrap function for DOM objects.
-pub(crate) trait DomObjectWrap<D: DomTypes>:
- Sized + DomObject + DomGlobalGeneric<D>
-{
- /// Function pointer to the general wrap function type
- #[allow(clippy::type_complexity)]
- const WRAP: unsafe fn(
- JSContext,
- &D::GlobalScope,
- Option<HandleObject>,
- Box<Self>,
- CanGc,
- ) -> Root<Dom<Self>>;
-}
-
-/// A trait to provide a function pointer to wrap function for
-/// DOM iterator interfaces.
-pub(crate) trait DomObjectIteratorWrap<D: DomTypes>:
- DomObjectWrap<D> + JSTraceable + Iterable
-{
- /// Function pointer to the wrap function for `IterableIterator<T>`
- #[allow(clippy::type_complexity)]
- const ITER_WRAP: unsafe fn(
- JSContext,
- &D::GlobalScope,
- Option<HandleObject>,
- Box<IterableIterator<D, Self>>,
- CanGc,
- ) -> Root<Dom<IterableIterator<D, Self>>>;
-}
+pub(crate) use script_bindings::reflector::*;
diff --git a/components/script/dom/bindings/settings_stack.rs b/components/script/dom/bindings/settings_stack.rs
index 1284931c349..8e00d03a953 100644
--- a/components/script/dom/bindings/settings_stack.rs
+++ b/components/script/dom/bindings/settings_stack.rs
@@ -3,36 +3,20 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::RefCell;
-use std::marker::PhantomData;
-use std::thread;
-use js::jsapi::{GetScriptedCallerGlobal, HideScriptedCaller, JSTracer, UnhideScriptedCaller};
+use js::jsapi::{GetScriptedCallerGlobal, JSTracer};
use js::rust::Runtime;
+use script_bindings::settings_stack::*;
-use crate::DomTypes;
-use crate::dom::bindings::root::{Dom, DomRoot};
+//use script_bindings::interfaces::{DomHelpers, GlobalScopeHelpers};
+use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::trace::JSTraceable;
-use crate::dom::bindings::utils::DomHelpers;
-use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers};
-use crate::script_runtime::CanGc;
+use crate::dom::globalscope::GlobalScope;
thread_local!(pub(super) static STACK: RefCell<Vec<StackEntry<crate::DomTypeHolder>>> = const {
RefCell::new(Vec::new())
});
-#[derive(Debug, Eq, JSTraceable, PartialEq)]
-enum StackEntryKind {
- Incumbent,
- Entry,
-}
-
-#[cfg_attr(crown, allow(crown::unrooted_must_root))]
-#[derive(JSTraceable)]
-pub(crate) struct StackEntry<D: DomTypes> {
- global: Dom<D::GlobalScope>,
- kind: StackEntryKind,
-}
-
/// Traces the script settings stack.
pub(crate) unsafe fn trace(tracer: *mut JSTracer) {
STACK.with(|stack| {
@@ -46,61 +30,6 @@ pub(crate) fn is_execution_stack_empty() -> bool {
pub(crate) type AutoEntryScript = GenericAutoEntryScript<crate::DomTypeHolder>;
-/// RAII struct that pushes and pops entries from the script settings stack.
-pub(crate) struct GenericAutoEntryScript<D: DomTypes> {
- global: DomRoot<D::GlobalScope>,
- #[cfg(feature = "tracing")]
- #[allow(dead_code)]
- span: tracing::span::EnteredSpan,
-}
-
-impl<D: DomTypes> GenericAutoEntryScript<D> {
- /// <https://html.spec.whatwg.org/multipage/#prepare-to-run-script>
- pub(crate) fn new(global: &D::GlobalScope) -> Self {
- let settings_stack = <D as DomHelpers<D>>::settings_stack();
- settings_stack.with(|stack| {
- trace!("Prepare to run script with {:p}", global);
- let mut stack = stack.borrow_mut();
- stack.push(StackEntry {
- global: Dom::from_ref(global),
- kind: StackEntryKind::Entry,
- });
- Self {
- global: DomRoot::from_ref(global),
- #[cfg(feature = "tracing")]
- span: tracing::info_span!(
- "ScriptEvaluate",
- servo_profiling = true,
- url = global.get_url().to_string(),
- )
- .entered(),
- }
- })
- }
-}
-
-impl<D: DomTypes> Drop for GenericAutoEntryScript<D> {
- /// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-script>
- fn drop(&mut self) {
- let settings_stack = <D as DomHelpers<D>>::settings_stack();
- settings_stack.with(|stack| {
- let mut stack = stack.borrow_mut();
- let entry = stack.pop().unwrap();
- assert_eq!(
- &*entry.global as *const D::GlobalScope, &*self.global as *const D::GlobalScope,
- "Dropped AutoEntryScript out of order."
- );
- assert_eq!(entry.kind, StackEntryKind::Entry);
- trace!("Clean up after running script with {:p}", &*entry.global);
- });
-
- // Step 5
- if !thread::panicking() && incumbent_global().is_none() {
- self.global.perform_a_microtask_checkpoint(CanGc::note());
- }
- }
-}
-
/// Returns the ["entry"] global object.
///
/// ["entry"]: https://html.spec.whatwg.org/multipage/#entry
@@ -117,67 +46,7 @@ pub(crate) fn entry_global() -> DomRoot<GlobalScope> {
.unwrap()
}
-/// RAII struct that pushes and pops entries from the script settings stack.
-pub(crate) struct GenericAutoIncumbentScript<D: DomTypes> {
- global: usize,
- _marker: PhantomData<D>,
-}
-
-pub(crate) type AutoIncumbentScript = GenericAutoIncumbentScript<crate::DomTypeHolder>;
-
-impl<D: DomTypes> GenericAutoIncumbentScript<D> {
- /// <https://html.spec.whatwg.org/multipage/#prepare-to-run-a-callback>
- pub(crate) fn new(global: &D::GlobalScope) -> Self {
- // Step 2-3.
- unsafe {
- let cx =
- Runtime::get().expect("Creating a new incumbent script after runtime shutdown");
- HideScriptedCaller(cx.as_ptr());
- }
- let settings_stack = <D as DomHelpers<D>>::settings_stack();
- settings_stack.with(|stack| {
- trace!("Prepare to run a callback with {:p}", global);
- // Step 1.
- let mut stack = stack.borrow_mut();
- stack.push(StackEntry {
- global: Dom::from_ref(global),
- kind: StackEntryKind::Incumbent,
- });
- Self {
- global: global as *const _ as usize,
- _marker: PhantomData,
- }
- })
- }
-}
-
-impl<D: DomTypes> Drop for GenericAutoIncumbentScript<D> {
- /// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-a-callback>
- fn drop(&mut self) {
- let settings_stack = <D as DomHelpers<D>>::settings_stack();
- settings_stack.with(|stack| {
- // Step 4.
- let mut stack = stack.borrow_mut();
- let entry = stack.pop().unwrap();
- // Step 3.
- assert_eq!(
- &*entry.global as *const D::GlobalScope as usize, self.global,
- "Dropped AutoIncumbentScript out of order."
- );
- assert_eq!(entry.kind, StackEntryKind::Incumbent);
- trace!(
- "Clean up after running a callback with {:p}",
- &*entry.global
- );
- });
- unsafe {
- // Step 1-2.
- if let Some(cx) = Runtime::get() {
- UnhideScriptedCaller(cx.as_ptr());
- }
- }
- }
-}
+pub type AutoIncumbentScript = GenericAutoIncumbentScript<crate::DomTypeHolder>;
/// Returns the ["incumbent"] global object.
///
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index b0c65b9fd9d..5d48e4c4e0f 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -33,15 +33,12 @@ use std::collections::HashMap;
use std::collections::hash_map::RandomState;
use std::fmt::Display;
use std::hash::{BuildHasher, Hash};
-use std::mem;
-use std::ops::{Deref, DerefMut};
/// A trait to allow tracing (only) DOM objects.
pub(crate) use js::gc::Traceable as JSTraceable;
use js::glue::{CallScriptTracer, CallStringTracer, CallValueTracer};
use js::jsapi::{GCTraceKindToAscii, Heap, JSScript, JSString, JSTracer, TraceKind};
use js::jsval::JSVal;
-use js::rust::{GCMethods, Handle};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
pub(crate) use script_bindings::trace::*;
@@ -267,70 +264,3 @@ unsafe impl<T: DomObject> JSTraceable for Trusted<T> {
// Do nothing
}
}
-
-/// Roots any JSTraceable thing
-///
-/// If you have a valid DomObject, use DomRoot.
-/// If you have GC things like *mut JSObject or JSVal, use rooted!.
-/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
-/// If you know what you're doing, use this.
-#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
-pub(crate) struct RootedTraceableBox<T: JSTraceable + 'static>(js::gc::RootedTraceableBox<T>);
-
-unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
- unsafe fn trace(&self, tracer: *mut JSTracer) {
- self.0.trace(tracer);
- }
-}
-
-impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
- /// DomRoot a JSTraceable thing for the life of this RootedTraceableBox
- pub(crate) fn new(traceable: T) -> RootedTraceableBox<T> {
- Self(js::gc::RootedTraceableBox::new(traceable))
- }
-
- /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox.
- pub(crate) fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
- Self(js::gc::RootedTraceableBox::from_box(boxed_traceable))
- }
-}
-
-impl<T> RootedTraceableBox<Heap<T>>
-where
- Heap<T>: JSTraceable + 'static,
- T: GCMethods + Copy,
-{
- pub(crate) fn handle(&self) -> Handle<T> {
- self.0.handle()
- }
-}
-
-impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
- fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
- // Briefly resurrect the real Box value so we can rely on the existing calculations.
- // Then immediately forget about it again to avoid dropping the box.
- let inner = unsafe { Box::from_raw(self.0.ptr()) };
- let size = inner.size_of(ops);
- mem::forget(inner);
- size
- }
-}
-
-impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
- fn default() -> RootedTraceableBox<T> {
- RootedTraceableBox::new(T::default())
- }
-}
-
-impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
- type Target = T;
- fn deref(&self) -> &T {
- self.0.deref()
- }
-}
-
-impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
- fn deref_mut(&mut self) -> &mut T {
- self.0.deref_mut()
- }
-}
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index 5f16d3a96d2..f97a7d9a130 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -6,17 +6,15 @@
use std::cell::RefCell;
use std::thread::LocalKey;
-use std::{ptr, slice};
use js::conversions::ToJSValConvertible;
use js::glue::{IsWrapper, JSPrincipalsCallbacks, UnwrapObjectDynamic, UnwrapObjectStatic};
use js::jsapi::{
- CallArgs, DOMCallbacks, HandleId as RawHandleId, HandleObject as RawHandleObject,
- JS_DeprecatedStringHasLatin1Chars, JS_EnumerateStandardClasses, JS_FreezeObject,
- JS_GetLatin1StringCharsAndLength, JS_IsGlobalObject, JS_ResolveStandardClass, JSContext,
- JSObject, MutableHandleIdVector as RawMutableHandleIdVector,
+ CallArgs, DOMCallbacks, HandleObject as RawHandleObject, JS_FreezeObject, JSContext, JSObject,
};
-use js::rust::{Handle, HandleObject, MutableHandleValue, get_object_class, is_dom_class};
+use js::rust::{HandleObject, MutableHandleValue, get_object_class, is_dom_class};
+use script_bindings::interfaces::DomHelpers;
+use script_bindings::settings_stack::StackEntry;
use crate::DomTypes;
use crate::dom::bindings::codegen::{InterfaceObjectMap, PrototypeList};
@@ -29,7 +27,7 @@ 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::settings_stack;
use crate::dom::globalscope::GlobalScope;
use crate::dom::windowproxy::WindowProxyHandler;
use crate::realms::InRealm;
@@ -105,61 +103,6 @@ fn is_platform_object(
}
}
-/// Enumerate lazy properties of a global object.
-pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
- cx: *mut JSContext,
- obj: RawHandleObject,
- _props: RawMutableHandleIdVector,
- _enumerable_only: bool,
-) -> bool {
- assert!(JS_IsGlobalObject(obj.get()));
- if !JS_EnumerateStandardClasses(cx, obj) {
- return false;
- }
- 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<D: DomTypes>(
- cx: *mut JSContext,
- obj: RawHandleObject,
- id: RawHandleId,
- rval: *mut bool,
-) -> bool {
- assert!(JS_IsGlobalObject(obj.get()));
- if !JS_ResolveStandardClass(cx, obj, id, rval) {
- return false;
- }
- if *rval {
- return true;
- }
- if !id.is_string() {
- *rval = false;
- return true;
- }
-
- let string = id.to_string();
- if !JS_DeprecatedStringHasLatin1Chars(string) {
- *rval = false;
- return true;
- }
- let mut length = 0;
- let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
- assert!(!ptr.is_null());
- let bytes = slice::from_raw_parts(ptr, length);
-
- 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 {
- *rval = false;
- }
- true
-}
-
unsafe extern "C" fn instance_class_has_proto_at_depth(
clasp: *const js::jsapi::JSClass,
proto_id: u32,
@@ -175,48 +118,6 @@ pub(crate) const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
};
-/// 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,
- can_gc: CanGc,
- );
-
- unsafe fn call_html_constructor<T: DerivedFrom<D::Element> + DomObject>(
- cx: SafeJSContext,
- args: &CallArgs,
- global: &D::GlobalScope,
- proto_id: crate::dom::bindings::codegen::PrototypeList::ID,
- creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
- can_gc: CanGc,
- ) -> 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 {
fn throw_dom_exception(
cx: SafeJSContext,
@@ -227,7 +128,7 @@ impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
throw_dom_exception(cx, global, result, can_gc)
}
- unsafe fn call_html_constructor<
+ fn call_html_constructor<
T: DerivedFrom<<crate::DomTypeHolder as DomTypes>::Element> + DomObject,
>(
cx: SafeJSContext,
diff --git a/components/script/dom/bindings/weakref.rs b/components/script/dom/bindings/weakref.rs
index 1c86b68c706..c1cb012b7c2 100644
--- a/components/script/dom/bindings/weakref.rs
+++ b/components/script/dom/bindings/weakref.rs
@@ -8,7 +8,7 @@ use std::ops::{Deref, DerefMut, Drop};
use js::jsapi::JSTracer;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
-pub use script_bindings::weakref::*;
+pub(crate) use script_bindings::weakref::*;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::root::DomRoot;
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 11ffdc752d0..6cce4b0f0e7 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -54,6 +54,7 @@ use net_traits::{
ResourceThreads, fetch_async,
};
use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time};
+use script_bindings::interfaces::GlobalScopeHelpers;
use script_traits::serializable::{BlobData, BlobImpl, FileBlob};
use script_traits::transferable::MessagePortImpl;
use script_traits::{
@@ -3318,30 +3319,6 @@ unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot<Glob
root_from_object_static(global).unwrap()
}
-/// Operations that must be invoked from the generated bindings.
-#[allow(unsafe_code)]
-pub(crate) trait GlobalScopeHelpers<D: crate::DomTypes> {
- unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot<D::GlobalScope>;
- fn get_cx() -> SafeJSContext;
- unsafe fn from_object(obj: *mut JSObject) -> DomRoot<D::GlobalScope>;
- fn from_reflector(reflector: &impl DomObject, realm: InRealm) -> DomRoot<D::GlobalScope>;
-
- unsafe fn from_object_maybe_wrapped(
- obj: *mut JSObject,
- cx: *mut JSContext,
- ) -> DomRoot<D::GlobalScope>;
-
- fn origin(&self) -> &MutableOrigin;
-
- fn incumbent() -> Option<DomRoot<D::GlobalScope>>;
-
- fn perform_a_microtask_checkpoint(&self, can_gc: CanGc);
-
- fn get_url(&self) -> ServoUrl;
-
- fn is_secure_context(&self) -> bool;
-}
-
#[allow(unsafe_code)]
impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot<Self> {
diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs
index b970e7f3342..1ac1aa52a45 100644
--- a/components/script/dom/promise.rs
+++ b/components/script/dom/promise.rs
@@ -29,6 +29,7 @@ use js::rust::wrappers::{
ResolvePromise, SetAnyPromiseIsHandled, SetPromiseUserInputEventHandlingState,
};
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
+use script_bindings::interfaces::PromiseHelpers;
use crate::dom::bindings::conversions::root_from_object;
use crate::dom::bindings::error::{Error, ErrorToJsval};
@@ -387,15 +388,6 @@ fn create_native_handler_function(
}
}
-/// Operations that must be invoked from the generated bindings.
-pub(crate) trait PromiseHelpers<D: crate::DomTypes> {
- fn new_resolved(
- global: &D::GlobalScope,
- cx: SafeJSContext,
- value: impl ToJSValConvertible,
- ) -> Rc<D::Promise>;
-}
-
impl PromiseHelpers<crate::DomTypeHolder> for Promise {
fn new_resolved(
global: &GlobalScope,
diff --git a/components/script/lib.rs b/components/script/lib.rs
index b2ade0330c9..7a866f1c7b2 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -45,13 +45,11 @@ pub(crate) mod document_collection;
pub(crate) mod iframe_collection;
pub(crate) mod image_animation;
pub mod layout_dom;
-mod mem;
#[allow(unsafe_code)]
pub(crate) mod messaging;
mod microtask;
mod navigation;
mod network_listener;
-#[allow(dead_code)]
mod realms;
mod routed_promise;
#[allow(dead_code)]
@@ -82,12 +80,12 @@ mod xpath;
mod svgpath;
pub use init::init;
+pub(crate) use script_bindings::DomTypes;
pub use script_runtime::JSEngineSetup;
pub use script_thread::ScriptThread;
pub use serviceworker_manager::ServiceWorkerManager;
pub(crate) use crate::dom::bindings::codegen::DomTypeHolder::DomTypeHolder;
-pub(crate) use crate::dom::bindings::codegen::DomTypes::DomTypes;
// These trait exports are public, because they are used in the DOM bindings.
// Since they are used in derive macros,
// it is useful that they are accessible at the root of the crate.
diff --git a/components/script/realms.rs b/components/script/realms.rs
index 1254b604b42..9a392e7f6af 100644
--- a/components/script/realms.rs
+++ b/components/script/realms.rs
@@ -2,67 +2,10 @@
* 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::jsapi::{GetCurrentRealmOrNull, JSAutoRealm};
-
-use crate::DomTypes;
-use crate::dom::bindings::reflector::DomObject;
-use crate::dom::globalscope::GlobalScopeHelpers;
-use crate::script_runtime::JSContext;
-
-pub(crate) struct AlreadyInRealm(());
-
-impl AlreadyInRealm {
- #![allow(unsafe_code)]
- pub(crate) fn assert<D: DomTypes>() -> AlreadyInRealm {
- unsafe {
- assert!(!GetCurrentRealmOrNull(*D::GlobalScope::get_cx()).is_null());
- }
- AlreadyInRealm(())
- }
-
- pub(crate) fn assert_for_cx(cx: JSContext) -> AlreadyInRealm {
- unsafe {
- assert!(!GetCurrentRealmOrNull(*cx).is_null());
- }
- AlreadyInRealm(())
- }
-}
-
-#[derive(Clone, Copy)]
-pub(crate) enum InRealm<'a> {
- Already(&'a AlreadyInRealm),
- Entered(&'a JSAutoRealm),
-}
-
-impl<'a> From<&'a AlreadyInRealm> for InRealm<'a> {
- fn from(token: &'a AlreadyInRealm) -> InRealm<'a> {
- InRealm::already(token)
- }
-}
-
-impl<'a> From<&'a JSAutoRealm> for InRealm<'a> {
- fn from(token: &'a JSAutoRealm) -> InRealm<'a> {
- InRealm::entered(token)
- }
-}
-
-impl InRealm<'_> {
- pub(crate) fn already(token: &AlreadyInRealm) -> InRealm {
- InRealm::Already(token)
- }
-
- pub(crate) fn entered(token: &JSAutoRealm) -> InRealm {
- InRealm::Entered(token)
- }
-}
-
-pub(crate) fn enter_realm_generic<D: DomTypes>(object: &impl DomObject) -> JSAutoRealm {
- JSAutoRealm::new(
- *D::GlobalScope::get_cx(),
- object.reflector().get_jsobject().get(),
- )
-}
+use js::jsapi::JSAutoRealm;
+pub(crate) use script_bindings::realms::{AlreadyInRealm, InRealm};
+use script_bindings::reflector::DomObject;
pub(crate) fn enter_realm(object: &impl DomObject) -> JSAutoRealm {
- enter_realm_generic::<crate::DomTypeHolder>(object)
+ script_bindings::realms::enter_realm::<crate::DomTypeHolder>(object)
}
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 17c13e3c0b9..956ab4791da 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -27,6 +27,7 @@ use net_traits::CoreResourceMsg::{
DeleteCookie, DeleteCookies, GetCookiesDataForUrl, SetCookieForUrl,
};
use net_traits::IpcSend;
+use script_bindings::conversions::is_array_like;
use servo_url::ServoUrl;
use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus;
@@ -45,8 +46,7 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::XMLSerializerBinding::XMLSerializerMethods;
use crate::dom::bindings::conversions::{
ConversionBehavior, ConversionResult, FromJSValConvertible, StringificationBehavior,
- get_property, get_property_jsval, is_array_like, jsid_to_string, jsstring_to_str,
- root_from_object,
+ get_property, get_property_jsval, jsid_to_string, jsstring_to_str, root_from_object,
};
use crate::dom::bindings::error::{Error, throw_dom_exception};
use crate::dom::bindings::inheritance::Castable;
diff --git a/components/script_bindings/Cargo.toml b/components/script_bindings/Cargo.toml
index 7d19ab39c25..7e4e751a2a8 100644
--- a/components/script_bindings/Cargo.toml
+++ b/components/script_bindings/Cargo.toml
@@ -19,6 +19,9 @@ path = "lib.rs"
bitflags = { workspace = true }
crossbeam-channel = { workspace = true }
cssparser = { workspace = true }
+deny_public_fields = { path = "../deny_public_fields" }
+dom_struct = { path = "../dom_struct" }
+domobject_derive = { path = "../domobject_derive" }
html5ever = { workspace = true }
indexmap = { workspace = true }
js = { workspace = true }
@@ -29,13 +32,16 @@ malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
num-traits = { workspace = true }
parking_lot = { workspace = true }
+phf = "0.11"
regex = { workspace = true }
servo_arc = { workspace = true }
servo_config = { path = "../config" }
+servo_url = { path = "../url" }
smallvec = { workspace = true }
stylo = { workspace = true }
stylo_atoms = { workspace = true }
tendril = { version = "0.4.1", features = ["encoding_rs"] }
+tracing = { workspace = true, optional = true }
webxr-api = { workspace = true, optional = true }
xml5ever = { workspace = true }
@@ -46,6 +52,7 @@ serde_json = { workspace = true }
[features]
bluetooth = []
+tracing = ["dep:tracing"]
webgpu = []
webxr = ["webxr-api"]
diff --git a/components/script_bindings/callback.rs b/components/script_bindings/callback.rs
index d891535e671..a31b57f677f 100644
--- a/components/script_bindings/callback.rs
+++ b/components/script_bindings/callback.rs
@@ -2,10 +2,31 @@
* 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::jsapi::JSObject;
-use js::rust::HandleObject;
+//! Base classes to work with IDL callbacks.
+use std::default::Default;
+use std::ffi::CString;
+use std::mem::drop;
+use std::rc::Rc;
+
+use js::jsapi::{
+ AddRawValueRoot, EnterRealm, Heap, IsCallable, JSObject, LeaveRealm, Realm, RemoveRawValueRoot,
+};
+use js::jsval::{JSVal, ObjectValue, UndefinedValue};
+use js::rust::wrappers::{JS_GetProperty, JS_WrapObject};
+use js::rust::{HandleObject, MutableHandleValue, Runtime};
+
+use crate::DomTypes;
+use crate::codegen::GenericBindings::WindowBinding::Window_Binding::WindowMethods;
+use crate::error::{Error, Fallible};
+use crate::inheritance::Castable;
+use crate::interfaces::{DocumentHelpers, DomHelpers, GlobalScopeHelpers};
+use crate::realms::{InRealm, enter_realm};
use crate::reflector::DomObject;
+use crate::root::{Dom, DomRoot};
+use crate::script_runtime::{CanGc, JSContext};
+use crate::settings_stack::{GenericAutoEntryScript, GenericAutoIncumbentScript};
+use crate::utils::AsCCharPtrPtr;
pub trait ThisReflector {
fn jsobject(&self) -> *mut JSObject;
@@ -22,3 +43,275 @@ impl ThisReflector for HandleObject<'_> {
self.get()
}
}
+
+/// The exception handling used for a call.
+#[derive(Clone, Copy, PartialEq)]
+pub enum ExceptionHandling {
+ /// Report any exception and don't throw it to the caller code.
+ Report,
+ /// Throw any exception to the caller code.
+ Rethrow,
+}
+
+/// A common base class for representing IDL callback function and
+/// callback interface types.
+#[derive(JSTraceable)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+pub struct CallbackObject<D: DomTypes> {
+ /// The underlying `JSObject`.
+ callback: Heap<*mut JSObject>,
+ permanent_js_root: Heap<JSVal>,
+
+ /// The ["callback context"], that is, the global to use as incumbent
+ /// global when calling the callback.
+ ///
+ /// Looking at the WebIDL standard, it appears as though there would always
+ /// be a value here, but [sometimes] callback functions are created by
+ /// hand-waving without defining the value of the callback context, and
+ /// without any JavaScript code on the stack to grab an incumbent global
+ /// from.
+ ///
+ /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
+ /// [sometimes]: https://github.com/whatwg/html/issues/2248
+ incumbent: Option<Dom<D::GlobalScope>>,
+}
+
+impl<D: DomTypes> CallbackObject<D> {
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ // These are used by the bindings and do not need `default()` functions.
+ #[allow(clippy::new_without_default)]
+ fn new() -> Self {
+ Self {
+ callback: Heap::default(),
+ permanent_js_root: Heap::default(),
+ incumbent: D::GlobalScope::incumbent().map(|i| Dom::from_ref(&*i)),
+ }
+ }
+
+ pub fn get(&self) -> *mut JSObject {
+ self.callback.get()
+ }
+
+ #[allow(unsafe_code)]
+ unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) {
+ self.callback.set(callback);
+ self.permanent_js_root.set(ObjectValue(callback));
+ assert!(AddRawValueRoot(
+ *cx,
+ self.permanent_js_root.get_unsafe(),
+ b"CallbackObject::root\n".as_c_char_ptr()
+ ));
+ }
+}
+
+impl<D: DomTypes> Drop for CallbackObject<D> {
+ #[allow(unsafe_code)]
+ fn drop(&mut self) {
+ unsafe {
+ if let Some(cx) = Runtime::get() {
+ RemoveRawValueRoot(cx.as_ptr(), self.permanent_js_root.get_unsafe());
+ }
+ }
+ }
+}
+
+impl<D: DomTypes> PartialEq for CallbackObject<D> {
+ fn eq(&self, other: &CallbackObject<D>) -> bool {
+ self.callback.get() == other.callback.get()
+ }
+}
+
+/// A trait to be implemented by concrete IDL callback function and
+/// callback interface types.
+pub trait CallbackContainer<D: DomTypes> {
+ /// Create a new CallbackContainer object for the given `JSObject`.
+ ///
+ /// # Safety
+ /// `callback` must point to a valid, non-null JSObject.
+ unsafe fn new(cx: JSContext, callback: *mut JSObject) -> Rc<Self>;
+ /// Returns the underlying `CallbackObject`.
+ fn callback_holder(&self) -> &CallbackObject<D>;
+ /// Returns the underlying `JSObject`.
+ fn callback(&self) -> *mut JSObject {
+ self.callback_holder().get()
+ }
+ /// Returns the ["callback context"], that is, the global to use as
+ /// incumbent global when calling the callback.
+ ///
+ /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
+ fn incumbent(&self) -> Option<&D::GlobalScope> {
+ self.callback_holder().incumbent.as_deref()
+ }
+}
+
+/// A common base class for representing IDL callback function types.
+#[derive(JSTraceable, PartialEq)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+pub struct CallbackFunction<D: DomTypes> {
+ object: CallbackObject<D>,
+}
+
+impl<D: DomTypes> CallbackFunction<D> {
+ /// Create a new `CallbackFunction` for this object.
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ // These are used by the bindings and do not need `default()` functions.
+ #[allow(clippy::new_without_default)]
+ pub fn new() -> Self {
+ Self {
+ object: CallbackObject::new(),
+ }
+ }
+
+ /// Returns the underlying `CallbackObject`.
+ pub fn callback_holder(&self) -> &CallbackObject<D> {
+ &self.object
+ }
+
+ /// Initialize the callback function with a value.
+ /// Should be called once this object is done moving.
+ ///
+ /// # Safety
+ /// `callback` must point to a valid, non-null JSObject.
+ pub unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) {
+ self.object.init(cx, callback);
+ }
+}
+
+/// A common base class for representing IDL callback interface types.
+#[derive(JSTraceable, PartialEq)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+pub struct CallbackInterface<D: DomTypes> {
+ object: CallbackObject<D>,
+}
+
+impl<D: DomTypes> CallbackInterface<D> {
+ /// Create a new CallbackInterface object for the given `JSObject`.
+ // These are used by the bindings and do not need `default()` functions.
+ #[allow(clippy::new_without_default)]
+ pub fn new() -> Self {
+ Self {
+ object: CallbackObject::new(),
+ }
+ }
+
+ /// Returns the underlying `CallbackObject`.
+ pub fn callback_holder(&self) -> &CallbackObject<D> {
+ &self.object
+ }
+
+ /// Initialize the callback function with a value.
+ /// Should be called once this object is done moving.
+ ///
+ /// # Safety
+ /// `callback` must point to a valid, non-null JSObject.
+ pub unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) {
+ self.object.init(cx, callback);
+ }
+
+ /// Returns the property with the given `name`, if it is a callable object,
+ /// or an error otherwise.
+ pub fn get_callable_property(&self, cx: JSContext, name: &str) -> Fallible<JSVal> {
+ rooted!(in(*cx) let mut callable = UndefinedValue());
+ rooted!(in(*cx) let obj = self.callback_holder().get());
+ unsafe {
+ let c_name = CString::new(name).unwrap();
+ if !JS_GetProperty(*cx, obj.handle(), c_name.as_ptr(), callable.handle_mut()) {
+ return Err(Error::JSFailed);
+ }
+
+ if !callable.is_object() || !IsCallable(callable.to_object()) {
+ return Err(Error::Type(format!(
+ "The value of the {} property is not callable",
+ name
+ )));
+ }
+ }
+ Ok(callable.get())
+ }
+}
+
+/// Wraps the reflector for `p` into the realm of `cx`.
+pub(crate) fn wrap_call_this_value<T: ThisReflector>(
+ cx: JSContext,
+ p: &T,
+ mut rval: MutableHandleValue,
+) -> bool {
+ rooted!(in(*cx) let mut obj = p.jsobject());
+ assert!(!obj.is_null());
+
+ unsafe {
+ if !JS_WrapObject(*cx, obj.handle_mut()) {
+ return false;
+ }
+ }
+
+ rval.set(ObjectValue(*obj));
+ true
+}
+
+/// A class that performs whatever setup we need to safely make a call while
+/// this class is on the stack. After `new` returns, the call is safe to make.
+pub struct CallSetup<D: DomTypes> {
+ /// The global for reporting exceptions. This is the global object of the
+ /// (possibly wrapped) callback object.
+ exception_global: DomRoot<D::GlobalScope>,
+ /// The `JSContext` used for the call.
+ cx: JSContext,
+ /// The realm we were in before the call.
+ old_realm: *mut Realm,
+ /// The exception handling used for the call.
+ handling: ExceptionHandling,
+ /// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
+ /// steps 8 and 18.2.
+ entry_script: Option<GenericAutoEntryScript<D>>,
+ /// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
+ /// steps 9 and 18.1.
+ incumbent_script: Option<GenericAutoIncumbentScript<D>>,
+}
+
+impl<D: DomTypes> CallSetup<D> {
+ /// Performs the setup needed to make a call.
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ pub fn new<T: CallbackContainer<D>>(callback: &T, handling: ExceptionHandling) -> Self {
+ let global = unsafe { D::GlobalScope::from_object(callback.callback()) };
+ if let Some(window) = global.downcast::<D::Window>() {
+ window.Document().ensure_safe_to_run_script_or_layout();
+ }
+ let cx = D::GlobalScope::get_cx();
+
+ let aes = GenericAutoEntryScript::<D>::new(&global);
+ let ais = callback.incumbent().map(GenericAutoIncumbentScript::new);
+ CallSetup {
+ exception_global: global,
+ cx,
+ old_realm: unsafe { EnterRealm(*cx, callback.callback()) },
+ handling,
+ entry_script: Some(aes),
+ incumbent_script: ais,
+ }
+ }
+
+ /// Returns the `JSContext` used for the call.
+ pub fn get_context(&self) -> JSContext {
+ self.cx
+ }
+}
+
+impl<D: DomTypes> Drop for CallSetup<D> {
+ fn drop(&mut self) {
+ unsafe {
+ LeaveRealm(*self.cx, self.old_realm);
+ }
+ if self.handling == ExceptionHandling::Report {
+ let ar = enter_realm::<D>(&*self.exception_global);
+ <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());
+ }
+}
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index 1c888b27292..a3adf0f39ab 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -141,7 +141,7 @@ DOMInterfaces = {
},
'Document': {
- 'additionalTraits': ["script_bindings::interfaces::DocumentHelpers"],
+ 'additionalTraits': ["crate::interfaces::DocumentHelpers"],
'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ElementFromPoint', 'ElementsFromPoint', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate'],
},
@@ -240,7 +240,7 @@ DOMInterfaces = {
},
'GlobalScope': {
- 'additionalTraits': ['crate::dom::globalscope::GlobalScopeHelpers<Self>'],
+ 'additionalTraits': ['crate::interfaces::GlobalScopeHelpers<Self>'],
},
'GPU': {
@@ -494,7 +494,7 @@ DOMInterfaces = {
'Promise': {
'spiderMonkeyInterface': True,
- 'additionalTraits': ["crate::dom::promise::PromiseHelpers<Self>", "js::conversions::FromJSValConvertibleRc"]
+ 'additionalTraits': ["crate::interfaces::PromiseHelpers<Self>", "js::conversions::FromJSValConvertibleRc"]
},
'Range': {
@@ -531,7 +531,7 @@ DOMInterfaces = {
'ServoInternals': {
'inRealms': ['ReportMemory'],
'canGc': ['ReportMemory'],
- 'additionalTraits': ['script_bindings::interfaces::ServoInternalsHelpers'],
+ 'additionalTraits': ['crate::interfaces::ServoInternalsHelpers'],
},
'ShadowRoot': {
@@ -555,7 +555,7 @@ DOMInterfaces = {
'TestBinding': {
'inRealms': ['PromiseAttribute', 'PromiseNativeHandler'],
'canGc': ['InterfaceAttribute', 'GetInterfaceAttributeNullable', 'ReceiveInterface', 'ReceiveInterfaceSequence', 'ReceiveNullableInterface', 'PromiseAttribute', 'PromiseNativeHandler', 'PromiseResolveNative', 'PromiseRejectNative', 'PromiseRejectWithTypeError'],
- 'additionalTraits': ['script_bindings::interfaces::TestBindingHelpers'],
+ 'additionalTraits': ['crate::interfaces::TestBindingHelpers'],
},
'TestWorklet': {
@@ -586,13 +586,13 @@ DOMInterfaces = {
'WebGL2RenderingContext': {
'canGc': ['MakeXRCompatible'],
- 'additionalTraits': ['script_bindings::interfaces::WebGL2RenderingContextHelpers'],
+ 'additionalTraits': ['crate::interfaces::WebGL2RenderingContextHelpers'],
},
'Window': {
'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap'],
'inRealms': ['Fetch', 'GetOpener'],
- 'additionalTraits': ['script_bindings::interfaces::WindowHelpers'],
+ 'additionalTraits': ['crate::interfaces::WindowHelpers'],
},
'WindowProxy' : {
diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py
index 09a4bd4139f..4f87ec792b4 100644
--- a/components/script_bindings/codegen/CodegenRust.py
+++ b/components/script_bindings/codegen/CodegenRust.py
@@ -2282,10 +2282,10 @@ class CGImports(CGWrapper):
parentName = descriptor.getParentName()
while parentName:
descriptor = descriptorProvider.getDescriptor(parentName)
- extras += [descriptor.path, descriptor.bindingPath]
+ extras += [descriptor.bindingPath]
parentName = descriptor.getParentName()
elif t.isType() and t.isRecord():
- extras += ['script_bindings::record::Record']
+ extras += ['crate::record::Record']
elif isinstance(t, IDLPromiseType):
pass
else:
@@ -2316,7 +2316,7 @@ class CGTemplatedType(CGWrapper):
class CGNamespace(CGWrapper):
def __init__(self, namespace, child, public=False):
- pub = "pub(crate) " if public else ""
+ pub = "pub " if public else ""
pre = f"{pub}mod {namespace} {{\n"
post = f"}} // mod {namespace}"
CGWrapper.__init__(self, child, pre=pre, post=post)
@@ -2337,15 +2337,15 @@ def DOMClassTypeId(desc):
inner = ""
if desc.hasDescendants():
if desc.interface.getExtendedAttribute("Abstract"):
- return "script_bindings::codegen::InheritTypes::TopTypeId { abstract_: () }"
+ return "crate::codegen::InheritTypes::TopTypeId { abstract_: () }"
name = desc.interface.identifier.name
- inner = f"(script_bindings::codegen::InheritTypes::{name}TypeId::{name})"
+ inner = f"(crate::codegen::InheritTypes::{name}TypeId::{name})"
elif len(protochain) == 1:
- return "script_bindings::codegen::InheritTypes::TopTypeId { alone: () }"
+ return "crate::codegen::InheritTypes::TopTypeId { alone: () }"
reversed_protochain = list(reversed(protochain))
for (child, parent) in zip(reversed_protochain, reversed_protochain[1:]):
- inner = f"(script_bindings::codegen::InheritTypes::{parent}TypeId::{child}{inner})"
- return f"script_bindings::codegen::InheritTypes::TopTypeId {{ {protochain[0].lower()}: {inner} }}"
+ inner = f"(crate::codegen::InheritTypes::{parent}TypeId::{child}{inner})"
+ return f"crate::codegen::InheritTypes::TopTypeId {{ {protochain[0].lower()}: {inner} }}"
def DOMClass(descriptor):
@@ -2421,7 +2421,7 @@ pub(crate) fn init_class_ops<D: DomTypes>() {{
}});
}}
-pub(crate) static Class: ThreadUnsafeOnceLock<DOMJSClass> = ThreadUnsafeOnceLock::new();
+pub static Class: ThreadUnsafeOnceLock<DOMJSClass> = ThreadUnsafeOnceLock::new();
pub(crate) fn init_domjs_class<D: DomTypes>() {{
init_class_ops::<D>();
@@ -2637,13 +2637,10 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
"""
imports = [
- 'crate::dom',
- 'crate::dom::bindings::import::base::*',
- 'crate::dom::bindings::codegen::DomTypes::DomTypes',
- 'crate::dom::bindings::conversions::windowproxy_from_handlevalue',
- 'script_bindings::record::Record',
- 'crate::dom::types::*',
- 'crate::dom::windowproxy::WindowProxy',
+ 'crate::import::base::*',
+ 'crate::codegen::DomTypes::DomTypes',
+ 'crate::conversions::windowproxy_from_handlevalue',
+ 'crate::record::Record',
'js::typedarray',
]
@@ -2679,13 +2676,13 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs, config):
traits = [
- "crate::dom::bindings::utils::DomHelpers<Self>",
+ "crate::interfaces::DomHelpers<Self>",
"js::rust::Trace",
"malloc_size_of::MallocSizeOf",
"Sized",
]
joinedTraits = ' + '.join(traits)
- elements = [CGGeneric(f"pub(crate) trait DomTypes: {joinedTraits} where Self: 'static {{\n")]
+ elements = [CGGeneric(f"pub trait DomTypes: {joinedTraits} where Self: 'static {{\n")]
def fixupInterfaceTypeReferences(typename):
return typename.replace("D::", "Self::")
@@ -2705,10 +2702,10 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
chain = chain[:-1]
if chain:
- traits += ["crate::dom::bindings::inheritance::Castable"]
+ traits += ["crate::inheritance::Castable"]
for parent in chain:
- traits += [f"crate::dom::bindings::conversions::DerivedFrom<Self::{parent}>"]
+ traits += [f"crate::conversions::DerivedFrom<Self::{parent}>"]
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
if iterableDecl:
@@ -2719,27 +2716,27 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
valuetype = fixupInterfaceTypeReferences(
getRetvalDeclarationForType(iterableDecl.valueType, descriptor).define()
)
- traits += [f"crate::dom::bindings::like::Maplike<Key={keytype}, Value={valuetype}>"]
+ traits += [f"crate::like::Maplike<Key={keytype}, Value={valuetype}>"]
if iterableDecl.isSetlike():
keytype = fixupInterfaceTypeReferences(
getRetvalDeclarationForType(iterableDecl.keyType, descriptor).define()
)
- traits += [f"crate::dom::bindings::like::Setlike<Key={keytype}>"]
+ traits += [f"crate::like::Setlike<Key={keytype}>"]
if iterableDecl.hasKeyType():
traits += [
- "crate::dom::bindings::reflector::DomObjectIteratorWrap<Self>",
- "crate::dom::bindings::iterable::IteratorDerives",
+ "crate::reflector::DomObjectIteratorWrap<Self>",
+ "crate::iterable::IteratorDerives",
]
if descriptor.weakReferenceable:
- traits += ["crate::dom::bindings::weakref::WeakReferenceable"]
+ traits += ["crate::weakref::WeakReferenceable"]
if not descriptor.interface.isNamespace():
traits += [
"js::conversions::ToJSValConvertible",
- "crate::dom::bindings::reflector::MutDomObject",
- "crate::dom::bindings::reflector::DomObject",
- "crate::dom::bindings::reflector::DomGlobalGeneric<Self>",
+ "crate::reflector::MutDomObject",
+ "crate::reflector::DomObject",
+ "crate::reflector::DomGlobalGeneric<Self>",
"malloc_size_of::MallocSizeOf",
]
@@ -2750,12 +2747,12 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
and not descriptor.interface.isIteratorInterface()
):
traits += [
- "crate::dom::bindings::conversions::IDLInterface",
+ "crate::conversions::IDLInterface",
"PartialEq",
]
if descriptor.concrete and not descriptor.isGlobal():
- traits += ["crate::dom::bindings::reflector::DomObjectWrap<Self>"]
+ traits += ["crate::reflector::DomObjectWrap<Self>"]
if not descriptor.interface.isCallback() and not descriptor.interface.isIteratorInterface():
nonConstMembers = [m for m in descriptor.interface.members if not m.isConst()]
@@ -2766,7 +2763,7 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
or descriptor.interface.legacyFactoryFunctions
):
namespace = f"{toBindingPath(descriptor)}"
- traits += [f"crate::dom::bindings::codegen::Bindings::{namespace}::{iface_name}Methods<Self>"]
+ traits += [f"crate::codegen::GenericBindings::{namespace}::{iface_name}Methods<Self>"]
isPromise = firstCap(iface_name) == "Promise"
elements += [
CGGeneric(" #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]\n"),
@@ -2778,8 +2775,8 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
]
elements += [CGGeneric("}\n")]
imports = [
- CGGeneric("use crate::dom::bindings::root::DomRoot;\n"),
- CGGeneric("use crate::dom::bindings::str::DOMString;\n"),
+ CGGeneric("use crate::root::DomRoot;\n"),
+ CGGeneric("use crate::str::DOMString;\n"),
]
return CGList(imports + elements)
@@ -3403,7 +3400,7 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod):
self.toJSONMethod = toJSONMethod
def definition_body(self):
- ret = """let incumbent_global = GlobalScope::incumbent().expect("no incumbent global");
+ ret = """let incumbent_global = D::GlobalScope::incumbent().expect("no incumbent global");
let global = incumbent_global.reflector().get_jsobject();\n"""
interface = self.descriptor.interface
for m in interface.members:
@@ -4322,7 +4319,7 @@ class CGDefaultToJSONMethod(CGSpecializedMethod):
def definition_body(self):
ret = dedent("""
- use crate::dom::bindings::inheritance::HasParent;
+ use crate::inheritance::HasParent;
rooted!(in(cx) let result = JS_NewPlainObject(cx));
if result.is_null() {
return false;
@@ -4965,7 +4962,7 @@ class CGEnum(CGThing):
decl = f"""
#[repr(usize)]
#[derive({derives})]
-pub(crate) enum {ident} {{
+pub enum {ident} {{
{enums}
}}
"""
@@ -4974,10 +4971,10 @@ pub(crate) enum {ident} {{
for val in list(enum.values())])
inner = f"""
-use crate::dom::bindings::conversions::ConversionResult;
-use crate::dom::bindings::conversions::FromJSValConvertible;
-use crate::dom::bindings::conversions::ToJSValConvertible;
-use crate::dom::bindings::utils::find_enum_value;
+use crate::utils::find_enum_value;
+use js::conversions::ConversionResult;
+use js::conversions::FromJSValConvertible;
+use js::conversions::ToJSValConvertible;
use js::jsapi::JSContext;
use js::rust::HandleValue;
use js::rust::MutableHandleValue;
@@ -4988,7 +4985,7 @@ pub(crate) const pairs: &[(&str, super::{ident})] = &[
];
impl super::{ident} {{
- pub(crate) fn as_str(&self) -> &'static str {{
+ pub fn as_str(&self) -> &'static str {{
pairs[*self as usize].0
}}
}}
@@ -5077,7 +5074,7 @@ class CGConstant(CGThing):
elif tag == IDLType.Tags.double:
const_type = "f64"
- return f"pub(crate) const {name}: {const_type} = {value};\n"
+ return f"pub const {name}: {const_type} = {value};\n"
def getUnionTypeTemplateVars(type, descriptorProvider):
@@ -5208,7 +5205,7 @@ impl{self.generic} Clone for {self.type}{self.genericSuffix} {{
manualImpls = "\n".join(map(lambda t: self.manualImpl(t, templateVars), self.manualImpls))
return f"""
#[derive({", ".join(derives)})]
-pub(crate) enum {self.type}{self.generic} {{
+pub enum {self.type}{self.generic} {{
{joinedEnumValues}
}}
@@ -5589,7 +5586,7 @@ class ClassConstructor(ClassItem):
name = cgClass.getNameString().replace(': DomTypes', '')
return f"""
-pub(crate) unsafe fn {self.getDecorators(True)}new({args}) -> Rc<{name}>{body}
+pub unsafe fn {self.getDecorators(True)}new({args}) -> Rc<{name}>{body}
"""
def define(self, cgClass):
@@ -5681,7 +5678,7 @@ class CGClass(CGThing):
myself = ''
if self.decorators != '':
myself += f'{self.decorators}\n'
- myself += f'{self.indent}pub(crate) struct {self.name}{specialization}'
+ myself += f'{self.indent}pub struct {self.name}{specialization}'
result += myself
assert len(self.bases) == 1 # XXjdm Can we support multiple inheritance?
@@ -5689,7 +5686,7 @@ class CGClass(CGThing):
result += ' {\n'
if self.bases:
- self.members = [ClassMember("parent", self.bases[0].name, "pub(crate)")] + self.members
+ self.members = [ClassMember("parent", self.bases[0].name, "pub")] + self.members
result += CGIndenter(CGGeneric(self.extradeclarations),
len(self.indent)).define()
@@ -6590,7 +6587,7 @@ class CGDOMJSProxyHandlerDOMClass(CGThing):
def define(self):
return f"""
-pub(crate) static Class: ThreadUnsafeOnceLock<DOMClass> = ThreadUnsafeOnceLock::new();
+pub static Class: ThreadUnsafeOnceLock<DOMClass> = ThreadUnsafeOnceLock::new();
pub(crate) fn init_proxy_handler_dom_class<D: DomTypes>() {{
Class.set({DOMClass(self.descriptor)});
@@ -6758,7 +6755,7 @@ class CGInterfaceTrait(CGThing):
name = descriptor.interface.identifier.name
self.cgRoot = CGWrapper(CGIndenter(CGList(methods, "")),
- pre=f"pub(crate) trait {name}Methods<D: DomTypes> {{\n",
+ pre=f"pub trait {name}Methods<D: DomTypes> {{\n",
post="}")
self.empty = not methods
@@ -6793,7 +6790,7 @@ class CGInitStatics(CGThing):
] for name in nonempty]
flat_specs = [x for xs in specs for x in xs]
specs = '\n'.join(flat_specs)
- module = f"crate::dom::bindings::codegen::Bindings::{toBindingPath(descriptor)}"
+ module = f"crate::codegen::GenericBindings::{toBindingPath(descriptor)}"
relevantMethods = [
m for m in descriptor.interface.members if m.isMethod()
] if not descriptor.interface.isCallback() else []
@@ -7055,8 +7052,7 @@ class CGDescriptor(CGThing):
# These are inside the generated module
cgThings = CGImports(cgThings, descriptors=[descriptor], callbacks=[],
dictionaries=[], enums=[], typedefs=[], imports=[
- 'crate::dom',
- 'crate::dom::bindings::import::module::*',
+ 'crate::import::module::*',
], config=config)
cgThings = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
@@ -7066,7 +7062,7 @@ class CGDescriptor(CGThing):
if reexports:
reexports = ', '.join([reexportedName(name) for name in reexports])
namespace = toBindingNamespace(descriptor.name)
- cgThings = CGList([CGGeneric(f'pub(crate) use self::{namespace}::{{{reexports}}};'),
+ cgThings = CGList([CGGeneric(f'pub use self::{namespace}::{{{reexports}}};'),
cgThings], '\n')
self.cgRoot = cgThings
@@ -7171,10 +7167,10 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS
typeName += parentSuffix
if type_needs_tracing(d.parent):
typeName = f"RootedTraceableBox<{typeName}>"
- inheritance = f" pub(crate) parent: {typeName},\n"
+ inheritance = f" pub parent: {typeName},\n"
else:
inheritance = ""
- memberDecls = [f" pub(crate) {self.makeMemberName(m[0].identifier.name)}: {self.getMemberType(m)},"
+ memberDecls = [f" pub {self.makeMemberName(m[0].identifier.name)}: {self.getMemberType(m)},"
for m in self.memberInfo]
derive = ["JSTraceable"] + self.derives
@@ -7216,7 +7212,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS
return (
f"#[derive({', '.join(derive)})]\n"
f"{mustRoot}"
- f"pub(crate) struct {self.makeClassName(d)}{self.generic} {{\n"
+ f"pub struct {self.makeClassName(d)}{self.generic} {{\n"
f"{inheritance}"
f"{joinedMemberDecls}\n"
"}\n"
@@ -7290,7 +7286,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS
return (
f"impl{self.generic} {selfName}{self.genericSuffix} {{\n"
f"{CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define()}\n"
- " pub(crate) fn new(cx: SafeJSContext, val: HandleValue) \n"
+ " pub fn new(cx: SafeJSContext, val: HandleValue) \n"
f" -> Result<ConversionResult<{actualType}>, ()> {{\n"
f" {unsafe_if_necessary} {{\n"
" let object = if val.get().is_null_or_undefined() {\n"
@@ -7320,7 +7316,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS
"\n"
f"impl{self.generic} {selfName}{self.genericSuffix} {{\n"
" #[allow(clippy::wrong_self_convention)]\n"
- " pub(crate) unsafe fn to_jsobject(&self, cx: *mut JSContext, mut obj: MutableHandleObject) {\n"
+ " pub unsafe fn to_jsobject(&self, cx: *mut JSContext, mut obj: MutableHandleObject) {\n"
f"{CGIndenter(CGList(memberInserts), indentLevel=8).define()} }}\n"
"}\n"
"\n"
@@ -7396,7 +7392,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS
parentTemplate = "parent: %s::%s::empty(),\n"
fieldTemplate = "%s: %s,\n"
functionTemplate = (
- "pub(crate) fn empty() -> Self {\n"
+ "pub fn empty() -> Self {\n"
" Self {\n"
"%s"
" }\n"
@@ -7406,7 +7402,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS
parentTemplate = "dictionary.parent = %s::%s::empty();\n"
fieldTemplate = "dictionary.%s = %s;\n"
functionTemplate = (
- "pub(crate) fn empty() -> RootedTraceableBox<Self> {\n"
+ "pub fn empty() -> RootedTraceableBox<Self> {\n"
" let mut dictionary = RootedTraceableBox::new(Self::default());\n"
"%s"
" dictionary\n"
@@ -7463,7 +7459,7 @@ class CGInitAllStatics(CGAbstractMethod):
def definition_body(self):
return CGList([
- CGGeneric(f" Bindings::{toBindingModuleFileFromDescriptor(desc)}::{toBindingNamespace(desc.name)}"
+ CGGeneric(f" GenericBindings::{toBindingModuleFileFromDescriptor(desc)}::{toBindingNamespace(desc.name)}"
"::init_statics::<D>();")
for desc in self.descriptors
], "\n")
@@ -7473,18 +7469,21 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod):
def __init__(self, descriptors):
docs = "Create the global vtables used by the generated DOM bindings to implement JS proxies."
CGAbstractMethod.__init__(self, None, 'RegisterProxyHandlers', 'void', [],
- unsafe=True, pub=True, docs=docs, templateArgs=["D: DomTypes"])
+ pub=True, docs=docs, templateArgs=["D: DomTypes"])
self.descriptors = descriptors
def definition_body(self):
- return CGList([
+ body = [CGGeneric("unsafe {")]
+ body += [
CGGeneric(f"proxy_handlers::{desc.name}.store(\n"
- f" Bindings::{toBindingModuleFile(desc.name)}::{toBindingNamespace(desc.name)}"
+ f" GenericBindings::{toBindingModuleFile(desc.name)}::{toBindingNamespace(desc.name)}"
"::DefineProxyHandler::<D>() as *mut _,\n"
" std::sync::atomic::Ordering::Release,\n"
");")
for desc in self.descriptors
- ], "\n")
+ ]
+ body += [CGGeneric("}")]
+ return CGList(body, "\n")
class CGRegisterProxyHandlers(CGThing):
@@ -7687,11 +7686,11 @@ class CGBindingRoot(CGThing):
if t.innerType.isUnion() and not t.innerType.nullable():
# Allow using the typedef's name for accessing variants.
- typeDefinition = f"pub(crate) use self::{type.replace('<D>', '')} as {name};"
+ typeDefinition = f"pub use self::{type.replace('<D>', '')} as {name};"
else:
generic = "<D>" if containsDomInterface(t.innerType) else ""
replacedType = type.replace("D::", "<D as DomTypes>::")
- typeDefinition = f"pub(crate) type {name}{generic} = {replacedType};"
+ typeDefinition = f"pub type {name}{generic} = {replacedType};"
cgthings.append(CGGeneric(typeDefinition))
@@ -7719,7 +7718,7 @@ class CGBindingRoot(CGThing):
# These are the global imports (outside of the generated module)
curr = CGImports(curr, descriptors=callbackDescriptors, callbacks=mainCallbacks,
dictionaries=dictionaries, enums=enums, typedefs=typedefs,
- imports=['crate::dom::bindings::import::base::*'], config=config)
+ imports=['crate::import::base::*'], config=config)
# Add the auto-generated comment.
curr = CGWrapper(curr, pre=f"{AUTOGENERATED_WARNING_COMMENT}{ALLOWED_WARNINGS}")
@@ -8589,7 +8588,7 @@ class GlobalGenRoots():
], "\n")
return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[
- 'crate::dom::bindings::codegen::Bindings',
+ 'crate::codegen::GenericBindings',
'crate::DomTypes',
], config=config)
@@ -8616,7 +8615,7 @@ class GlobalGenRoots():
| set(leafModule(d) for d in config.getDictionaries()))
curr = CGList([CGGeneric(
"#[allow(clippy::derivable_impls)]\n"
- f"pub(crate) mod {name};\n"
+ f"pub mod {name};\n"
) for name in sorted(descriptors)])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
@@ -8663,6 +8662,7 @@ class GlobalGenRoots():
if base in topTypes:
typeIdCode.append(CGGeneric(f"""
impl {base} {{
+ #[allow(dead_code)]
pub(crate) fn type_id(&self) -> &'static {base}TypeId {{
unsafe {{
&get_dom_class(self.reflector().get_jsobject().get())
@@ -8752,7 +8752,7 @@ impl Clone for TopTypeId {
unions.add(name)
generic = "<crate::DomTypeHolder>" if containsDomInterface(t) else ""
cgthings += [CGGeneric(f"pub(crate) type {name} = "
- f"crate::dom::bindings::codegen::GenericUnionTypes::{name}{generic};\n")]
+ f"script_bindings::codegen::GenericUnionTypes::{name}{generic};\n")]
curr = CGList(cgthings)
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
diff --git a/components/script_bindings/codegen/Configuration.py b/components/script_bindings/codegen/Configuration.py
index a4a6a538fdc..636a70197d2 100644
--- a/components/script_bindings/codegen/Configuration.py
+++ b/components/script_bindings/codegen/Configuration.py
@@ -228,7 +228,7 @@ class Descriptor(DescriptorProvider):
self.nativeType = typeName
pathDefault = 'crate::dom::types::%s' % typeName
elif self.interface.isCallback():
- ty = 'crate::dom::bindings::codegen::GenericBindings::%sBinding::%s' % (ifaceName, ifaceName)
+ ty = 'crate::codegen::GenericBindings::%sBinding::%s' % (ifaceName, ifaceName)
pathDefault = ty
self.returnType = "Rc<%s<D>>" % ty
self.argumentType = "???"
@@ -238,7 +238,7 @@ class Descriptor(DescriptorProvider):
self.argumentType = "&%s%s" % (prefix, typeName)
self.nativeType = "*const %s%s" % (prefix, typeName)
if self.interface.isIteratorInterface():
- pathDefault = 'crate::dom::bindings::iterable::IterableIterator'
+ pathDefault = 'crate::iterable::IterableIterator'
else:
pathDefault = 'crate::dom::types::%s' % MakeNativeName(typeName)
@@ -491,7 +491,7 @@ def getIdlFileName(object):
def getModuleFromObject(object):
- return ('crate::dom::bindings::codegen::GenericBindings::' + getIdlFileName(object) + 'Binding')
+ return ('crate::codegen::GenericBindings::' + getIdlFileName(object) + 'Binding')
def getTypesFromDescriptor(descriptor):
@@ -552,5 +552,5 @@ def iteratorNativeType(descriptor, infer=False):
res = "IterableIterator%s" % ("" if infer else '<D, D::%s>' % descriptor.interface.identifier.name)
# todo: this hack is telling us that something is still wrong in codegen
if iterableDecl.isSetlike() or iterableDecl.isMaplike():
- res = f"crate::dom::bindings::iterable::{res}"
+ res = f"crate::iterable::{res}"
return res
diff --git a/components/script_bindings/constructor.rs b/components/script_bindings/constructor.rs
new file mode 100644
index 00000000000..0fbf1e5a45b
--- /dev/null
+++ b/components/script_bindings/constructor.rs
@@ -0,0 +1,37 @@
+/* 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/. */
+
+use std::ptr;
+
+use js::jsapi::{CallArgs, JSObject};
+use js::rust::HandleObject;
+
+use crate::codegen::PrototypeList;
+use crate::error::throw_constructor_without_new;
+use crate::interface::get_desired_proto;
+use crate::script_runtime::JSContext;
+use crate::utils::ProtoOrIfaceArray;
+
+pub(crate) unsafe fn call_default_constructor<D: crate::DomTypes>(
+ cx: JSContext,
+ args: &CallArgs,
+ global: &D::GlobalScope,
+ proto_id: PrototypeList::ID,
+ ctor_name: &str,
+ creator: unsafe fn(JSContext, HandleObject, *mut ProtoOrIfaceArray),
+ constructor: impl FnOnce(JSContext, &CallArgs, &D::GlobalScope, HandleObject) -> bool,
+) -> bool {
+ if !args.is_constructing() {
+ throw_constructor_without_new(cx, ctor_name);
+ return false;
+ }
+
+ rooted!(in(*cx) let mut desired_proto = ptr::null_mut::<JSObject>());
+ let proto_result = get_desired_proto(cx, args, proto_id, creator, desired_proto.handle_mut());
+ if proto_result.is_err() {
+ return false;
+ }
+
+ constructor(cx, args, global, desired_proto.handle())
+}
diff --git a/components/script_bindings/conversions.rs b/components/script_bindings/conversions.rs
index 847f83fc606..a45da5b4cc4 100644
--- a/components/script_bindings/conversions.rs
+++ b/components/script_bindings/conversions.rs
@@ -13,21 +13,24 @@ use js::glue::{
JS_GetReservedSlot, UnwrapObjectDynamic,
};
use js::jsapi::{
- JS_DeprecatedStringHasLatin1Chars, JS_GetLatin1StringCharsAndLength,
+ Heap, IsWindowProxy, JS_DeprecatedStringHasLatin1Chars, JS_GetLatin1StringCharsAndLength,
JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN, JSContext, JSObject, JSString,
};
use js::jsval::{ObjectValue, StringValue, UndefinedValue};
+use js::rust::wrappers::IsArrayObject;
use js::rust::{
HandleId, HandleValue, MutableHandleValue, ToString, get_object_class, is_dom_class,
is_dom_object, maybe_wrap_value,
};
use num_traits::Float;
+use crate::JSTraceable;
use crate::inheritance::Castable;
use crate::num::Finite;
use crate::reflector::{DomObject, Reflector};
use crate::root::DomRoot;
use crate::str::{ByteString, DOMString, USVString};
+use crate::trace::RootedTraceableBox;
use crate::utils::{DOMClass, DOMJSClass};
/// A trait to check whether a given `JSObject` implements an IDL interface.
@@ -494,3 +497,88 @@ where
}
native_from_object(v.get().to_object(), cx)
}
+
+impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceableBox<T> {
+ #[inline]
+ unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ let value = &**self;
+ value.to_jsval(cx, rval);
+ }
+}
+
+impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>>
+where
+ T: FromJSValConvertible + js::rust::GCMethods + Copy,
+ Heap<T>: JSTraceable + Default,
+{
+ type Config = T::Config;
+
+ unsafe fn from_jsval(
+ cx: *mut JSContext,
+ value: HandleValue,
+ config: Self::Config,
+ ) -> Result<ConversionResult<Self>, ()> {
+ T::from_jsval(cx, value, config).map(|result| match result {
+ ConversionResult::Success(inner) => {
+ ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner)))
+ },
+ ConversionResult::Failure(msg) => ConversionResult::Failure(msg),
+ })
+ }
+}
+
+/// Returns whether `value` is an array-like object (Array, FileList,
+/// HTMLCollection, HTMLFormControlsCollection, HTMLOptionsCollection,
+/// NodeList).
+///
+/// # Safety
+/// `cx` must point to a valid, non-null JSContext.
+pub unsafe fn is_array_like<D: crate::DomTypes>(cx: *mut JSContext, value: HandleValue) -> bool {
+ let mut is_array = false;
+ assert!(IsArrayObject(cx, value, &mut is_array));
+ if is_array {
+ return true;
+ }
+
+ let object: *mut JSObject = match FromJSValConvertible::from_jsval(cx, value, ()).unwrap() {
+ ConversionResult::Success(object) => object,
+ _ => return false,
+ };
+
+ if root_from_object::<D::FileList>(object, cx).is_ok() {
+ return true;
+ }
+ if root_from_object::<D::HTMLCollection>(object, cx).is_ok() {
+ return true;
+ }
+ if root_from_object::<D::HTMLFormControlsCollection>(object, cx).is_ok() {
+ return true;
+ }
+ if root_from_object::<D::HTMLOptionsCollection>(object, cx).is_ok() {
+ return true;
+ }
+ if root_from_object::<D::NodeList>(object, cx).is_ok() {
+ return true;
+ }
+
+ false
+}
+
+/// Get a `DomRoot<T>` for a WindowProxy accessible from a `HandleValue`.
+/// Caller is responsible for throwing a JS exception if needed in case of error.
+pub(crate) unsafe fn windowproxy_from_handlevalue<D: crate::DomTypes>(
+ v: HandleValue,
+ _cx: *mut JSContext,
+) -> Result<DomRoot<D::WindowProxy>, ()> {
+ if !v.get().is_object() {
+ return Err(());
+ }
+ let object = v.get().to_object();
+ if !IsWindowProxy(object) {
+ return Err(());
+ }
+ let mut value = UndefinedValue();
+ GetProxyReservedSlot(object, 0, &mut value);
+ let ptr = value.to_private() as *const D::WindowProxy;
+ Ok(DomRoot::from_ref(&*ptr))
+}
diff --git a/components/script_bindings/finalize.rs b/components/script_bindings/finalize.rs
index fa1079b5624..46fbc83c965 100644
--- a/components/script_bindings/finalize.rs
+++ b/components/script_bindings/finalize.rs
@@ -30,7 +30,7 @@ unsafe fn do_finalize_global(obj: *mut JSObject) {
/// # Safety
/// `this` must point to a valid, non-null instance of T.
-pub unsafe fn finalize_common<T>(this: *const T) {
+pub(crate) unsafe fn finalize_common<T>(this: *const T) {
if !this.is_null() {
// The pointer can be null if the object is the unforgeable holder of that interface.
let _ = Box::from_raw(this as *mut T);
@@ -41,7 +41,7 @@ pub unsafe fn finalize_common<T>(this: *const T) {
/// # Safety
/// `obj` must point to a valid, non-null JS object.
/// `this` must point to a valid, non-null instance of T.
-pub unsafe fn finalize_global<T>(obj: *mut JSObject, this: *const T) {
+pub(crate) unsafe fn finalize_global<T>(obj: *mut JSObject, this: *const T) {
do_finalize_global(obj);
finalize_common::<T>(this);
}
@@ -49,7 +49,7 @@ pub unsafe fn finalize_global<T>(obj: *mut JSObject, this: *const T) {
/// # Safety
/// `obj` must point to a valid, non-null JS object.
/// `this` must point to a valid, non-null instance of T.
-pub unsafe fn finalize_weak_referenceable<T: WeakReferenceable>(
+pub(crate) unsafe fn finalize_weak_referenceable<T: WeakReferenceable>(
obj: *mut JSObject,
this: *const T,
) {
diff --git a/components/script/dom/bindings/guard.rs b/components/script_bindings/guard.rs
index 16b5187abef..68286b48fec 100644
--- a/components/script/dom/bindings/guard.rs
+++ b/components/script_bindings/guard.rs
@@ -5,12 +5,12 @@
//! Machinery to conditionally expose things.
use js::rust::HandleObject;
-use script_bindings::codegen::Globals::Globals;
use servo_config::prefs::get;
use crate::DomTypes;
-use crate::dom::bindings::interface::is_exposed_in;
-use crate::dom::globalscope::GlobalScopeHelpers;
+use crate::codegen::Globals::Globals;
+use crate::interface::is_exposed_in;
+use crate::interfaces::GlobalScopeHelpers;
use crate::realms::{AlreadyInRealm, InRealm};
use crate::script_runtime::JSContext;
diff --git a/components/script_bindings/import.rs b/components/script_bindings/import.rs
new file mode 100644
index 00000000000..65e9ee30e1d
--- /dev/null
+++ b/components/script_bindings/import.rs
@@ -0,0 +1,137 @@
+/* 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/. */
+
+pub(crate) mod base {
+ pub(crate) use std::ptr;
+ pub(crate) use std::rc::Rc;
+
+ pub(crate) use js::conversions::{
+ ConversionBehavior, ConversionResult, FromJSValConvertible, ToJSValConvertible,
+ };
+ pub(crate) use js::error::throw_type_error;
+ pub(crate) use js::jsapi::{
+ CurrentGlobalOrNull, HandleValue as RawHandleValue, HandleValueArray, Heap, IsCallable,
+ JS_NewObject, JSContext, JSObject,
+ };
+ pub(crate) use js::jsval::{JSVal, NullValue, ObjectOrNullValue, ObjectValue, UndefinedValue};
+ pub(crate) use js::panic::maybe_resume_unwind;
+ pub(crate) use js::rust::wrappers::{Call, JS_WrapValue};
+ pub(crate) use js::rust::{HandleObject, HandleValue, MutableHandleObject, MutableHandleValue};
+
+ pub(crate) use crate::callback::{
+ CallSetup, CallbackContainer, CallbackFunction, CallbackInterface, CallbackObject,
+ ExceptionHandling, ThisReflector, wrap_call_this_value,
+ };
+ pub(crate) use crate::codegen::DomTypes::DomTypes;
+ pub(crate) use crate::codegen::GenericUnionTypes;
+ pub(crate) use crate::conversions::{StringificationBehavior, root_from_handlevalue};
+ pub(crate) use crate::error::Error::JSFailed;
+ pub(crate) use crate::error::Fallible;
+ pub(crate) use crate::interfaces::*;
+ pub(crate) use crate::lock::ThreadUnsafeOnceLock;
+ pub(crate) use crate::num::Finite;
+ pub(crate) use crate::proxyhandler::CrossOriginProperties;
+ pub(crate) use crate::reflector::{DomGlobalGeneric, DomObject};
+ pub(crate) use crate::root::DomRoot;
+ pub(crate) use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
+ pub(crate) use crate::str::{ByteString, DOMString, USVString};
+ pub(crate) use crate::trace::RootedTraceableBox;
+ pub(crate) use crate::utils::{get_dictionary_property, set_dictionary_property};
+}
+
+pub(crate) mod module {
+ pub(crate) use std::cmp;
+ pub(crate) use std::ffi::CString;
+ pub(crate) use std::ptr::NonNull;
+
+ pub(crate) use js::conversions::ToJSValConvertible;
+ pub(crate) use js::glue::{
+ CreateProxyHandler, GetProxyReservedSlot, JS_GetReservedSlot, ProxyTraps,
+ SetProxyReservedSlot,
+ };
+ pub(crate) use js::jsapi::{
+ __BindgenBitfieldUnit, CallArgs, GCContext, GetRealmErrorPrototype,
+ GetRealmFunctionPrototype, GetRealmIteratorPrototype, GetRealmObjectPrototype,
+ GetWellKnownSymbol, Handle as RawHandle, HandleId as RawHandleId,
+ HandleObject as RawHandleObject, JS_AtomizeAndPinString, JS_ForwardGetPropertyTo,
+ JS_GetPropertyDescriptorById, JS_HasPropertyById, JS_NewPlainObject, JS_SetReservedSlot,
+ JSAutoRealm, JSCLASS_FOREGROUND_FINALIZE, JSCLASS_RESERVED_SLOTS_SHIFT, JSClass,
+ JSClassOps, JSFunctionSpec, JSITER_HIDDEN, JSITER_OWNONLY, JSITER_SYMBOLS,
+ JSJitGetterCallArgs, JSJitInfo, JSJitInfo__bindgen_ty_1, JSJitInfo__bindgen_ty_2,
+ JSJitInfo__bindgen_ty_3, JSJitInfo_AliasSet, JSJitInfo_ArgType, JSJitInfo_OpType,
+ JSJitMethodCallArgs, JSJitSetterCallArgs, JSNativeWrapper, JSPROP_ENUMERATE,
+ JSPROP_PERMANENT, JSPROP_READONLY, JSPropertySpec, JSPropertySpec_Accessor,
+ JSPropertySpec_AccessorsOrValue, JSPropertySpec_AccessorsOrValue_Accessors,
+ JSPropertySpec_Kind, JSPropertySpec_Name, JSPropertySpec_ValueWrapper,
+ JSPropertySpec_ValueWrapper__bindgen_ty_1, JSPropertySpec_ValueWrapper_Type, JSTracer,
+ JSTypedMethodJitInfo, JSValueType, MutableHandle as RawMutableHandle,
+ MutableHandleIdVector as RawMutableHandleIdVector,
+ MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue,
+ ObjectOpResult, PropertyDescriptor, SymbolCode, UndefinedHandleValue, jsid,
+ };
+ pub(crate) use js::jsval::PrivateValue;
+ pub(crate) use js::panic::wrap_panic;
+ pub(crate) use js::rust::wrappers::{
+ AppendToIdVector, Call, GetPropertyKeys, JS_CopyOwnPropertiesAndPrivateFields,
+ JS_DefineProperty, JS_DefinePropertyById2, JS_GetProperty,
+ JS_InitializePropertiesFromCompatibleNativeObject, JS_NewObjectWithGivenProto,
+ JS_NewObjectWithoutMetadata, JS_SetImmutablePrototype, JS_SetProperty, JS_SetPrototype,
+ JS_WrapObject, NewProxyObject, RUST_INTERNED_STRING_TO_JSID, RUST_SYMBOL_TO_JSID,
+ int_to_jsid,
+ };
+ pub(crate) use js::rust::{
+ CustomAutoRooterGuard, GCMethods, Handle, MutableHandle, get_context_realm,
+ get_object_class, get_object_realm,
+ };
+ pub(crate) use js::typedarray::{
+ ArrayBuffer, ArrayBufferView, Float32Array, Float64Array, Uint8Array, Uint8ClampedArray,
+ };
+ pub(crate) use js::{
+ JS_CALLEE, JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL,
+ JSCLASS_RESERVED_SLOTS_MASK, typedarray,
+ };
+ pub(crate) use servo_config::pref;
+
+ pub(crate) use super::base::*;
+ pub(crate) use crate::codegen::Globals::Globals;
+ pub(crate) use crate::codegen::{PrototypeList, RegisterBindings};
+ pub(crate) use crate::constant::{ConstantSpec, ConstantVal};
+ pub(crate) use crate::constructor::call_default_constructor;
+ pub(crate) use crate::conversions::{
+ DOM_OBJECT_SLOT, StringificationBehavior, is_array_like, jsid_to_string,
+ native_from_handlevalue, native_from_object_static,
+ };
+ pub(crate) use crate::error::{Error, ErrorResult};
+ pub(crate) use crate::finalize::{
+ finalize_common, finalize_global, finalize_weak_referenceable,
+ };
+ pub(crate) use crate::guard::{Condition, Guard};
+ pub(crate) use crate::inheritance::Castable;
+ pub(crate) use crate::interface::{
+ ConstructorClassHook, InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass,
+ ProtoOrIfaceIndex, create_callback_interface_object, create_global_object,
+ create_interface_prototype_object, create_named_constructors,
+ create_noncallback_interface_object, define_dom_interface, define_guarded_methods,
+ define_guarded_properties, get_per_interface_object_handle, is_exposed_in,
+ };
+ pub(crate) use crate::iterable::{Iterable, IterableIterator, IteratorType};
+ pub(crate) use crate::like::{Maplike, Setlike};
+ pub(crate) use crate::mem::malloc_size_of_including_raw_self;
+ pub(crate) use crate::namespace::{NamespaceObjectClass, create_namespace_object};
+ pub(crate) use crate::proxyhandler::{
+ ensure_expando_object, get_expando_object, set_property_descriptor,
+ };
+ pub(crate) use crate::realms::{AlreadyInRealm, InRealm};
+ pub(crate) use crate::root::{Dom, DomSlice, MaybeUnreflectedDom, Root};
+ pub(crate) use crate::script_runtime::CanGc;
+ pub(crate) use crate::utils::{
+ AsVoidPtr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, DOMClass, DOMJSClass, JSCLASS_DOM_GLOBAL,
+ ProtoOrIfaceArray, enumerate_global, exception_to_promise, generic_getter,
+ generic_lenient_getter, generic_lenient_setter, generic_method, generic_setter,
+ generic_static_promise_method, get_array_index_from_id, get_property_on_prototype,
+ has_property_on_prototype, resolve_global, trace_global,
+ };
+ pub(crate) use crate::weakref::DOM_WEAK_SLOT;
+ pub(crate) use crate::{JSTraceable, proxyhandler};
+}
diff --git a/components/script/dom/bindings/interface.rs b/components/script_bindings/interface.rs
index d1c191be3a4..08ee0a4f420 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script_bindings/interface.rs
@@ -32,19 +32,19 @@ use js::rust::{
HandleObject, HandleValue, MutableHandleObject, RealmOptions, define_methods,
define_properties, get_object_class, is_dom_class, maybe_wrap_object,
};
-use script_bindings::constant::{ConstantSpec, define_constants};
use servo_url::MutableOrigin;
use crate::DomTypes;
-use crate::dom::bindings::codegen::InterfaceObjectMap::Globals;
-use crate::dom::bindings::codegen::PrototypeList;
-use crate::dom::bindings::conversions::{DOM_OBJECT_SLOT, get_dom_class};
-use crate::dom::bindings::guard::Guard;
-use crate::dom::bindings::principals::ServoJSPrincipals;
-use crate::dom::bindings::utils::{
+use crate::codegen::Globals::Globals;
+use crate::codegen::PrototypeList;
+use crate::constant::{ConstantSpec, define_constants};
+use crate::conversions::{DOM_OBJECT_SLOT, get_dom_class};
+use crate::guard::Guard;
+use crate::principals::ServoJSPrincipals;
+use crate::script_runtime::JSContext as SafeJSContext;
+use crate::utils::{
DOM_PROTOTYPE_SLOT, DOMJSClass, JSCLASS_DOM_GLOBAL, ProtoOrIfaceArray, get_proto_or_iface_array,
};
-use crate::script_runtime::JSContext as SafeJSContext;
/// The class of a non-callback interface object.
#[derive(Clone, Copy)]
@@ -599,7 +599,8 @@ fn get_proto_id_for_new_target(new_target: HandleObject) -> Option<PrototypeList
}
}
-pub(crate) fn get_desired_proto(
+#[allow(clippy::result_unit_err)]
+pub fn get_desired_proto(
cx: SafeJSContext,
args: &CallArgs,
proto_id: PrototypeList::ID,
diff --git a/components/script_bindings/interfaces.rs b/components/script_bindings/interfaces.rs
index ce8fc71f23b..12b95b8eb4c 100644
--- a/components/script_bindings/interfaces.rs
+++ b/components/script_bindings/interfaces.rs
@@ -2,14 +2,103 @@
* 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 std::cell::RefCell;
+use std::rc::Rc;
+use std::thread::LocalKey;
+
+use js::conversions::ToJSValConvertible;
+use js::glue::JSPrincipalsCallbacks;
+use js::jsapi::{CallArgs, HandleObject as RawHandleObject, JSContext as RawJSContext, JSObject};
use js::rust::{HandleObject, MutableHandleObject};
+use servo_url::{MutableOrigin, ServoUrl};
+
+use crate::DomTypes;
+use crate::codegen::PrototypeList;
+use crate::conversions::DerivedFrom;
+use crate::error::Error;
+use crate::realms::InRealm;
+use crate::reflector::{DomObject, DomObjectWrap};
+use crate::root::DomRoot;
+use crate::script_runtime::{CanGc, JSContext};
+use crate::settings_stack::StackEntry;
+use crate::utils::ProtoOrIfaceArray;
+
+/// Operations that must be invoked from the generated bindings.
+pub trait DomHelpers<D: DomTypes> {
+ fn throw_dom_exception(cx: JSContext, global: &D::GlobalScope, result: Error, can_gc: CanGc);
+
+ fn call_html_constructor<T: DerivedFrom<D::Element> + DomObject>(
+ cx: JSContext,
+ args: &CallArgs,
+ global: &D::GlobalScope,
+ proto_id: PrototypeList::ID,
+ creator: unsafe fn(JSContext, HandleObject, *mut ProtoOrIfaceArray),
+ can_gc: CanGc,
+ ) -> bool;
+
+ fn settings_stack() -> &'static LocalKey<RefCell<Vec<StackEntry<D>>>>;
-use crate::script_runtime::JSContext;
+ fn principals_callbacks() -> &'static JSPrincipalsCallbacks;
+
+ fn is_platform_object_same_origin(cx: JSContext, obj: RawHandleObject) -> bool;
+
+ fn interface_map() -> &'static phf::Map<&'static [u8], for<'a> fn(JSContext, 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: JSContext, dispatch_event: bool, realm: InRealm, can_gc: CanGc);
+}
+
+/// Operations that must be invoked from the generated bindings.
+#[allow(unsafe_code)]
+pub trait GlobalScopeHelpers<D: DomTypes> {
+ /// # Safety
+ /// `cx` must point to a valid, non-null RawJSContext.
+ unsafe fn from_context(cx: *mut RawJSContext, realm: InRealm) -> DomRoot<D::GlobalScope>;
+ fn get_cx() -> JSContext;
+ /// # Safety
+ /// `obj` must point to a valid, non-null JSObject.
+ unsafe fn from_object(obj: *mut JSObject) -> DomRoot<D::GlobalScope>;
+ fn from_reflector(reflector: &impl DomObject, realm: InRealm) -> DomRoot<D::GlobalScope>;
+
+ /// # Safety
+ /// `obj` must point to a valid, non-null JSObject.
+ /// `cx` must point to a valid, non-null RawJSContext.
+ unsafe fn from_object_maybe_wrapped(
+ obj: *mut JSObject,
+ cx: *mut RawJSContext,
+ ) -> DomRoot<D::GlobalScope>;
+
+ fn origin(&self) -> &MutableOrigin;
+
+ fn incumbent() -> Option<DomRoot<D::GlobalScope>>;
+
+ fn perform_a_microtask_checkpoint(&self, can_gc: CanGc);
+
+ fn get_url(&self) -> ServoUrl;
+
+ fn is_secure_context(&self) -> bool;
+}
pub trait DocumentHelpers {
fn ensure_safe_to_run_script_or_layout(&self);
}
+/// Operations that must be invoked from the generated bindings.
+pub trait PromiseHelpers<D: crate::DomTypes> {
+ fn new_resolved(
+ global: &D::GlobalScope,
+ cx: JSContext,
+ value: impl ToJSValConvertible,
+ ) -> Rc<D::Promise>;
+}
+
pub trait ServoInternalsHelpers {
fn is_servo_internal(cx: JSContext, global: HandleObject) -> bool;
}
diff --git a/components/script_bindings/iterable.rs b/components/script_bindings/iterable.rs
index 61cd4540bae..03efd8a4856 100644
--- a/components/script_bindings/iterable.rs
+++ b/components/script_bindings/iterable.rs
@@ -2,13 +2,36 @@
* 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/. */
+//! Implementation of `iterable<...>` and `iterable<..., ...>` WebIDL declarations.
+
+use std::cell::Cell;
+use std::marker::PhantomData;
+use std::ptr;
+use std::ptr::NonNull;
+
+use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
+use js::jsapi::{Heap, JSObject};
+use js::jsval::UndefinedValue;
+use js::rust::{HandleObject, HandleValue, MutableHandleObject};
+use crate::codegen::GenericBindings::IterableIteratorBinding::{
+ IterableKeyAndValueResult, IterableKeyOrValueResult,
+};
+use crate::conversions::IDLInterface;
+use crate::error::Fallible;
+use crate::interfaces::DomHelpers;
+use crate::realms::InRealm;
+use crate::reflector::{DomGlobalGeneric, DomObjectIteratorWrap, DomObjectWrap, Reflector};
+use crate::root::{Dom, DomRoot, Root};
+use crate::script_runtime::{CanGc, JSContext};
+use crate::trace::{NoTrace, RootedTraceableBox};
use crate::utils::DOMClass;
+use crate::{DomTypes, JSTraceable};
/// The values that an iterator will iterate over.
#[derive(JSTraceable, MallocSizeOf)]
-pub enum IteratorType {
+pub(crate) enum IteratorType {
/// The keys of the iterable object.
Keys,
/// The values of the iterable object.
@@ -38,3 +61,148 @@ pub trait Iterable {
pub trait IteratorDerives {
fn derives(class: &'static DOMClass) -> bool;
}
+
+/// An iterator over the iterable entries of a given DOM interface.
+#[dom_struct]
+pub struct IterableIterator<
+ D: DomTypes,
+ T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>,
+> {
+ reflector: Reflector,
+ iterable: Dom<T>,
+ type_: IteratorType,
+ index: Cell<u32>,
+ _marker: NoTrace<PhantomData<D>>,
+}
+
+impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable> IterableIterator<D, T> {
+ pub fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope> {
+ <Self as DomGlobalGeneric<D>>::global_(self, realm)
+ }
+}
+
+impl<
+ D: DomTypes,
+ T: DomObjectIteratorWrap<D>
+ + JSTraceable
+ + Iterable
+ + DomGlobalGeneric<D>
+ + IDLInterface
+ + IteratorDerives,
+> IDLInterface for IterableIterator<D, T>
+{
+ fn derives(class: &'static DOMClass) -> bool {
+ <T as IteratorDerives>::derives(class)
+ }
+}
+
+impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>>
+ IterableIterator<D, T>
+{
+ /// Create a new iterator instance for the provided iterable DOM interface.
+ pub(crate) fn new(iterable: &T, type_: IteratorType, realm: InRealm) -> DomRoot<Self> {
+ let iterator = Box::new(IterableIterator {
+ reflector: Reflector::new(),
+ type_,
+ iterable: Dom::from_ref(iterable),
+ index: Cell::new(0),
+ _marker: NoTrace(PhantomData),
+ });
+ <D as DomHelpers<D>>::reflect_dom_object(iterator, &*iterable.global_(realm), CanGc::note())
+ }
+
+ /// Return the next value from the iterable object.
+ #[allow(non_snake_case)]
+ pub fn Next(&self, cx: JSContext) -> Fallible<NonNull<JSObject>> {
+ let index = self.index.get();
+ rooted!(in(*cx) let mut value = UndefinedValue());
+ rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
+ let result = if index >= self.iterable.get_iterable_length() {
+ dict_return(cx, rval.handle_mut(), true, value.handle())
+ } else {
+ match self.type_ {
+ IteratorType::Keys => {
+ unsafe {
+ self.iterable
+ .get_key_at_index(index)
+ .to_jsval(*cx, value.handle_mut());
+ }
+ dict_return(cx, rval.handle_mut(), false, value.handle())
+ },
+ IteratorType::Values => {
+ unsafe {
+ self.iterable
+ .get_value_at_index(index)
+ .to_jsval(*cx, value.handle_mut());
+ }
+ dict_return(cx, rval.handle_mut(), false, value.handle())
+ },
+ IteratorType::Entries => {
+ rooted!(in(*cx) let mut key = UndefinedValue());
+ unsafe {
+ self.iterable
+ .get_key_at_index(index)
+ .to_jsval(*cx, key.handle_mut());
+ self.iterable
+ .get_value_at_index(index)
+ .to_jsval(*cx, value.handle_mut());
+ }
+ key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle())
+ },
+ }
+ };
+ self.index.set(index + 1);
+ result.map(|_| NonNull::new(rval.get()).expect("got a null pointer"))
+ }
+}
+
+impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>>
+ DomObjectWrap<D> for IterableIterator<D, T>
+{
+ const WRAP: unsafe fn(
+ JSContext,
+ &D::GlobalScope,
+ Option<HandleObject>,
+ Box<Self>,
+ CanGc,
+ ) -> Root<Dom<Self>> = T::ITER_WRAP;
+}
+
+fn dict_return(
+ cx: JSContext,
+ mut result: MutableHandleObject,
+ done: bool,
+ value: HandleValue,
+) -> Fallible<()> {
+ let mut dict = IterableKeyOrValueResult::empty();
+ dict.done = done;
+ dict.value.set(value.get());
+ rooted!(in(*cx) let mut dict_value = UndefinedValue());
+ unsafe {
+ dict.to_jsval(*cx, dict_value.handle_mut());
+ }
+ result.set(dict_value.to_object());
+ Ok(())
+}
+
+fn key_and_value_return(
+ cx: JSContext,
+ mut result: MutableHandleObject,
+ key: HandleValue,
+ value: HandleValue,
+) -> Fallible<()> {
+ let mut dict = IterableKeyAndValueResult::empty();
+ dict.done = false;
+ dict.value = Some(
+ vec![key, value]
+ .into_iter()
+ .map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
+ .collect(),
+ );
+ rooted!(in(*cx) let mut dict_value = UndefinedValue());
+ unsafe {
+ dict.to_jsval(*cx, dict_value.handle_mut());
+ }
+ result.set(dict_value.to_object());
+ Ok(())
+}
diff --git a/components/script_bindings/lib.rs b/components/script_bindings/lib.rs
index 0ecad1ca07c..83dc9fbd1c8 100644
--- a/components/script_bindings/lib.rs
+++ b/components/script_bindings/lib.rs
@@ -11,6 +11,8 @@
#![deny(crown_is_not_used)]
#[macro_use]
+extern crate js;
+#[macro_use]
extern crate jstraceable_derive;
#[macro_use]
extern crate log;
@@ -18,21 +20,30 @@ extern crate log;
extern crate malloc_size_of_derive;
pub mod callback;
-pub mod constant;
+mod constant;
+mod constructor;
pub mod conversions;
pub mod error;
-pub mod finalize;
+mod finalize;
+mod guard;
+mod import;
pub mod inheritance;
+pub mod interface;
pub mod interfaces;
pub mod iterable;
pub mod like;
-pub mod lock;
+mod lock;
+mod mem;
+mod namespace;
pub mod num;
+pub mod principals;
pub mod proxyhandler;
+pub mod realms;
pub mod record;
pub mod reflector;
pub mod root;
pub mod script_runtime;
+pub mod settings_stack;
pub mod str;
pub mod trace;
pub mod utils;
@@ -51,6 +62,32 @@ pub mod codegen {
pub mod PrototypeList {
include!(concat!(env!("OUT_DIR"), "/PrototypeList.rs"));
}
+ pub(crate) mod DomTypes {
+ include!(concat!(env!("OUT_DIR"), "/DomTypes.rs"));
+ }
+ #[allow(
+ dead_code,
+ clippy::extra_unused_type_parameters,
+ clippy::missing_safety_doc,
+ clippy::result_unit_err
+ )]
+ pub mod GenericBindings {
+ include!(concat!(env!("OUT_DIR"), "/Bindings/mod.rs"));
+ }
+ #[allow(
+ non_camel_case_types,
+ unused_imports,
+ unused_variables,
+ clippy::large_enum_variant,
+ clippy::upper_case_acronyms,
+ clippy::enum_variant_names
+ )]
+ pub mod GenericUnionTypes {
+ include!(concat!(env!("OUT_DIR"), "/GenericUnionTypes.rs"));
+ }
+ pub mod RegisterBindings {
+ include!(concat!(env!("OUT_DIR"), "/RegisterBindings.rs"));
+ }
}
// These trait exports are public, because they are used in the DOM bindings.
@@ -58,4 +95,6 @@ pub mod codegen {
// it is useful that they are accessible at the root of the crate.
pub(crate) use js::gc::Traceable as JSTraceable;
+pub use crate::codegen::DomTypes::DomTypes;
+pub(crate) use crate::reflector::{DomObject, MutDomObject, Reflector};
pub(crate) use crate::trace::CustomTraceable;
diff --git a/components/script/mem.rs b/components/script_bindings/mem.rs
index 52a6e724b22..52a6e724b22 100644
--- a/components/script/mem.rs
+++ b/components/script_bindings/mem.rs
diff --git a/components/script/dom/bindings/namespace.rs b/components/script_bindings/namespace.rs
index ad0a5801519..1ed5e06915b 100644
--- a/components/script/dom/bindings/namespace.rs
+++ b/components/script_bindings/namespace.rs
@@ -9,11 +9,11 @@ use std::ptr;
use js::jsapi::{JSClass, JSFunctionSpec};
use js::rust::{HandleObject, MutableHandleObject};
-use script_bindings::constant::ConstantSpec;
use crate::DomTypes;
-use crate::dom::bindings::guard::Guard;
-use crate::dom::bindings::interface::{create_object, define_on_global_object};
+use crate::constant::ConstantSpec;
+use crate::guard::Guard;
+use crate::interface::{create_object, define_on_global_object};
use crate::script_runtime::JSContext;
/// The class of a namespace object.
diff --git a/components/script_bindings/principals.rs b/components/script_bindings/principals.rs
new file mode 100644
index 00000000000..6b30f71fb7e
--- /dev/null
+++ b/components/script_bindings/principals.rs
@@ -0,0 +1,128 @@
+/* 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/. */
+
+use std::marker::PhantomData;
+use std::mem::ManuallyDrop;
+use std::ops::Deref;
+use std::ptr::NonNull;
+
+use js::glue::{CreateRustJSPrincipals, GetRustJSPrincipalsPrivate};
+use js::jsapi::{JS_DropPrincipals, JS_HoldPrincipals, JSPrincipals};
+use js::rust::Runtime;
+use servo_url::MutableOrigin;
+
+use crate::DomTypes;
+use crate::interfaces::DomHelpers;
+
+/// An owned reference to Servo's `JSPrincipals` instance.
+#[repr(transparent)]
+pub struct ServoJSPrincipals(NonNull<JSPrincipals>);
+
+impl ServoJSPrincipals {
+ pub fn new<D: DomTypes>(origin: &MutableOrigin) -> Self {
+ unsafe {
+ let private: Box<MutableOrigin> = Box::new(origin.clone());
+ 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))
+ }
+ }
+
+ /// Construct `Self` from a raw `*mut JSPrincipals`, incrementing its
+ /// reference count.
+ ///
+ /// # Safety
+ /// `raw` must point to a valid JSPrincipals value.
+ #[inline]
+ pub unsafe fn from_raw_nonnull(raw: NonNull<JSPrincipals>) -> Self {
+ JS_HoldPrincipals(raw.as_ptr());
+ Self(raw)
+ }
+
+ #[inline]
+ pub fn origin(&self) -> MutableOrigin {
+ unsafe {
+ let origin = GetRustJSPrincipalsPrivate(self.0.as_ptr()) as *mut MutableOrigin;
+ (*origin).clone()
+ }
+ }
+
+ #[inline]
+ pub fn as_raw_nonnull(&self) -> NonNull<JSPrincipals> {
+ self.0
+ }
+
+ #[inline]
+ pub fn as_raw(&self) -> *mut JSPrincipals {
+ self.0.as_ptr()
+ }
+}
+
+impl Clone for ServoJSPrincipals {
+ #[inline]
+ fn clone(&self) -> Self {
+ unsafe { Self::from_raw_nonnull(self.as_raw_nonnull()) }
+ }
+}
+
+impl Drop for ServoJSPrincipals {
+ #[inline]
+ fn drop(&mut self) {
+ if let Some(cx) = Runtime::get() {
+ unsafe { JS_DropPrincipals(cx.as_ptr(), self.as_raw()) };
+ }
+ }
+}
+
+/// A borrowed reference to Servo's `JSPrincipals` instance. Does not update the
+/// reference count on creation and deletion.
+pub struct ServoJSPrincipalsRef<'a>(ManuallyDrop<ServoJSPrincipals>, PhantomData<&'a ()>);
+
+impl ServoJSPrincipalsRef<'_> {
+ /// Construct `Self` from a raw `NonNull<JSPrincipals>`.
+ ///
+ /// # Safety
+ ///
+ /// `ServoJSPrincipalsRef` does not update the reference count of the
+ /// wrapped `JSPrincipals` object. It's up to the caller to ensure the
+ /// returned `ServoJSPrincipalsRef` object or any clones are not used past
+ /// the lifetime of the wrapped object.
+ #[inline]
+ pub unsafe fn from_raw_nonnull(raw: NonNull<JSPrincipals>) -> Self {
+ // Don't use `ServoJSPrincipals::from_raw_nonnull`; we don't want to
+ // update the reference count
+ Self(ManuallyDrop::new(ServoJSPrincipals(raw)), PhantomData)
+ }
+
+ /// Construct `Self` from a raw `*mut JSPrincipals`.
+ ///
+ /// # Safety
+ ///
+ /// The behavior is undefined if `raw` is null. See also
+ /// [`Self::from_raw_nonnull`].
+ #[inline]
+ pub unsafe fn from_raw_unchecked(raw: *mut JSPrincipals) -> Self {
+ Self::from_raw_nonnull(NonNull::new_unchecked(raw))
+ }
+}
+
+impl Clone for ServoJSPrincipalsRef<'_> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self(ManuallyDrop::new(ServoJSPrincipals(self.0.0)), PhantomData)
+ }
+}
+
+impl Deref for ServoJSPrincipalsRef<'_> {
+ type Target = ServoJSPrincipals;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
diff --git a/components/script_bindings/proxyhandler.rs b/components/script_bindings/proxyhandler.rs
index 7614479ac59..e075e669b0a 100644
--- a/components/script_bindings/proxyhandler.rs
+++ b/components/script_bindings/proxyhandler.rs
@@ -8,15 +8,20 @@ use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr;
-use js::glue::{GetProxyHandlerFamily, GetProxyPrivate, SetProxyPrivate};
+use js::conversions::ToJSValConvertible;
+use js::glue::{
+ GetProxyHandler, GetProxyHandlerFamily, GetProxyPrivate, InvokeGetOwnPropertyDescriptor,
+ 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,
+ 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,
- MutableHandleObject as RawMutableHandleObject, ObjectOpResult, PropertyDescriptor,
- SetDOMProxyInformation, SymbolCode, jsid,
+ MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue,
+ ObjectOpResult, PropertyDescriptor, SetDOMProxyInformation, SymbolCode, jsid,
};
use js::jsid::SymbolId;
use js::jsval::{ObjectValue, UndefinedValue};
@@ -27,8 +32,13 @@ use js::rust::wrappers::{
use js::rust::{Handle, HandleObject, HandleValue, MutableHandle, MutableHandleObject};
use js::{jsapi, rooted};
+use crate::DomTypes;
use crate::conversions::{is_dom_proxy, jsid_to_string, jsstring_to_str};
-use crate::script_runtime::JSContext as SafeJSContext;
+use crate::error::Error;
+use crate::interfaces::{DomHelpers, GlobalScopeHelpers};
+use crate::realms::{AlreadyInRealm, InRealm};
+use crate::reflector::DomObject;
+use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
use crate::str::DOMString;
use crate::utils::delete_property_by_id;
@@ -36,7 +46,7 @@ use crate::utils::delete_property_by_id;
///
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
-pub unsafe extern "C" fn shadow_check_callback(
+pub(crate) unsafe extern "C" fn shadow_check_callback(
cx: *mut JSContext,
object: RawHandleObject,
id: RawHandleId,
@@ -78,7 +88,7 @@ pub fn init() {
/// # 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(
+pub(crate) unsafe extern "C" fn define_property(
cx: *mut JSContext,
proxy: RawHandleObject,
id: RawHandleId,
@@ -95,7 +105,7 @@ pub unsafe extern "C" fn define_property(
/// # 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(
+pub(crate) unsafe extern "C" fn delete(
cx: *mut JSContext,
proxy: RawHandleObject,
id: RawHandleId,
@@ -115,7 +125,7 @@ pub unsafe extern "C" fn delete(
///
/// # Safety
/// `result` must point to a valid, non-null ObjectOpResult.
-pub unsafe extern "C" fn prevent_extensions(
+pub(crate) unsafe extern "C" fn prevent_extensions(
_cx: *mut JSContext,
_proxy: RawHandleObject,
result: *mut ObjectOpResult,
@@ -128,7 +138,7 @@ pub unsafe extern "C" fn prevent_extensions(
///
/// # Safety
/// `succeeded` must point to a valid, non-null bool.
-pub unsafe extern "C" fn is_extensible(
+pub(crate) unsafe extern "C" fn is_extensible(
_cx: *mut JSContext,
_proxy: RawHandleObject,
succeeded: *mut bool,
@@ -149,7 +159,7 @@ pub unsafe extern "C" fn is_extensible(
///
/// # Safety
/// `is_ordinary` must point to a valid, non-null bool.
-pub unsafe extern "C" fn get_prototype_if_ordinary(
+pub(crate) unsafe extern "C" fn get_prototype_if_ordinary(
_: *mut JSContext,
proxy: RawHandleObject,
is_ordinary: *mut bool,
@@ -161,7 +171,7 @@ pub unsafe extern "C" fn get_prototype_if_ordinary(
}
/// Get the expando object, or null if there is none.
-pub fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandleObject) {
+pub(crate) fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandleObject) {
unsafe {
assert!(is_dom_proxy(obj.get()));
let val = &mut UndefinedValue();
@@ -179,7 +189,7 @@ pub fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandleObject
///
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
-pub unsafe fn ensure_expando_object(
+pub(crate) unsafe fn ensure_expando_object(
cx: *mut JSContext,
obj: RawHandleObject,
mut expando: MutableHandleObject,
@@ -212,7 +222,7 @@ pub fn set_property_descriptor(
*is_none = false;
}
-pub fn id_to_source(cx: SafeJSContext, id: RawHandleId) -> Option<DOMString> {
+pub(crate) 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>());
@@ -230,9 +240,9 @@ pub fn id_to_source(cx: SafeJSContext, id: RawHandleId) -> Option<DOMString> {
/// [`CrossOriginProperties(O)`].
///
/// [`CrossOriginProperties(O)`]: https://html.spec.whatwg.org/multipage/#crossoriginproperties-(-o-)
-pub struct CrossOriginProperties {
- pub attributes: &'static [JSPropertySpec],
- pub methods: &'static [JSFunctionSpec],
+pub(crate) struct CrossOriginProperties {
+ pub(crate) attributes: &'static [JSPropertySpec],
+ pub(crate) methods: &'static [JSFunctionSpec],
}
impl CrossOriginProperties {
@@ -250,7 +260,7 @@ impl CrossOriginProperties {
/// Implementation of [`CrossOriginOwnPropertyKeys`].
///
/// [`CrossOriginOwnPropertyKeys`]: https://html.spec.whatwg.org/multipage/#crossoriginownpropertykeys-(-o-)
-pub fn cross_origin_own_property_keys(
+pub(crate) fn cross_origin_own_property_keys(
cx: SafeJSContext,
_proxy: RawHandleObject,
cross_origin_properties: &'static CrossOriginProperties,
@@ -276,7 +286,7 @@ pub fn cross_origin_own_property_keys(
/// # Safety
/// `is_ordinary` must point to a valid, non-null bool.
-pub unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
+pub(crate) unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
_: *mut JSContext,
_proxy: RawHandleObject,
is_ordinary: *mut bool,
@@ -294,7 +304,7 @@ pub unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
///
/// # Safety
/// `result` must point to a valid, non-null ObjectOpResult.
-pub unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
+pub(crate) unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
cx: *mut JSContext,
proxy: RawHandleObject,
proto: RawHandleObject,
@@ -323,25 +333,25 @@ pub unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
true
}
-pub fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
+pub(crate) fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
if d.hasGetter_() {
out.set(d.getter_);
}
}
-pub fn get_setter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
+pub(crate) 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 {
+pub(crate) 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 {
+pub(crate) fn is_data_descriptor(d: &PropertyDescriptor) -> bool {
d.hasWritable_() || d.hasValue_()
}
@@ -353,7 +363,7 @@ pub fn is_data_descriptor(d: &PropertyDescriptor) -> bool {
///
/// # Safety
/// `bp` must point to a valid, non-null bool.
-pub unsafe fn cross_origin_has_own(
+pub(crate) unsafe fn cross_origin_has_own(
cx: SafeJSContext,
_proxy: RawHandleObject,
cross_origin_properties: &'static CrossOriginProperties,
@@ -379,7 +389,7 @@ pub unsafe fn cross_origin_has_own(
/// for a maybe-cross-origin object.
///
/// [`CrossOriginGetOwnPropertyHelper`]: https://html.spec.whatwg.org/multipage/#crossorigingetownpropertyhelper-(-o,-p-)
-pub fn cross_origin_get_own_property_helper(
+pub(crate) fn cross_origin_get_own_property_helper(
cx: SafeJSContext,
proxy: RawHandleObject,
cross_origin_properties: &'static CrossOriginProperties,
@@ -405,7 +415,7 @@ const ALLOWLISTED_SYMBOL_CODES: &[SymbolCode] = &[
SymbolCode::isConcatSpreadable,
];
-pub fn is_cross_origin_allowlisted_prop(cx: SafeJSContext, id: RawHandleId) -> bool {
+pub(crate) 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;
@@ -492,3 +502,269 @@ fn ensure_cross_origin_property_holder(
true
}
+
+/// Report a cross-origin denial for a property, Always returns `false`, so it
+/// can be used as `return report_cross_origin_denial(...);`.
+///
+/// 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<D: DomTypes>(
+ cx: SafeJSContext,
+ id: RawHandleId,
+ access: &str,
+) -> bool {
+ debug!(
+ "permission denied to {} property {} on cross-origin object",
+ access,
+ id_to_source(cx, id).as_deref().unwrap_or("< error >"),
+ );
+ let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
+ if !JS_IsExceptionPending(*cx) {
+ let global = D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
+ // TODO: include `id` and `access` in the exception message
+ <D as DomHelpers<D>>::throw_dom_exception(cx, &global, Error::Security, CanGc::note());
+ }
+ false
+}
+
+/// 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<D: DomTypes>(
+ cx: *mut JSContext,
+ proxy: RawHandleObject,
+ id: RawHandleId,
+ v: RawHandleValue,
+ receiver: RawHandleValue,
+ result: *mut ObjectOpResult,
+) -> bool {
+ let cx = SafeJSContext::from_ptr(cx);
+
+ 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.
+ let _ac = JSAutoRealm::new(*cx, proxy.get());
+
+ // OrdinarySet
+ // <https://tc39.es/ecma262/#sec-ordinaryset>
+ rooted!(in(*cx) let mut own_desc = PropertyDescriptor::default());
+ let mut is_none = false;
+ if !InvokeGetOwnPropertyDescriptor(
+ GetProxyHandler(*proxy),
+ *cx,
+ proxy,
+ id,
+ own_desc.handle_mut().into(),
+ &mut is_none,
+ ) {
+ return false;
+ }
+
+ js::jsapi::SetPropertyIgnoringNamedGetter(
+ *cx,
+ proxy,
+ id,
+ v,
+ receiver,
+ own_desc.handle().into(),
+ result,
+ )
+}
+
+/// Implementation of `[[GetPrototypeOf]]` for [`Location`].
+///
+/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-getprototypeof
+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),
+ proto: RawMutableHandleObject,
+) -> bool {
+ // > 1. If ! IsPlatformObjectSameOrigin(this) is true, then return ! OrdinaryGetPrototypeOf(this).
+ if <D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) {
+ let ac = JSAutoRealm::new(*cx, proxy.get());
+ let global = D::GlobalScope::from_context(*cx, InRealm::Entered(&ac));
+ get_proto_object(
+ cx,
+ global.reflector().get_jsobject(),
+ MutableHandleObject::from_raw(proto),
+ );
+ return !proto.is_null();
+ }
+
+ // > 2. Return null.
+ proto.set(ptr::null_mut());
+ 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<D: DomTypes>(
+ cx: SafeJSContext,
+ proxy: RawHandleObject,
+ receiver: RawHandleValue,
+ id: RawHandleId,
+ vp: RawMutableHandleValue,
+) -> bool {
+ // > 1. Let `desc` be `? O.[[GetOwnProperty]](P)`.
+ rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default());
+ let mut is_none = false;
+ if !InvokeGetOwnPropertyDescriptor(
+ GetProxyHandler(*proxy),
+ *cx,
+ proxy,
+ id,
+ descriptor.handle_mut().into(),
+ &mut is_none,
+ ) {
+ return false;
+ }
+
+ // > 2. Assert: `desc` is not undefined.
+ assert!(
+ !is_none,
+ "Callees should throw in all cases when they are not finding \
+ a property decriptor"
+ );
+
+ // > 3. If `! IsDataDescriptor(desc)` is true, then return `desc.[[Value]]`.
+ if is_data_descriptor(&descriptor) {
+ vp.set(descriptor.value_);
+ return true;
+ }
+
+ // > 4. Assert: `IsAccessorDescriptor(desc)` is `true`.
+ assert!(is_accessor_descriptor(&descriptor));
+
+ // > 5. Let `getter` be `desc.[[Get]]`.
+ // >
+ // > 6. If `getter` is `undefined`, then throw a `SecurityError`
+ // > `DOMException`.
+ 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::<D>(cx, id, "get");
+ }
+
+ rooted!(in(*cx) let mut getter_jsval = UndefinedValue());
+ getter.get().to_jsval(*cx, getter_jsval.handle_mut());
+
+ // > 7. Return `? Call(getter, Receiver)`.
+ jsapi::Call(
+ *cx,
+ receiver,
+ getter_jsval.handle().into(),
+ &jsapi::HandleValueArray::empty(),
+ vp,
+ )
+}
+
+/// Implementation of [`CrossOriginSet`].
+///
+/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy
+/// 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<D: DomTypes>(
+ cx: SafeJSContext,
+ proxy: RawHandleObject,
+ id: RawHandleId,
+ v: RawHandleValue,
+ receiver: RawHandleValue,
+ result: *mut ObjectOpResult,
+) -> bool {
+ // > 1. Let desc be ? O.[[GetOwnProperty]](P).
+ rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default());
+ let mut is_none = false;
+ if !InvokeGetOwnPropertyDescriptor(
+ GetProxyHandler(*proxy),
+ *cx,
+ proxy,
+ id,
+ descriptor.handle_mut().into(),
+ &mut is_none,
+ ) {
+ return false;
+ }
+
+ // > 2. Assert: desc is not undefined.
+ assert!(
+ !is_none,
+ "Callees should throw in all cases when they are not finding \
+ a property decriptor"
+ );
+
+ // > 3. If desc.[[Set]] is present and its value is not undefined,
+ // > then: [...]
+ rooted!(in(*cx) let mut setter = ptr::null_mut::<JSObject>());
+ get_setter_object(&descriptor, setter.handle_mut().into());
+ if setter.get().is_null() {
+ // > 4. Throw a "SecurityError" DOMException.
+ return report_cross_origin_denial::<D>(cx, id, "set");
+ }
+
+ rooted!(in(*cx) let mut setter_jsval = UndefinedValue());
+ setter.get().to_jsval(*cx, setter_jsval.handle_mut());
+
+ // > 3.1. Perform ? Call(setter, Receiver, «V»).
+ // >
+ // > 3.2. Return true.
+ rooted!(in(*cx) let mut ignored = UndefinedValue());
+ if !jsapi::Call(
+ *cx,
+ receiver,
+ setter_jsval.handle().into(),
+ // FIXME: Our binding lacks `HandleValueArray(Handle<Value>)`
+ // <https://searchfox.org/mozilla-central/rev/072710086ddfe25aa2962c8399fefb2304e8193b/js/public/ValueArray.h#54-55>
+ &jsapi::HandleValueArray {
+ length_: 1,
+ elements_: v.ptr,
+ },
+ ignored.handle_mut().into(),
+ ) {
+ return false;
+ }
+
+ (*result).code_ = 0 /* OkCode */;
+ true
+}
+
+/// 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<D: DomTypes>(
+ cx: SafeJSContext,
+ _proxy: RawHandleObject,
+ id: RawHandleId,
+ desc: RawMutableHandle<PropertyDescriptor>,
+ is_none: &mut bool,
+) -> bool {
+ assert!(*is_none, "why are we being called?");
+
+ // > 1. If P is `then`, `@@toStringTag`, `@@hasInstance`, or
+ // > `@@isConcatSpreadable`, then return `PropertyDescriptor{ [[Value]]:
+ // > undefined, [[Writable]]: false, [[Enumerable]]: false,
+ // > [[Configurable]]: true }`.
+ if is_cross_origin_allowlisted_prop(cx, id) {
+ set_property_descriptor(
+ MutableHandle::from_raw(desc),
+ HandleValue::undefined(),
+ jsapi::JSPROP_READONLY as u32,
+ is_none,
+ );
+ return true;
+ }
+
+ // > 2. Throw a `SecurityError` `DOMException`.
+ report_cross_origin_denial::<D>(cx, id, "access")
+}
diff --git a/components/script_bindings/realms.rs b/components/script_bindings/realms.rs
new file mode 100644
index 00000000000..3fe60d5ae5c
--- /dev/null
+++ b/components/script_bindings/realms.rs
@@ -0,0 +1,64 @@
+/* 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/. */
+
+use js::jsapi::{GetCurrentRealmOrNull, JSAutoRealm};
+
+use crate::DomTypes;
+use crate::interfaces::GlobalScopeHelpers;
+use crate::reflector::DomObject;
+use crate::script_runtime::JSContext;
+
+pub struct AlreadyInRealm(());
+
+impl AlreadyInRealm {
+ #![allow(unsafe_code)]
+ pub fn assert<D: DomTypes>() -> AlreadyInRealm {
+ unsafe {
+ assert!(!GetCurrentRealmOrNull(*D::GlobalScope::get_cx()).is_null());
+ }
+ AlreadyInRealm(())
+ }
+
+ pub fn assert_for_cx(cx: JSContext) -> AlreadyInRealm {
+ unsafe {
+ assert!(!GetCurrentRealmOrNull(*cx).is_null());
+ }
+ AlreadyInRealm(())
+ }
+}
+
+#[derive(Clone, Copy)]
+pub enum InRealm<'a> {
+ Already(&'a AlreadyInRealm),
+ Entered(&'a JSAutoRealm),
+}
+
+impl<'a> From<&'a AlreadyInRealm> for InRealm<'a> {
+ fn from(token: &'a AlreadyInRealm) -> InRealm<'a> {
+ InRealm::already(token)
+ }
+}
+
+impl<'a> From<&'a JSAutoRealm> for InRealm<'a> {
+ fn from(token: &'a JSAutoRealm) -> InRealm<'a> {
+ InRealm::entered(token)
+ }
+}
+
+impl InRealm<'_> {
+ pub fn already(token: &AlreadyInRealm) -> InRealm {
+ InRealm::Already(token)
+ }
+
+ pub fn entered(token: &JSAutoRealm) -> InRealm {
+ InRealm::Entered(token)
+ }
+}
+
+pub fn enter_realm<D: DomTypes>(object: &impl DomObject) -> JSAutoRealm {
+ JSAutoRealm::new(
+ *D::GlobalScope::get_cx(),
+ object.reflector().get_jsobject().get(),
+ )
+}
diff --git a/components/script_bindings/reflector.rs b/components/script_bindings/reflector.rs
index 2f9e77c6928..6b6ae03cb69 100644
--- a/components/script_bindings/reflector.rs
+++ b/components/script_bindings/reflector.rs
@@ -6,6 +6,13 @@ use js::jsapi::{Heap, JSObject};
use js::rust::HandleObject;
use malloc_size_of_derive::MallocSizeOf;
+use crate::interfaces::GlobalScopeHelpers;
+use crate::iterable::{Iterable, IterableIterator};
+use crate::realms::{AlreadyInRealm, InRealm};
+use crate::root::{Dom, DomRoot, Root};
+use crate::script_runtime::{CanGc, JSContext};
+use crate::{DomTypes, JSTraceable};
+
/// A struct to store a reference to the reflector of a DOM object.
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
#[derive(MallocSizeOf)]
@@ -90,3 +97,55 @@ impl MutDomObject for Reflector {
self.set_jsobject(obj)
}
}
+
+pub trait DomGlobalGeneric<D: DomTypes>: DomObject {
+ /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this
+ /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For
+ /// `Node`s it's almost always better to use `NodeTraits::owning_global`.
+ fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope>
+ where
+ Self: Sized,
+ {
+ D::GlobalScope::from_reflector(self, realm)
+ }
+
+ /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this
+ /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For
+ /// `Node`s it's almost always better to use `NodeTraits::owning_global`.
+ fn global(&self) -> DomRoot<D::GlobalScope>
+ where
+ Self: Sized,
+ {
+ let realm = AlreadyInRealm::assert_for_cx(D::GlobalScope::get_cx());
+ D::GlobalScope::from_reflector(self, InRealm::already(&realm))
+ }
+}
+
+impl<D: DomTypes, T: DomObject> DomGlobalGeneric<D> for T {}
+
+/// A trait to provide a function pointer to wrap function for DOM objects.
+pub trait DomObjectWrap<D: DomTypes>: Sized + DomObject + DomGlobalGeneric<D> {
+ /// Function pointer to the general wrap function type
+ #[allow(clippy::type_complexity)]
+ const WRAP: unsafe fn(
+ JSContext,
+ &D::GlobalScope,
+ Option<HandleObject>,
+ Box<Self>,
+ CanGc,
+ ) -> Root<Dom<Self>>;
+}
+
+/// A trait to provide a function pointer to wrap function for
+/// DOM iterator interfaces.
+pub trait DomObjectIteratorWrap<D: DomTypes>: DomObjectWrap<D> + JSTraceable + Iterable {
+ /// Function pointer to the wrap function for `IterableIterator<T>`
+ #[allow(clippy::type_complexity)]
+ const ITER_WRAP: unsafe fn(
+ JSContext,
+ &D::GlobalScope,
+ Option<HandleObject>,
+ Box<IterableIterator<D, Self>>,
+ CanGc,
+ ) -> Root<Dom<IterableIterator<D, Self>>>;
+}
diff --git a/components/script_bindings/settings_stack.rs b/components/script_bindings/settings_stack.rs
new file mode 100644
index 00000000000..cdc8c2a029d
--- /dev/null
+++ b/components/script_bindings/settings_stack.rs
@@ -0,0 +1,142 @@
+/* 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/. */
+
+use std::marker::PhantomData;
+use std::thread;
+
+use js::jsapi::{HideScriptedCaller, UnhideScriptedCaller};
+use js::rust::Runtime;
+
+use crate::DomTypes;
+use crate::interfaces::{DomHelpers, GlobalScopeHelpers};
+use crate::root::{Dom, DomRoot};
+use crate::script_runtime::CanGc;
+
+#[derive(Debug, Eq, JSTraceable, PartialEq)]
+pub enum StackEntryKind {
+ Incumbent,
+ Entry,
+}
+
+#[cfg_attr(crown, allow(crown::unrooted_must_root))]
+#[derive(JSTraceable)]
+pub struct StackEntry<D: DomTypes> {
+ pub global: Dom<D::GlobalScope>,
+ pub kind: StackEntryKind,
+}
+
+/// RAII struct that pushes and pops entries from the script settings stack.
+pub struct GenericAutoEntryScript<D: DomTypes> {
+ global: DomRoot<D::GlobalScope>,
+ #[cfg(feature = "tracing")]
+ #[allow(dead_code)]
+ span: tracing::span::EnteredSpan,
+}
+
+impl<D: DomTypes> GenericAutoEntryScript<D> {
+ /// <https://html.spec.whatwg.org/multipage/#prepare-to-run-script>
+ pub fn new(global: &D::GlobalScope) -> Self {
+ let settings_stack = <D as DomHelpers<D>>::settings_stack();
+ settings_stack.with(|stack| {
+ trace!("Prepare to run script with {:p}", global);
+ let mut stack = stack.borrow_mut();
+ stack.push(StackEntry {
+ global: Dom::from_ref(global),
+ kind: StackEntryKind::Entry,
+ });
+ Self {
+ global: DomRoot::from_ref(global),
+ #[cfg(feature = "tracing")]
+ span: tracing::info_span!(
+ "ScriptEvaluate",
+ servo_profiling = true,
+ url = global.get_url().to_string(),
+ )
+ .entered(),
+ }
+ })
+ }
+}
+
+impl<D: DomTypes> Drop for GenericAutoEntryScript<D> {
+ /// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-script>
+ fn drop(&mut self) {
+ let settings_stack = <D as DomHelpers<D>>::settings_stack();
+ settings_stack.with(|stack| {
+ let mut stack = stack.borrow_mut();
+ let entry = stack.pop().unwrap();
+ assert_eq!(
+ &*entry.global as *const D::GlobalScope, &*self.global as *const D::GlobalScope,
+ "Dropped AutoEntryScript out of order."
+ );
+ assert_eq!(entry.kind, StackEntryKind::Entry);
+ trace!("Clean up after running script with {:p}", &*entry.global);
+ });
+
+ // Step 5
+ if !thread::panicking() && D::GlobalScope::incumbent().is_none() {
+ self.global.perform_a_microtask_checkpoint(CanGc::note());
+ }
+ }
+}
+
+/// RAII struct that pushes and pops entries from the script settings stack.
+pub struct GenericAutoIncumbentScript<D: DomTypes> {
+ global: usize,
+ _marker: PhantomData<D>,
+}
+
+impl<D: DomTypes> GenericAutoIncumbentScript<D> {
+ /// <https://html.spec.whatwg.org/multipage/#prepare-to-run-a-callback>
+ pub fn new(global: &D::GlobalScope) -> Self {
+ // Step 2-3.
+ unsafe {
+ let cx =
+ Runtime::get().expect("Creating a new incumbent script after runtime shutdown");
+ HideScriptedCaller(cx.as_ptr());
+ }
+ let settings_stack = <D as DomHelpers<D>>::settings_stack();
+ settings_stack.with(|stack| {
+ trace!("Prepare to run a callback with {:p}", global);
+ // Step 1.
+ let mut stack = stack.borrow_mut();
+ stack.push(StackEntry {
+ global: Dom::from_ref(global),
+ kind: StackEntryKind::Incumbent,
+ });
+ Self {
+ global: global as *const _ as usize,
+ _marker: PhantomData,
+ }
+ })
+ }
+}
+
+impl<D: DomTypes> Drop for GenericAutoIncumbentScript<D> {
+ /// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-a-callback>
+ fn drop(&mut self) {
+ let settings_stack = <D as DomHelpers<D>>::settings_stack();
+ settings_stack.with(|stack| {
+ // Step 4.
+ let mut stack = stack.borrow_mut();
+ let entry = stack.pop().unwrap();
+ // Step 3.
+ assert_eq!(
+ &*entry.global as *const D::GlobalScope as usize, self.global,
+ "Dropped AutoIncumbentScript out of order."
+ );
+ assert_eq!(entry.kind, StackEntryKind::Incumbent);
+ trace!(
+ "Clean up after running a callback with {:p}",
+ &*entry.global
+ );
+ });
+ unsafe {
+ // Step 1-2.
+ if let Some(cx) = Runtime::get() {
+ UnhideScriptedCaller(cx.as_ptr());
+ }
+ }
+ }
+}
diff --git a/components/script_bindings/trace.rs b/components/script_bindings/trace.rs
index 3248fbfc67c..dbdf5be94df 100644
--- a/components/script_bindings/trace.rs
+++ b/components/script_bindings/trace.rs
@@ -3,16 +3,21 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::OnceCell;
+use std::fmt::Display;
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
+use std::mem;
+use std::ops::{Deref, DerefMut};
use crossbeam_channel::Sender;
use html5ever::interface::{Tracer as HtmlTracer, TreeSink};
use html5ever::tokenizer::{TokenSink, Tokenizer};
use html5ever::tree_builder::TreeBuilder;
use indexmap::IndexMap;
+use js::gc::{GCMethods, Handle};
use js::glue::CallObjectTracer;
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parking_lot::RwLock;
use servo_arc::Arc as ServoArc;
use smallvec::SmallVec;
@@ -46,7 +51,11 @@ pub unsafe fn trace_reflector(tracer: *mut JSTracer, description: &str, reflecto
///
/// # Safety
/// tracer must point to a valid, non-null JS tracer.
-pub unsafe fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) {
+pub(crate) unsafe fn trace_object(
+ tracer: *mut JSTracer,
+ description: &str,
+ obj: &Heap<*mut JSObject>,
+) {
unsafe {
trace!("tracing {}", description);
CallObjectTracer(
@@ -308,3 +317,101 @@ unsafe impl<Handle: JSTraceable + Clone, Sink: JSTraceable + XmlTreeSink<Handle
tree_builder.sink.trace(trc);
}
}
+
+/// Roots any JSTraceable thing
+///
+/// If you have a valid DomObject, use DomRoot.
+/// If you have GC things like *mut JSObject or JSVal, use rooted!.
+/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
+/// If you know what you're doing, use this.
+#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
+pub struct RootedTraceableBox<T: JSTraceable + 'static>(js::gc::RootedTraceableBox<T>);
+
+unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
+ unsafe fn trace(&self, tracer: *mut JSTracer) {
+ self.0.trace(tracer);
+ }
+}
+
+impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
+ /// DomRoot a JSTraceable thing for the life of this RootedTraceableBox
+ pub fn new(traceable: T) -> RootedTraceableBox<T> {
+ Self(js::gc::RootedTraceableBox::new(traceable))
+ }
+
+ /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox.
+ pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
+ Self(js::gc::RootedTraceableBox::from_box(boxed_traceable))
+ }
+}
+
+impl<T> RootedTraceableBox<Heap<T>>
+where
+ Heap<T>: JSTraceable + 'static,
+ T: GCMethods + Copy,
+{
+ pub fn handle(&self) -> Handle<T> {
+ self.0.handle()
+ }
+}
+
+impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
+ fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ // Briefly resurrect the real Box value so we can rely on the existing calculations.
+ // Then immediately forget about it again to avoid dropping the box.
+ let inner = unsafe { Box::from_raw(self.0.ptr()) };
+ let size = inner.size_of(ops);
+ mem::forget(inner);
+ size
+ }
+}
+
+impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
+ fn default() -> RootedTraceableBox<T> {
+ RootedTraceableBox::new(T::default())
+ }
+}
+
+impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ self.0.deref()
+ }
+}
+
+impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ self.0.deref_mut()
+ }
+}
+
+/// Wrapper type for nop traceble
+///
+/// SAFETY: Inner type must not impl JSTraceable
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(crown, crown::trace_in_no_trace_lint::must_not_have_traceable)]
+pub(crate) struct NoTrace<T>(pub(crate) T);
+
+impl<T: Display> Display for NoTrace<T> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl<T> From<T> for NoTrace<T> {
+ fn from(item: T) -> Self {
+ Self(item)
+ }
+}
+
+#[allow(unsafe_code)]
+unsafe impl<T> JSTraceable for NoTrace<T> {
+ #[inline]
+ unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {}
+}
+
+impl<T: MallocSizeOf> MallocSizeOf for NoTrace<T> {
+ fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ self.0.size_of(ops)
+ }
+}
diff --git a/components/script_bindings/utils.rs b/components/script_bindings/utils.rs
index 001360e07ff..95f742c9a06 100644
--- a/components/script_bindings/utils.rs
+++ b/components/script_bindings/utils.rs
@@ -5,17 +5,23 @@
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::ptr::{self, NonNull};
+use std::slice;
use js::conversions::ToJSValConvertible;
+use js::gc::Handle;
use js::glue::{
CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, JS_GetReservedSlot,
RUST_FUNCTION_VALUE_TO_JITINFO,
};
use js::jsapi::{
AtomToLinearString, CallArgs, ExceptionStackBehavior, GetLinearStringCharAt,
- GetLinearStringLength, GetNonCCWObjectGlobal, HandleObject as RawHandleObject, Heap,
- JS_ClearPendingException, JS_IsExceptionPending, JSAtom, JSContext, JSJitInfo, JSObject,
- JSTracer, MutableHandleValue as RawMutableHandleValue, ObjectOpResult, StringIsArrayIndex,
+ GetLinearStringLength, GetNonCCWObjectGlobal, HandleId as RawHandleId,
+ HandleObject as RawHandleObject, Heap, JS_ClearPendingException,
+ JS_DeprecatedStringHasLatin1Chars, JS_EnumerateStandardClasses,
+ JS_GetLatin1StringCharsAndLength, JS_IsExceptionPending, JS_IsGlobalObject,
+ JS_ResolveStandardClass, JSAtom, JSContext, JSJitInfo, JSObject, JSTracer,
+ MutableHandleIdVector as RawMutableHandleIdVector, MutableHandleValue as RawMutableHandleValue,
+ ObjectOpResult, StringIsArrayIndex,
};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::wrappers::{
@@ -29,11 +35,13 @@ use js::rust::{
use js::{JS_CALLEE, rooted};
use malloc_size_of::MallocSizeOfOps;
+use crate::DomTypes;
use crate::codegen::Globals::Globals;
use crate::codegen::InheritTypes::TopTypeId;
use crate::codegen::PrototypeList::{self, MAX_PROTO_CHAIN_LENGTH, PROTO_OR_IFACE_LENGTH};
use crate::conversions::{PrototypeCheck, jsstring_to_str, private_from_proto_check};
use crate::error::throw_invalid_this;
+use crate::interfaces::DomHelpers;
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
use crate::str::DOMString;
use crate::trace::trace_object;
@@ -77,24 +85,24 @@ unsafe impl Sync for DOMJSClass {}
/// The index of the slot where the object holder of that interface's
/// unforgeable members are defined.
-pub const DOM_PROTO_UNFORGEABLE_HOLDER_SLOT: u32 = 0;
+pub(crate) const DOM_PROTO_UNFORGEABLE_HOLDER_SLOT: u32 = 0;
/// The index of the slot that contains a reference to the ProtoOrIfaceArray.
// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
-pub const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
+pub(crate) const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
/// The flag set on the `JSClass`es for DOM global objects.
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
// LSetDOMProperty. Those constants need to be changed accordingly if this value
// changes.
-pub const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
+pub(crate) const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
/// Returns the ProtoOrIfaceArray for the given global object.
/// Fails if `global` is not a DOM global object.
///
/// # Safety
/// `global` must point to a valid, non-null JS object.
-pub unsafe fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray {
+pub(crate) unsafe fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray {
assert_ne!(((*get_object_class(global)).flags & JSCLASS_DOM_GLOBAL), 0);
let mut slot = UndefinedValue();
JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT, &mut slot);
@@ -112,7 +120,7 @@ pub type ProtoOrIfaceArray = [*mut JSObject; PROTO_OR_IFACE_LENGTH];
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
/// `found` must point to a valid, non-null bool.
-pub unsafe fn get_property_on_prototype(
+pub(crate) unsafe fn get_property_on_prototype(
cx: *mut JSContext,
proxy: HandleObject,
receiver: HandleValue,
@@ -206,7 +214,7 @@ pub fn get_array_index_from_id(id: HandleId) -> Option<u32> {
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
#[allow(clippy::result_unit_err)]
-pub unsafe fn find_enum_value<'a, T>(
+pub(crate) unsafe fn find_enum_value<'a, T>(
cx: *mut JSContext,
v: HandleValue,
pairs: &'a [(&'static str, T)],
@@ -285,7 +293,7 @@ pub unsafe fn get_dictionary_property(
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
#[allow(clippy::result_unit_err)]
-pub unsafe fn set_dictionary_property(
+pub(crate) unsafe fn set_dictionary_property(
cx: *mut JSContext,
object: HandleObject,
property: &str,
@@ -325,7 +333,7 @@ pub unsafe fn has_property_on_prototype(
///
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
-pub unsafe fn delete_property_by_id(
+pub(crate) unsafe fn delete_property_by_id(
cx: *mut JSContext,
object: HandleObject,
id: HandleId,
@@ -404,7 +412,7 @@ unsafe fn generic_call<const EXCEPTION_TO_REJECTION: bool>(
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
/// `vp` must point to a VALID, non-null JSVal.
-pub unsafe extern "C" fn generic_method<const EXCEPTION_TO_REJECTION: bool>(
+pub(crate) unsafe extern "C" fn generic_method<const EXCEPTION_TO_REJECTION: bool>(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
@@ -417,7 +425,7 @@ pub unsafe extern "C" fn generic_method<const EXCEPTION_TO_REJECTION: bool>(
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
/// `vp` must point to a VALID, non-null JSVal.
-pub unsafe extern "C" fn generic_getter<const EXCEPTION_TO_REJECTION: bool>(
+pub(crate) unsafe extern "C" fn generic_getter<const EXCEPTION_TO_REJECTION: bool>(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
@@ -430,7 +438,7 @@ pub unsafe extern "C" fn generic_getter<const EXCEPTION_TO_REJECTION: bool>(
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
/// `vp` must point to a VALID, non-null JSVal.
-pub unsafe extern "C" fn generic_lenient_getter<const EXCEPTION_TO_REJECTION: bool>(
+pub(crate) unsafe extern "C" fn generic_lenient_getter<const EXCEPTION_TO_REJECTION: bool>(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
@@ -458,7 +466,7 @@ unsafe extern "C" fn call_setter(
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
/// `vp` must point to a VALID, non-null JSVal.
-pub unsafe extern "C" fn generic_setter(
+pub(crate) unsafe extern "C" fn generic_setter(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
@@ -471,7 +479,7 @@ pub unsafe extern "C" fn generic_setter(
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
/// `vp` must point to a VALID, non-null JSVal.
-pub unsafe extern "C" fn generic_lenient_setter(
+pub(crate) unsafe extern "C" fn generic_lenient_setter(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
@@ -484,7 +492,7 @@ pub unsafe extern "C" fn generic_lenient_setter(
///
/// `cx` must point to a valid, non-null JSContext.
/// `vp` must point to a VALID, non-null JSVal.
-pub unsafe extern "C" fn generic_static_promise_method(
+pub(crate) unsafe extern "C" fn generic_static_promise_method(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
@@ -508,7 +516,7 @@ pub unsafe extern "C" fn generic_static_promise_method(
///
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
-pub unsafe fn exception_to_promise(
+pub(crate) unsafe fn exception_to_promise(
cx: *mut JSContext,
rval: RawMutableHandleValue,
_can_gc: CanGc,
@@ -533,7 +541,7 @@ pub unsafe fn exception_to_promise(
/// # 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) {
+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() {
@@ -557,7 +565,7 @@ impl<T> AsVoidPtr for T {
}
// Generic method for returning c_char from caller
-pub trait AsCCharPtrPtr {
+pub(crate) trait AsCCharPtrPtr {
fn as_c_char_ptr(&self) -> *const c_char;
}
@@ -566,3 +574,58 @@ impl AsCCharPtrPtr for [u8] {
self as *const [u8] as *const c_char
}
}
+
+/// Enumerate lazy properties of a global object.
+pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ _props: RawMutableHandleIdVector,
+ _enumerable_only: bool,
+) -> bool {
+ assert!(JS_IsGlobalObject(obj.get()));
+ if !JS_EnumerateStandardClasses(cx, obj) {
+ return false;
+ }
+ 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<D: DomTypes>(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ id: RawHandleId,
+ rval: *mut bool,
+) -> bool {
+ assert!(JS_IsGlobalObject(obj.get()));
+ if !JS_ResolveStandardClass(cx, obj, id, rval) {
+ return false;
+ }
+ if *rval {
+ return true;
+ }
+ if !id.is_string() {
+ *rval = false;
+ return true;
+ }
+
+ let string = id.to_string();
+ if !JS_DeprecatedStringHasLatin1Chars(string) {
+ *rval = false;
+ return true;
+ }
+ let mut length = 0;
+ let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
+ assert!(!ptr.is_null());
+ let bytes = slice::from_raw_parts(ptr, length);
+
+ 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 {
+ *rval = false;
+ }
+ true
+}
diff --git a/components/script_bindings/weakref.rs b/components/script_bindings/weakref.rs
index 38f4f709997..2ec07e1f4af 100644
--- a/components/script_bindings/weakref.rs
+++ b/components/script_bindings/weakref.rs
@@ -29,7 +29,7 @@ use crate::root::DomRoot;
/// stored for weak-referenceable bindings. We use slot 1 for holding it,
/// this is unsafe for globals, we disallow weak-referenceable globals
/// directly in codegen.
-pub const DOM_WEAK_SLOT: u32 = 1;
+pub(crate) const DOM_WEAK_SLOT: u32 = 1;
/// A weak reference to a JS-managed DOM object.
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]