aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings
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/script/dom/bindings
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/script/dom/bindings')
-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/guard.rs96
-rw-r--r--components/script/dom/bindings/import.rs159
-rw-r--r--components/script/dom/bindings/interface.rs696
-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/namespace.rs62
-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
16 files changed, 57 insertions, 2422 deletions
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/guard.rs b/components/script/dom/bindings/guard.rs
deleted file mode 100644
index 16b5187abef..00000000000
--- a/components/script/dom/bindings/guard.rs
+++ /dev/null
@@ -1,96 +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/. */
-
-//! 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::realms::{AlreadyInRealm, InRealm};
-use crate::script_runtime::JSContext;
-
-/// A container with a list of conditions.
-pub(crate) struct Guard<T: Clone + Copy> {
- conditions: &'static [Condition],
- value: T,
-}
-
-impl<T: Clone + Copy> Guard<T> {
- /// Construct a new guarded value.
- pub(crate) const fn new(conditions: &'static [Condition], value: T) -> Self {
- Guard { conditions, value }
- }
-
- /// Expose the value if the conditions are satisfied.
- ///
- /// The passed handle is the object on which the value may be exposed.
- pub(crate) fn expose<D: DomTypes>(
- &self,
- cx: JSContext,
- obj: HandleObject,
- global: HandleObject,
- ) -> Option<T> {
- let mut exposed_on_global = false;
- let conditions_satisfied = self.conditions.iter().all(|c| match c {
- Condition::Satisfied => {
- exposed_on_global = true;
- true
- },
- // If there are multiple Exposed conditions, we just need one of them to be true
- Condition::Exposed(globals) => {
- exposed_on_global |= is_exposed_in(global, *globals);
- true
- },
- _ => c.is_satisfied::<D>(cx, obj, global),
- });
-
- if conditions_satisfied && exposed_on_global {
- Some(self.value)
- } else {
- None
- }
- }
-}
-
-/// A condition to expose things.
-#[derive(Clone, Copy)]
-pub(crate) enum Condition {
- /// The condition is satisfied if the function returns true.
- Func(fn(JSContext, HandleObject) -> bool),
- /// The condition is satisfied if the preference is set.
- Pref(&'static str),
- // The condition is satisfied if the interface is exposed in the global.
- Exposed(Globals),
- SecureContext(),
- /// The condition is always satisfied.
- Satisfied,
-}
-
-fn is_secure_context<D: DomTypes>(cx: JSContext) -> bool {
- unsafe {
- let in_realm_proof = AlreadyInRealm::assert_for_cx(JSContext::from_ptr(*cx));
- D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)).is_secure_context()
- }
-}
-
-impl Condition {
- pub(crate) fn is_satisfied<D: DomTypes>(
- &self,
- cx: JSContext,
- obj: HandleObject,
- global: HandleObject,
- ) -> bool {
- match *self {
- Condition::Pref(name) => get().get_value(name).try_into().unwrap_or(false),
- Condition::Func(f) => f(cx, obj),
- Condition::Exposed(globals) => is_exposed_in(global, globals),
- Condition::SecureContext() => is_secure_context::<D>(cx),
- Condition::Satisfied => true,
- }
- }
-}
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/interface.rs b/components/script/dom/bindings/interface.rs
deleted file mode 100644
index d1c191be3a4..00000000000
--- a/components/script/dom/bindings/interface.rs
+++ /dev/null
@@ -1,696 +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/. */
-
-//! Machinery to initialise interface prototype objects and interface objects.
-
-use std::convert::TryFrom;
-use std::ffi::CStr;
-use std::ptr;
-
-use js::error::throw_type_error;
-use js::glue::UncheckedUnwrapObject;
-use js::jsapi::JS::CompartmentIterResult;
-use js::jsapi::{
- CallArgs, CheckedUnwrapStatic, Compartment, CompartmentSpecifier, CurrentGlobalOrNull,
- GetFunctionRealm, GetNonCCWObjectGlobal, GetRealmGlobalOrNull, GetWellKnownSymbol,
- HandleObject as RawHandleObject, IsSharableCompartment, IsSystemCompartment,
- JS_AtomizeAndPinString, JS_GetFunctionObject, JS_GetProperty, JS_IterateCompartments,
- JS_NewFunction, JS_NewGlobalObject, JS_NewObject, JS_NewPlainObject, JS_NewStringCopyN,
- JS_SetReservedSlot, JS_WrapObject, JSAutoRealm, JSClass, JSClassOps, JSContext,
- JSFUN_CONSTRUCTOR, JSFunctionSpec, JSObject, JSPROP_PERMANENT, JSPROP_READONLY,
- JSPROP_RESOLVING, JSPropertySpec, JSString, JSTracer, ObjectOps, OnNewGlobalHookOption,
- SymbolCode, TrueHandleValue, Value, jsid,
-};
-use js::jsval::{JSVal, NullValue, PrivateValue};
-use js::rust::wrappers::{
- JS_DefineProperty, JS_DefineProperty3, JS_DefineProperty4, JS_DefineProperty5,
- JS_DefinePropertyById5, JS_FireOnNewGlobalObject, JS_LinkConstructorAndPrototype,
- JS_NewObjectWithGivenProto, RUST_SYMBOL_TO_JSID,
-};
-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::{
- 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)]
-pub(crate) struct NonCallbackInterfaceObjectClass {
- /// The SpiderMonkey class structure.
- pub(crate) _class: JSClass,
- /// The prototype id of that interface, used in the hasInstance hook.
- pub(crate) _proto_id: PrototypeList::ID,
- /// The prototype depth of that interface, used in the hasInstance hook.
- pub(crate) _proto_depth: u16,
- /// The string representation of the object.
- pub(crate) representation: &'static [u8],
-}
-
-unsafe impl Sync for NonCallbackInterfaceObjectClass {}
-
-impl NonCallbackInterfaceObjectClass {
- /// Create a new `NonCallbackInterfaceObjectClass` structure.
- pub(crate) const fn new(
- constructor_behavior: &'static InterfaceConstructorBehavior,
- string_rep: &'static [u8],
- proto_id: PrototypeList::ID,
- proto_depth: u16,
- ) -> NonCallbackInterfaceObjectClass {
- NonCallbackInterfaceObjectClass {
- _class: JSClass {
- name: c"Function".as_ptr(),
- flags: 0,
- cOps: &constructor_behavior.0,
- spec: 0 as *const _,
- ext: 0 as *const _,
- oOps: &OBJECT_OPS,
- },
- _proto_id: proto_id,
- _proto_depth: proto_depth,
- representation: string_rep,
- }
- }
-
- /// cast own reference to `JSClass` reference
- pub(crate) fn as_jsclass(&self) -> &JSClass {
- unsafe { &*(self as *const _ as *const JSClass) }
- }
-}
-
-/// A constructor class hook.
-pub(crate) type ConstructorClassHook =
- unsafe extern "C" fn(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool;
-
-/// The constructor behavior of a non-callback interface object.
-pub(crate) struct InterfaceConstructorBehavior(JSClassOps);
-
-impl InterfaceConstructorBehavior {
- /// An interface constructor that unconditionally throws a type error.
- pub(crate) const fn throw() -> Self {
- InterfaceConstructorBehavior(JSClassOps {
- addProperty: None,
- delProperty: None,
- enumerate: None,
- newEnumerate: None,
- resolve: None,
- mayResolve: None,
- finalize: None,
- call: Some(invalid_constructor),
- construct: Some(invalid_constructor),
- trace: None,
- })
- }
-
- /// An interface constructor that calls a native Rust function.
- pub(crate) const fn call(hook: ConstructorClassHook) -> Self {
- InterfaceConstructorBehavior(JSClassOps {
- addProperty: None,
- delProperty: None,
- enumerate: None,
- newEnumerate: None,
- resolve: None,
- mayResolve: None,
- finalize: None,
- call: Some(non_new_constructor),
- construct: Some(hook),
- trace: None,
- })
- }
-}
-
-/// A trace hook.
-pub(crate) type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
-
-/// Create a global object with the given class.
-pub(crate) unsafe fn create_global_object<D: DomTypes>(
- cx: SafeJSContext,
- class: &'static JSClass,
- private: *const libc::c_void,
- trace: TraceHook,
- mut rval: MutableHandleObject,
- origin: &MutableOrigin,
-) {
- assert!(rval.is_null());
-
- let mut options = RealmOptions::default();
- options.creationOptions_.traceGlobal_ = Some(trace);
- options.creationOptions_.sharedMemoryAndAtomics_ = false;
- select_compartment(cx, &mut options);
-
- let principal = ServoJSPrincipals::new::<D>(origin);
-
- rval.set(JS_NewGlobalObject(
- *cx,
- class,
- principal.as_raw(),
- OnNewGlobalHookOption::DontFireOnNewGlobalHook,
- &*options,
- ));
- assert!(!rval.is_null());
-
- // Initialize the reserved slots before doing anything that can GC, to
- // avoid getting trace hooks called on a partially initialized object.
- let private_val = PrivateValue(private);
- JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, &private_val);
- let proto_array: Box<ProtoOrIfaceArray> =
- Box::new([ptr::null_mut::<JSObject>(); PrototypeList::PROTO_OR_IFACE_LENGTH]);
- let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void);
- JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val);
-
- let _ac = JSAutoRealm::new(*cx, rval.get());
- JS_FireOnNewGlobalObject(*cx, rval.handle());
-}
-
-/// Choose the compartment to create a new global object in.
-fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) {
- type Data = *mut Compartment;
- unsafe extern "C" fn callback(
- _cx: *mut JSContext,
- data: *mut libc::c_void,
- compartment: *mut Compartment,
- ) -> CompartmentIterResult {
- let data = data as *mut Data;
-
- if !IsSharableCompartment(compartment) || IsSystemCompartment(compartment) {
- return CompartmentIterResult::KeepGoing;
- }
-
- // Choose any sharable, non-system compartment in this context to allow
- // same-agent documents to share JS and DOM objects.
- *data = compartment;
- CompartmentIterResult::Stop
- }
-
- let mut compartment: Data = ptr::null_mut();
- unsafe {
- JS_IterateCompartments(
- *cx,
- (&mut compartment) as *mut Data as *mut libc::c_void,
- Some(callback),
- );
- }
-
- if compartment.is_null() {
- options.creationOptions_.compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
- } else {
- options.creationOptions_.compSpec_ = CompartmentSpecifier::ExistingCompartment;
- options.creationOptions_.__bindgen_anon_1.comp_ = compartment;
- }
-}
-
-/// Create and define the interface object of a callback interface.
-pub(crate) fn create_callback_interface_object<D: DomTypes>(
- cx: SafeJSContext,
- global: HandleObject,
- constants: &[Guard<&[ConstantSpec]>],
- name: &CStr,
- mut rval: MutableHandleObject,
-) {
- assert!(!constants.is_empty());
- unsafe {
- rval.set(JS_NewObject(*cx, ptr::null()));
- }
- assert!(!rval.is_null());
- define_guarded_constants::<D>(cx, rval.handle(), constants, global);
- define_name(cx, rval.handle(), name);
- define_on_global_object(cx, global, name, rval.handle());
-}
-
-/// Create the interface prototype object of a non-callback interface.
-#[allow(clippy::too_many_arguments)]
-pub(crate) fn create_interface_prototype_object<D: DomTypes>(
- cx: SafeJSContext,
- global: HandleObject,
- proto: HandleObject,
- class: &'static JSClass,
- regular_methods: &[Guard<&'static [JSFunctionSpec]>],
- regular_properties: &[Guard<&'static [JSPropertySpec]>],
- constants: &[Guard<&[ConstantSpec]>],
- unscopable_names: &[&CStr],
- mut rval: MutableHandleObject,
-) {
- create_object::<D>(
- cx,
- global,
- proto,
- class,
- regular_methods,
- regular_properties,
- constants,
- rval.reborrow(),
- );
-
- if !unscopable_names.is_empty() {
- rooted!(in(*cx) let mut unscopable_obj = ptr::null_mut::<JSObject>());
- create_unscopable_object(cx, unscopable_names, unscopable_obj.handle_mut());
- unsafe {
- let unscopable_symbol = GetWellKnownSymbol(*cx, SymbolCode::unscopables);
- assert!(!unscopable_symbol.is_null());
-
- rooted!(in(*cx) let mut unscopable_id: jsid);
- RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut());
-
- assert!(JS_DefinePropertyById5(
- *cx,
- rval.handle(),
- unscopable_id.handle(),
- unscopable_obj.handle(),
- JSPROP_READONLY as u32
- ))
- }
- }
-}
-
-/// Create and define the interface object of a non-callback interface.
-#[allow(clippy::too_many_arguments)]
-pub(crate) fn create_noncallback_interface_object<D: DomTypes>(
- cx: SafeJSContext,
- global: HandleObject,
- proto: HandleObject,
- class: &'static NonCallbackInterfaceObjectClass,
- static_methods: &[Guard<&'static [JSFunctionSpec]>],
- static_properties: &[Guard<&'static [JSPropertySpec]>],
- constants: &[Guard<&[ConstantSpec]>],
- interface_prototype_object: HandleObject,
- name: &CStr,
- length: u32,
- legacy_window_alias_names: &[&CStr],
- mut rval: MutableHandleObject,
-) {
- create_object::<D>(
- cx,
- global,
- proto,
- class.as_jsclass(),
- static_methods,
- static_properties,
- constants,
- rval.reborrow(),
- );
- unsafe {
- assert!(JS_LinkConstructorAndPrototype(
- *cx,
- rval.handle(),
- interface_prototype_object
- ));
- }
- define_name(cx, rval.handle(), name);
- define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
- define_on_global_object(cx, global, name, rval.handle());
-
- if is_exposed_in(global, Globals::WINDOW) {
- for legacy_window_alias in legacy_window_alias_names {
- define_on_global_object(cx, global, legacy_window_alias, rval.handle());
- }
- }
-}
-
-/// Create and define the named constructors of a non-callback interface.
-pub(crate) fn create_named_constructors(
- cx: SafeJSContext,
- global: HandleObject,
- named_constructors: &[(ConstructorClassHook, &CStr, u32)],
- interface_prototype_object: HandleObject,
-) {
- rooted!(in(*cx) let mut constructor = ptr::null_mut::<JSObject>());
-
- for &(native, name, arity) in named_constructors {
- unsafe {
- let fun = JS_NewFunction(*cx, Some(native), arity, JSFUN_CONSTRUCTOR, name.as_ptr());
- assert!(!fun.is_null());
- constructor.set(JS_GetFunctionObject(fun));
- assert!(!constructor.is_null());
-
- assert!(JS_DefineProperty3(
- *cx,
- constructor.handle(),
- c"prototype".as_ptr(),
- interface_prototype_object,
- (JSPROP_PERMANENT | JSPROP_READONLY) as u32
- ));
- }
-
- define_on_global_object(cx, global, name, constructor.handle());
- }
-}
-
-/// Create a new object with a unique type.
-#[allow(clippy::too_many_arguments)]
-pub(crate) fn create_object<D: DomTypes>(
- cx: SafeJSContext,
- global: HandleObject,
- proto: HandleObject,
- class: &'static JSClass,
- methods: &[Guard<&'static [JSFunctionSpec]>],
- properties: &[Guard<&'static [JSPropertySpec]>],
- constants: &[Guard<&[ConstantSpec]>],
- mut rval: MutableHandleObject,
-) {
- unsafe {
- rval.set(JS_NewObjectWithGivenProto(*cx, class, proto));
- }
- assert!(!rval.is_null());
- define_guarded_methods::<D>(cx, rval.handle(), methods, global);
- define_guarded_properties::<D>(cx, rval.handle(), properties, global);
- define_guarded_constants::<D>(cx, rval.handle(), constants, global);
-}
-
-/// Conditionally define constants on an object.
-pub(crate) fn define_guarded_constants<D: DomTypes>(
- cx: SafeJSContext,
- obj: HandleObject,
- constants: &[Guard<&[ConstantSpec]>],
- global: HandleObject,
-) {
- for guard in constants {
- if let Some(specs) = guard.expose::<D>(cx, obj, global) {
- define_constants(cx, obj, specs);
- }
- }
-}
-
-/// Conditionally define methods on an object.
-pub(crate) fn define_guarded_methods<D: DomTypes>(
- cx: SafeJSContext,
- obj: HandleObject,
- methods: &[Guard<&'static [JSFunctionSpec]>],
- global: HandleObject,
-) {
- for guard in methods {
- if let Some(specs) = guard.expose::<D>(cx, obj, global) {
- unsafe {
- define_methods(*cx, obj, specs).unwrap();
- }
- }
- }
-}
-
-/// Conditionally define properties on an object.
-pub(crate) fn define_guarded_properties<D: DomTypes>(
- cx: SafeJSContext,
- obj: HandleObject,
- properties: &[Guard<&'static [JSPropertySpec]>],
- global: HandleObject,
-) {
- for guard in properties {
- if let Some(specs) = guard.expose::<D>(cx, obj, global) {
- unsafe {
- define_properties(*cx, obj, specs).unwrap();
- }
- }
- }
-}
-
-/// Returns whether an interface with exposure set given by `globals` should
-/// be exposed in the global object `obj`.
-pub(crate) fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
- unsafe {
- let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ false);
- let dom_class = get_dom_class(unwrapped).unwrap();
- globals.contains(dom_class.global)
- }
-}
-
-/// Define a property with a given name on the global object. Should be called
-/// through the resolve hook.
-pub(crate) fn define_on_global_object(
- cx: SafeJSContext,
- global: HandleObject,
- name: &CStr,
- obj: HandleObject,
-) {
- unsafe {
- assert!(JS_DefineProperty3(
- *cx,
- global,
- name.as_ptr(),
- obj,
- JSPROP_RESOLVING
- ));
- }
-}
-
-const OBJECT_OPS: ObjectOps = ObjectOps {
- lookupProperty: None,
- defineProperty: None,
- hasProperty: None,
- getProperty: None,
- setProperty: None,
- getOwnPropertyDescriptor: None,
- deleteProperty: None,
- getElements: None,
- funToString: Some(fun_to_string_hook),
-};
-
-unsafe extern "C" fn fun_to_string_hook(
- cx: *mut JSContext,
- obj: RawHandleObject,
- _is_to_source: bool,
-) -> *mut JSString {
- let js_class = get_object_class(obj.get());
- assert!(!js_class.is_null());
- let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
- assert!(!repr.is_empty());
- let ret = JS_NewStringCopyN(cx, repr.as_ptr() as *const libc::c_char, repr.len());
- assert!(!ret.is_null());
- ret
-}
-
-fn create_unscopable_object(cx: SafeJSContext, names: &[&CStr], mut rval: MutableHandleObject) {
- assert!(!names.is_empty());
- assert!(rval.is_null());
- unsafe {
- rval.set(JS_NewPlainObject(*cx));
- assert!(!rval.is_null());
- for &name in names {
- assert!(JS_DefineProperty(
- *cx,
- rval.handle(),
- name.as_ptr(),
- HandleValue::from_raw(TrueHandleValue),
- JSPROP_READONLY as u32,
- ));
- }
- }
-}
-
-fn define_name(cx: SafeJSContext, obj: HandleObject, name: &CStr) {
- unsafe {
- rooted!(in(*cx) let name = JS_AtomizeAndPinString(*cx, name.as_ptr()));
- assert!(!name.is_null());
- assert!(JS_DefineProperty4(
- *cx,
- obj,
- c"name".as_ptr(),
- name.handle(),
- JSPROP_READONLY as u32
- ));
- }
-}
-
-fn define_length(cx: SafeJSContext, obj: HandleObject, length: i32) {
- unsafe {
- assert!(JS_DefineProperty5(
- *cx,
- obj,
- c"length".as_ptr(),
- length,
- JSPROP_READONLY as u32
- ));
- }
-}
-
-unsafe extern "C" fn invalid_constructor(
- cx: *mut JSContext,
- _argc: libc::c_uint,
- _vp: *mut JSVal,
-) -> bool {
- throw_type_error(cx, "Illegal constructor.");
- false
-}
-
-unsafe extern "C" fn non_new_constructor(
- cx: *mut JSContext,
- _argc: libc::c_uint,
- _vp: *mut JSVal,
-) -> bool {
- throw_type_error(cx, "This constructor needs to be called with `new`.");
- false
-}
-
-pub(crate) enum ProtoOrIfaceIndex {
- ID(PrototypeList::ID),
- Constructor(PrototypeList::Constructor),
-}
-
-impl From<ProtoOrIfaceIndex> for usize {
- fn from(index: ProtoOrIfaceIndex) -> usize {
- match index {
- ProtoOrIfaceIndex::ID(id) => id as usize,
- ProtoOrIfaceIndex::Constructor(constructor) => constructor as usize,
- }
- }
-}
-
-pub(crate) fn get_per_interface_object_handle(
- cx: SafeJSContext,
- global: HandleObject,
- id: ProtoOrIfaceIndex,
- creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
- mut rval: MutableHandleObject,
-) {
- unsafe {
- assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
-
- /* Check to see whether the interface objects are already installed */
- let proto_or_iface_array = get_proto_or_iface_array(global.get());
- let index: usize = id.into();
- rval.set((*proto_or_iface_array)[index]);
- if !rval.get().is_null() {
- return;
- }
-
- creator(cx, global, proto_or_iface_array);
- rval.set((*proto_or_iface_array)[index]);
- assert!(!rval.get().is_null());
- }
-}
-
-pub(crate) fn define_dom_interface(
- cx: SafeJSContext,
- global: HandleObject,
- id: ProtoOrIfaceIndex,
- creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
- enabled: fn(SafeJSContext, HandleObject) -> bool,
-) {
- assert!(!global.get().is_null());
-
- if !enabled(cx, global) {
- return;
- }
-
- rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>());
- get_per_interface_object_handle(cx, global, id, creator, proto.handle_mut());
- assert!(!proto.is_null());
-}
-
-fn get_proto_id_for_new_target(new_target: HandleObject) -> Option<PrototypeList::ID> {
- unsafe {
- let new_target_class = get_object_class(*new_target);
- if is_dom_class(&*new_target_class) {
- let domjsclass: *const DOMJSClass = new_target_class as *const DOMJSClass;
- let dom_class = &(*domjsclass).dom_class;
- return Some(dom_class.interface_chain[dom_class.depth as usize]);
- }
- None
- }
-}
-
-pub(crate) fn get_desired_proto(
- cx: SafeJSContext,
- args: &CallArgs,
- proto_id: PrototypeList::ID,
- creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
- mut desired_proto: MutableHandleObject,
-) -> Result<(), ()> {
- unsafe {
- // This basically implements
- // https://heycam.github.io/webidl/#internally-create-a-new-object-implementing-the-interface
- // step 3.
-
- assert!(args.is_constructing());
-
- // The desired prototype depends on the actual constructor that was invoked,
- // which is passed to us as the newTarget in the callargs. We want to do
- // something akin to the ES6 specification's GetProtototypeFromConstructor (so
- // get .prototype on the newTarget, with a fallback to some sort of default).
-
- // First, a fast path for the case when the the constructor is in fact one of
- // our DOM constructors. This is safe because on those the "constructor"
- // property is non-configurable and non-writable, so we don't have to do the
- // slow JS_GetProperty call.
- rooted!(in(*cx) let mut new_target = args.new_target().to_object());
- rooted!(in(*cx) let original_new_target = *new_target);
- // See whether we have a known DOM constructor here, such that we can take a
- // fast path.
- let target_proto_id = get_proto_id_for_new_target(new_target.handle()).or_else(|| {
- // We might still have a cross-compartment wrapper for a known DOM
- // constructor. CheckedUnwrapStatic is fine here, because we're looking for
- // DOM constructors and those can't be cross-origin objects.
- new_target.set(CheckedUnwrapStatic(*new_target));
- if !new_target.is_null() && *new_target != *original_new_target {
- get_proto_id_for_new_target(new_target.handle())
- } else {
- None
- }
- });
-
- if let Some(proto_id) = target_proto_id {
- let global = GetNonCCWObjectGlobal(*new_target);
- let proto_or_iface_cache = get_proto_or_iface_array(global);
- desired_proto.set((*proto_or_iface_cache)[proto_id as usize]);
- if *new_target != *original_new_target && !JS_WrapObject(*cx, desired_proto.into()) {
- return Err(());
- }
- return Ok(());
- }
-
- // Slow path. This basically duplicates the ES6 spec's
- // GetPrototypeFromConstructor except that instead of taking a string naming
- // the fallback prototype we determine the fallback based on the proto id we
- // were handed.
- rooted!(in(*cx) let mut proto_val = NullValue());
- if !JS_GetProperty(
- *cx,
- original_new_target.handle().into(),
- c"prototype".as_ptr(),
- proto_val.handle_mut().into(),
- ) {
- return Err(());
- }
-
- if proto_val.is_object() {
- desired_proto.set(proto_val.to_object());
- return Ok(());
- }
-
- // Fall back to getting the proto for our given proto id in the realm that
- // GetFunctionRealm(newTarget) returns.
- let realm = GetFunctionRealm(*cx, new_target.handle().into());
-
- if realm.is_null() {
- return Err(());
- }
-
- {
- let _realm = JSAutoRealm::new(*cx, GetRealmGlobalOrNull(realm));
- rooted!(in(*cx) let global = CurrentGlobalOrNull(*cx));
- get_per_interface_object_handle(
- cx,
- global.handle(),
- ProtoOrIfaceIndex::ID(proto_id),
- creator,
- desired_proto.reborrow(),
- );
- if desired_proto.is_null() {
- return Err(());
- }
- }
-
- maybe_wrap_object(*cx, desired_proto);
- Ok(())
- }
-}
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/namespace.rs b/components/script/dom/bindings/namespace.rs
deleted file mode 100644
index ad0a5801519..00000000000
--- a/components/script/dom/bindings/namespace.rs
+++ /dev/null
@@ -1,62 +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/. */
-
-//! Machinery to initialise namespace objects.
-
-use std::ffi::CStr;
-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::script_runtime::JSContext;
-
-/// The class of a namespace object.
-#[derive(Clone, Copy)]
-pub(crate) struct NamespaceObjectClass(JSClass);
-
-unsafe impl Sync for NamespaceObjectClass {}
-
-impl NamespaceObjectClass {
- /// Create a new `NamespaceObjectClass` structure.
- pub(crate) const unsafe fn new(name: &'static CStr) -> Self {
- NamespaceObjectClass(JSClass {
- name: name.as_ptr(),
- flags: 0,
- cOps: 0 as *mut _,
- spec: ptr::null(),
- ext: ptr::null(),
- oOps: ptr::null(),
- })
- }
-}
-
-/// Create a new namespace object.
-#[allow(clippy::too_many_arguments)]
-pub(crate) fn create_namespace_object<D: DomTypes>(
- cx: JSContext,
- global: HandleObject,
- proto: HandleObject,
- class: &'static NamespaceObjectClass,
- methods: &[Guard<&'static [JSFunctionSpec]>],
- constants: &[Guard<&'static [ConstantSpec]>],
- name: &CStr,
- mut rval: MutableHandleObject,
-) {
- create_object::<D>(
- cx,
- global,
- proto,
- &class.0,
- methods,
- &[],
- constants,
- rval.reborrow(),
- );
- define_on_global_object(cx, global, name, rval.handle());
-}
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;