aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2025-04-04 02:45:08 -0400
committerGitHub <noreply@github.com>2025-04-04 06:45:08 +0000
commitb4079b3ff33a3f7e2b35ac3aacc4467f8da42242 (patch)
treeaf6ae87af10c1383a3a3fcdb28b1d2544bc2fc45 /components
parent277c0b82dd4411798b461a4e3a782e7869ae5740 (diff)
downloadservo-b4079b3ff33a3f7e2b35ac3aacc4467f8da42242.tar.gz
servo-b4079b3ff33a3f7e2b35ac3aacc4467f8da42242.zip
Move generated bindings to script_bindings (#36323)
This is the final step of #1799, where the majority of the generated code for the JS bindings is now compiled as part of the script_bindings build step. The remaining pieces in script must live there because they refer to concrete DOM types; all code in script_bindings is generic over the [DomTypes](https://doc.servo.org/script/dom/bindings/codegen/DomTypes/trait.DomTypes.html) trait. My testing with incremental builds shows me a 12 second reduction in build times on my 2024 M4 Macbook Pro when modifying code in the script crate after these changes. Before this PR those changes took 20 seconds to rebuild Servo, and now they take 8 seconds. Testing: Existing WPT tests ensure no regressions. Fixes: #1799 --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
Diffstat (limited to 'components')
-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
43 files changed, 1923 insertions, 1826 deletions
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)]