diff options
Diffstat (limited to 'components/script/dom/bindings/callback.rs')
-rw-r--r-- | components/script/dom/bindings/callback.rs | 295 |
1 files changed, 0 insertions, 295 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()); - } -} |