mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
script: Make callbacks generic over DOM interfaces. (#35459)
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
2b0d2ecc73
commit
a433b20259
9 changed files with 141 additions and 97 deletions
|
@ -20,12 +20,13 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::Wind
|
|||
use crate::dom::bindings::error::{report_pending_exception, Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::settings_stack::{AutoEntryScript, AutoIncumbentScript};
|
||||
use crate::dom::bindings::settings_stack::{GenericAutoEntryScript, GenericAutoIncumbentScript};
|
||||
use crate::dom::bindings::utils::AsCCharPtrPtr;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::document::DocumentHelpers;
|
||||
use crate::dom::globalscope::GlobalScopeHelpers;
|
||||
use crate::realms::{enter_realm, InRealm};
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
use crate::DomTypes;
|
||||
|
||||
/// The exception handling used for a call.
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
|
@ -40,7 +41,7 @@ pub(crate) enum ExceptionHandling {
|
|||
/// callback interface types.
|
||||
#[derive(JSTraceable)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
pub(crate) struct CallbackObject {
|
||||
pub(crate) struct CallbackObject<D: DomTypes> {
|
||||
/// The underlying `JSObject`.
|
||||
callback: Heap<*mut JSObject>,
|
||||
permanent_js_root: Heap<JSVal>,
|
||||
|
@ -56,18 +57,18 @@ pub(crate) struct CallbackObject {
|
|||
///
|
||||
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
|
||||
/// [sometimes]: https://github.com/whatwg/html/issues/2248
|
||||
incumbent: Option<Dom<GlobalScope>>,
|
||||
incumbent: Option<Dom<D::GlobalScope>>,
|
||||
}
|
||||
|
||||
impl CallbackObject {
|
||||
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() -> CallbackObject {
|
||||
CallbackObject {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
callback: Heap::default(),
|
||||
permanent_js_root: Heap::default(),
|
||||
incumbent: GlobalScope::incumbent().map(|i| Dom::from_ref(&*i)),
|
||||
incumbent: D::GlobalScope::incumbent().map(|i| Dom::from_ref(&*i)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,7 @@ impl CallbackObject {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for CallbackObject {
|
||||
impl<D: DomTypes> Drop for CallbackObject<D> {
|
||||
#[allow(unsafe_code)]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
@ -98,19 +99,19 @@ impl Drop for CallbackObject {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CallbackObject {
|
||||
fn eq(&self, other: &CallbackObject) -> bool {
|
||||
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 {
|
||||
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;
|
||||
fn callback_holder(&self) -> &CallbackObject<D>;
|
||||
/// Returns the underlying `JSObject`.
|
||||
fn callback(&self) -> *mut JSObject {
|
||||
self.callback_holder().get()
|
||||
|
@ -119,7 +120,7 @@ pub(crate) trait CallbackContainer {
|
|||
/// incumbent global when calling the callback.
|
||||
///
|
||||
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
|
||||
fn incumbent(&self) -> Option<&GlobalScope> {
|
||||
fn incumbent(&self) -> Option<&D::GlobalScope> {
|
||||
self.callback_holder().incumbent.as_deref()
|
||||
}
|
||||
}
|
||||
|
@ -127,23 +128,23 @@ pub(crate) trait CallbackContainer {
|
|||
/// 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 {
|
||||
object: CallbackObject,
|
||||
pub(crate) struct CallbackFunction<D: DomTypes> {
|
||||
object: CallbackObject<D>,
|
||||
}
|
||||
|
||||
impl CallbackFunction {
|
||||
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() -> CallbackFunction {
|
||||
CallbackFunction {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
object: CallbackObject::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the underlying `CallbackObject`.
|
||||
pub(crate) fn callback_holder(&self) -> &CallbackObject {
|
||||
pub(crate) fn callback_holder(&self) -> &CallbackObject<D> {
|
||||
&self.object
|
||||
}
|
||||
|
||||
|
@ -157,22 +158,22 @@ impl CallbackFunction {
|
|||
/// 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 {
|
||||
object: CallbackObject,
|
||||
pub(crate) struct CallbackInterface<D: DomTypes> {
|
||||
object: CallbackObject<D>,
|
||||
}
|
||||
|
||||
impl CallbackInterface {
|
||||
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() -> CallbackInterface {
|
||||
CallbackInterface {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
object: CallbackObject::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the underlying `CallbackObject`.
|
||||
pub(crate) fn callback_holder(&self) -> &CallbackObject {
|
||||
pub(crate) fn callback_holder(&self) -> &CallbackObject<D> {
|
||||
&self.object
|
||||
}
|
||||
|
||||
|
@ -227,10 +228,10 @@ pub(crate) fn wrap_call_this_value<T: ThisReflector>(
|
|||
|
||||
/// 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 {
|
||||
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<GlobalScope>,
|
||||
exception_global: DomRoot<D::GlobalScope>,
|
||||
/// The `JSContext` used for the call.
|
||||
cx: JSContext,
|
||||
/// The realm we were in before the call.
|
||||
|
@ -239,27 +240,24 @@ pub(crate) struct CallSetup {
|
|||
handling: ExceptionHandling,
|
||||
/// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
|
||||
/// steps 8 and 18.2.
|
||||
entry_script: Option<AutoEntryScript>,
|
||||
entry_script: Option<GenericAutoEntryScript<D>>,
|
||||
/// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
|
||||
/// steps 9 and 18.1.
|
||||
incumbent_script: Option<AutoIncumbentScript>,
|
||||
incumbent_script: Option<GenericAutoIncumbentScript<D>>,
|
||||
}
|
||||
|
||||
impl CallSetup {
|
||||
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>(
|
||||
callback: &T,
|
||||
handling: ExceptionHandling,
|
||||
) -> CallSetup {
|
||||
let global = unsafe { GlobalScope::from_object(callback.callback()) };
|
||||
if let Some(window) = global.downcast::<Window>() {
|
||||
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 = GlobalScope::get_cx();
|
||||
let cx = D::GlobalScope::get_cx();
|
||||
|
||||
let aes = AutoEntryScript::new(&global);
|
||||
let ais = callback.incumbent().map(AutoIncumbentScript::new);
|
||||
let aes = GenericAutoEntryScript::<D>::new(&global);
|
||||
let ais = callback.incumbent().map(GenericAutoIncumbentScript::new);
|
||||
CallSetup {
|
||||
exception_global: global,
|
||||
cx,
|
||||
|
@ -276,7 +274,7 @@ impl CallSetup {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for CallSetup {
|
||||
impl<D: DomTypes> Drop for CallSetup<D> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
LeaveRealm(*self.cx, self.old_realm);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* 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};
|
||||
|
@ -10,10 +11,14 @@ use js::rust::Runtime;
|
|||
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::trace::JSTraceable;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::bindings::utils::DomHelpers;
|
||||
use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers};
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::DomTypes;
|
||||
|
||||
thread_local!(static STACK: RefCell<Vec<StackEntry>> = const { RefCell::new(Vec::new()) });
|
||||
thread_local!(pub(super) static STACK: RefCell<Vec<StackEntry<crate::DomTypeHolder>>> = const {
|
||||
RefCell::new(Vec::new())
|
||||
});
|
||||
|
||||
#[derive(Debug, Eq, JSTraceable, PartialEq)]
|
||||
enum StackEntryKind {
|
||||
|
@ -23,8 +28,8 @@ enum StackEntryKind {
|
|||
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
#[derive(JSTraceable)]
|
||||
struct StackEntry {
|
||||
global: Dom<GlobalScope>,
|
||||
pub(crate) struct StackEntry<D: DomTypes> {
|
||||
global: Dom<D::GlobalScope>,
|
||||
kind: StackEntryKind,
|
||||
}
|
||||
|
||||
|
@ -39,25 +44,28 @@ pub(crate) fn is_execution_stack_empty() -> bool {
|
|||
STACK.with(|stack| stack.borrow().is_empty())
|
||||
}
|
||||
|
||||
pub(crate) type AutoEntryScript = GenericAutoEntryScript<crate::DomTypeHolder>;
|
||||
|
||||
/// RAII struct that pushes and pops entries from the script settings stack.
|
||||
pub(crate) struct AutoEntryScript {
|
||||
global: DomRoot<GlobalScope>,
|
||||
pub(crate) struct GenericAutoEntryScript<D: DomTypes> {
|
||||
global: DomRoot<D::GlobalScope>,
|
||||
#[cfg(feature = "tracing")]
|
||||
#[allow(dead_code)]
|
||||
span: tracing::span::EnteredSpan,
|
||||
}
|
||||
|
||||
impl AutoEntryScript {
|
||||
impl<D: DomTypes> GenericAutoEntryScript<D> {
|
||||
/// <https://html.spec.whatwg.org/multipage/#prepare-to-run-script>
|
||||
pub(crate) fn new(global: &GlobalScope) -> Self {
|
||||
STACK.with(|stack| {
|
||||
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,
|
||||
});
|
||||
AutoEntryScript {
|
||||
Self {
|
||||
global: DomRoot::from_ref(global),
|
||||
#[cfg(feature = "tracing")]
|
||||
span: tracing::info_span!(
|
||||
|
@ -71,14 +79,15 @@ impl AutoEntryScript {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for AutoEntryScript {
|
||||
impl<D: DomTypes> Drop for GenericAutoEntryScript<D> {
|
||||
/// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-script>
|
||||
fn drop(&mut self) {
|
||||
STACK.with(|stack| {
|
||||
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 GlobalScope, &*self.global as *const GlobalScope,
|
||||
&*entry.global as *const D::GlobalScope, &*self.global as *const D::GlobalScope,
|
||||
"Dropped AutoEntryScript out of order."
|
||||
);
|
||||
assert_eq!(entry.kind, StackEntryKind::Entry);
|
||||
|
@ -109,20 +118,24 @@ pub(crate) fn entry_global() -> DomRoot<GlobalScope> {
|
|||
}
|
||||
|
||||
/// RAII struct that pushes and pops entries from the script settings stack.
|
||||
pub(crate) struct AutoIncumbentScript {
|
||||
pub(crate) struct GenericAutoIncumbentScript<D: DomTypes> {
|
||||
global: usize,
|
||||
_marker: PhantomData<D>,
|
||||
}
|
||||
|
||||
impl AutoIncumbentScript {
|
||||
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: &GlobalScope) -> Self {
|
||||
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());
|
||||
}
|
||||
STACK.with(|stack| {
|
||||
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();
|
||||
|
@ -130,23 +143,25 @@ impl AutoIncumbentScript {
|
|||
global: Dom::from_ref(global),
|
||||
kind: StackEntryKind::Incumbent,
|
||||
});
|
||||
AutoIncumbentScript {
|
||||
Self {
|
||||
global: global as *const _ as usize,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AutoIncumbentScript {
|
||||
impl<D: DomTypes> Drop for GenericAutoIncumbentScript<D> {
|
||||
/// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-a-callback>
|
||||
fn drop(&mut self) {
|
||||
STACK.with(|stack| {
|
||||
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 GlobalScope as usize, self.global,
|
||||
&*entry.global as *const D::GlobalScope as usize, self.global,
|
||||
"Dropped AutoIncumbentScript out of order."
|
||||
);
|
||||
assert_eq!(entry.kind, StackEntryKind::Incumbent);
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
//! Various utilities to glue JavaScript and the DOM implementation together.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::OnceLock;
|
||||
use std::thread::LocalKey;
|
||||
use std::{ptr, slice, str};
|
||||
|
||||
use js::conversions::ToJSValConvertible;
|
||||
|
@ -44,6 +46,7 @@ use crate::dom::bindings::conversions::{
|
|||
};
|
||||
use crate::dom::bindings::error::{throw_dom_exception, throw_invalid_this, Error};
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::settings_stack::{self, StackEntry};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::bindings::trace::trace_object;
|
||||
use crate::dom::windowproxy::WindowProxyHandler;
|
||||
|
@ -676,6 +679,8 @@ pub(crate) trait DomHelpers<D: DomTypes> {
|
|||
creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
|
||||
can_gc: CanGc,
|
||||
) -> bool;
|
||||
|
||||
fn settings_stack() -> &'static LocalKey<RefCell<Vec<StackEntry<D>>>>;
|
||||
}
|
||||
|
||||
impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
|
||||
|
@ -699,4 +704,8 @@ impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
|
|||
) -> bool {
|
||||
call_html_constructor::<T>(cx, args, global, proto_id, creator, can_gc)
|
||||
}
|
||||
|
||||
fn settings_stack() -> &'static LocalKey<RefCell<Vec<StackEntry<crate::DomTypeHolder>>>> {
|
||||
&settings_stack::STACK
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,6 +205,7 @@ use crate::stylesheet_set::StylesheetSetRef;
|
|||
use crate::task::TaskBox;
|
||||
use crate::task_source::TaskSourceName;
|
||||
use crate::timers::OneshotTimerCallback;
|
||||
use crate::DomTypes;
|
||||
|
||||
/// The number of times we are allowed to see spurious `requestAnimationFrame()` calls before
|
||||
/// falling back to fake ones.
|
||||
|
@ -6214,3 +6215,13 @@ fn is_named_element_with_id_attribute(elem: &Element) -> bool {
|
|||
// behaviour is actually implemented
|
||||
elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
|
||||
}
|
||||
|
||||
pub(crate) trait DocumentHelpers<D: DomTypes> {
|
||||
fn ensure_safe_to_run_script_or_layout(&self);
|
||||
}
|
||||
|
||||
impl DocumentHelpers<crate::DomTypeHolder> for Document {
|
||||
fn ensure_safe_to_run_script_or_layout(&self) {
|
||||
Document::ensure_safe_to_run_script_or_layout(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ pub(crate) enum CommonEventHandler {
|
|||
}
|
||||
|
||||
impl CommonEventHandler {
|
||||
fn parent(&self) -> &CallbackFunction {
|
||||
fn parent(&self) -> &CallbackFunction<crate::DomTypeHolder> {
|
||||
match *self {
|
||||
CommonEventHandler::EventHandler(ref handler) => &handler.parent,
|
||||
CommonEventHandler::ErrorEventHandler(ref handler) => &handler.parent,
|
||||
|
@ -612,7 +612,7 @@ impl EventTarget {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn set_event_handler_common<T: CallbackContainer>(
|
||||
pub(crate) fn set_event_handler_common<T: CallbackContainer<crate::DomTypeHolder>>(
|
||||
&self,
|
||||
ty: &str,
|
||||
listener: Option<Rc<T>>,
|
||||
|
@ -628,7 +628,7 @@ impl EventTarget {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn set_error_event_handler<T: CallbackContainer>(
|
||||
pub(crate) fn set_error_event_handler<T: CallbackContainer<crate::DomTypeHolder>>(
|
||||
&self,
|
||||
ty: &str,
|
||||
listener: Option<Rc<T>>,
|
||||
|
@ -644,7 +644,7 @@ impl EventTarget {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn set_beforeunload_event_handler<T: CallbackContainer>(
|
||||
pub(crate) fn set_beforeunload_event_handler<T: CallbackContainer<crate::DomTypeHolder>>(
|
||||
&self,
|
||||
ty: &str,
|
||||
listener: Option<Rc<T>>,
|
||||
|
@ -660,7 +660,7 @@ impl EventTarget {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn get_event_handler_common<T: CallbackContainer>(
|
||||
pub(crate) fn get_event_handler_common<T: CallbackContainer<crate::DomTypeHolder>>(
|
||||
&self,
|
||||
ty: &str,
|
||||
can_gc: CanGc,
|
||||
|
|
|
@ -3348,6 +3348,10 @@ pub(crate) trait GlobalScopeHelpers<D: crate::DomTypes> {
|
|||
) -> DomRoot<D::GlobalScope>;
|
||||
|
||||
fn origin(&self) -> &MutableOrigin;
|
||||
|
||||
fn incumbent() -> Option<DomRoot<D::GlobalScope>>;
|
||||
|
||||
fn perform_a_microtask_checkpoint(&self, can_gc: CanGc);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -3375,4 +3379,12 @@ impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
|
|||
fn origin(&self) -> &MutableOrigin {
|
||||
GlobalScope::origin(self)
|
||||
}
|
||||
|
||||
fn incumbent() -> Option<DomRoot<Self>> {
|
||||
GlobalScope::incumbent()
|
||||
}
|
||||
|
||||
fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
|
||||
GlobalScope::perform_a_microtask_checkpoint(self, can_gc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'Document': {
|
||||
'additionalTraits': ["crate::dom::document::DocumentHelpers<Self>"],
|
||||
'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ElementFromPoint', 'ElementsFromPoint', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate'],
|
||||
},
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ def isDomInterface(t, logging=False):
|
|||
if isinstance(t, IDLInterface):
|
||||
return True
|
||||
if t.isCallback():
|
||||
return False
|
||||
return True
|
||||
return t.isInterface() and (t.isGeckoInterface() or (t.isSpiderMonkeyInterface() and not t.isBufferSource()))
|
||||
|
||||
|
||||
|
@ -866,7 +866,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
|||
|
||||
if descriptor.interface.isCallback():
|
||||
name = descriptor.nativeType
|
||||
declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">")
|
||||
declType = CGWrapper(CGGeneric(f"{name}<D>"), pre="Rc<", post=">")
|
||||
template = f"{name}::new(cx, ${{val}}.get().to_object())"
|
||||
if type.nullable():
|
||||
declType = CGWrapper(declType, pre="Option<", post=">")
|
||||
|
@ -1078,7 +1078,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
|||
assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
|
||||
|
||||
callback = type.unroll().callback
|
||||
declType = CGGeneric(callback.identifier.name)
|
||||
declType = CGGeneric(f"{callback.identifier.name}<D>")
|
||||
finalDeclType = CGTemplatedType("Rc", declType)
|
||||
|
||||
conversion = CGCallbackTempRoot(declType.define())
|
||||
|
@ -1508,7 +1508,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
|
|||
return result
|
||||
if returnType.isCallback():
|
||||
callback = returnType.unroll().callback
|
||||
result = CGGeneric(f'Rc<{getModuleFromObject(callback)}::{callback.identifier.name}>')
|
||||
result = CGGeneric(f'Rc<{getModuleFromObject(callback)}::{callback.identifier.name}<D>>')
|
||||
if returnType.nullable():
|
||||
result = CGWrapper(result, pre="Option<", post=">")
|
||||
return result
|
||||
|
@ -2611,7 +2611,7 @@ class CGGeneric(CGThing):
|
|||
|
||||
class CGCallbackTempRoot(CGGeneric):
|
||||
def __init__(self, name):
|
||||
CGGeneric.__init__(self, f"{name}::new(cx, ${{val}}.get().to_object())")
|
||||
CGGeneric.__init__(self, f"{name.replace('<D>', '::<D>')}::new(cx, ${{val}}.get().to_object())")
|
||||
|
||||
|
||||
def getAllTypes(descriptors, dictionaries, callbacks, typedefs):
|
||||
|
@ -5100,7 +5100,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
|
|||
typeName = f"typedarray::Heap{name}"
|
||||
elif type.isCallback():
|
||||
name = type.name
|
||||
typeName = name
|
||||
typeName = f"{name}<D>"
|
||||
else:
|
||||
raise TypeError(f"Can't handle {type} in unions yet")
|
||||
|
||||
|
@ -5571,8 +5571,9 @@ class ClassConstructor(ClassItem):
|
|||
body += '\n'
|
||||
body = f' {{\n{body}}}'
|
||||
|
||||
name = cgClass.getNameString().replace(': DomTypes', '')
|
||||
return f"""
|
||||
pub(crate) unsafe fn {self.getDecorators(True)}new({args}) -> Rc<{cgClass.getNameString()}>{body}
|
||||
pub(crate) unsafe fn {self.getDecorators(True)}new({args}) -> Rc<{name}>{body}
|
||||
"""
|
||||
|
||||
def define(self, cgClass):
|
||||
|
@ -5710,7 +5711,7 @@ class CGClass(CGThing):
|
|||
result = f"{result}{memberString}"
|
||||
|
||||
result += f'{self.indent}}}\n\n'
|
||||
result += f'impl {self.name} {{\n'
|
||||
result += f'impl{specialization} {self.name}{specialization.replace(": DomTypes", "")} {{\n'
|
||||
|
||||
order = [(self.constructors + disallowedCopyConstructors, '\n'),
|
||||
(self.destructors, '\n'), (self.methods, '\n)')]
|
||||
|
@ -7561,7 +7562,7 @@ class CGConcreteBindingRoot(CGThing):
|
|||
|
||||
cgthings += [CGGeneric(
|
||||
f"pub(crate) type {c.identifier.name} = "
|
||||
f"{originalBinding}::{c.identifier.name};"
|
||||
f"{originalBinding}::{c.identifier.name}<crate::DomTypeHolder>;"
|
||||
) for c in mainCallbacks]
|
||||
|
||||
cgthings += [CGGeneric(f"pub(crate) use {originalBinding} as GenericBindings;")]
|
||||
|
@ -7595,7 +7596,9 @@ pub(crate) fn GetConstructorObject(
|
|||
|
||||
for c in callbackDescriptors:
|
||||
ifaceName = c.interface.identifier.name
|
||||
cgthings += [CGGeneric(f"pub(crate) type {ifaceName} = {originalBinding}::{ifaceName};")]
|
||||
cgthings += [CGGeneric(
|
||||
f"pub(crate) type {ifaceName} = {originalBinding}::{ifaceName}<crate::DomTypeHolder>;"
|
||||
)]
|
||||
|
||||
# And make sure we have the right number of newlines at the end
|
||||
curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
|
||||
|
@ -7889,6 +7892,7 @@ class CGCallback(CGClass):
|
|||
bases=[ClassBase(baseName)],
|
||||
constructors=self.getConstructors(),
|
||||
methods=realMethods,
|
||||
templateSpecialization=['D: DomTypes'],
|
||||
decorators="#[derive(JSTraceable, PartialEq)]\n"
|
||||
"#[cfg_attr(crown, allow(crown::unrooted_must_root))]\n"
|
||||
"#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]")
|
||||
|
@ -7906,11 +7910,6 @@ class CGCallback(CGClass):
|
|||
def getMethodImpls(self, method):
|
||||
assert method.needThisHandling
|
||||
args = list(method.args)
|
||||
# Callbacks are not generic over DomTypes yet, so we need to manually
|
||||
# re-specialize any use of generics within these generated methods.
|
||||
for arg in args:
|
||||
arg.argType = arg.argType.replace('D::', '').replace('<D>', '<crate::DomTypeHolder>')
|
||||
method.returnType = method.returnType.replace('D::', '')
|
||||
# Strip out the JSContext*/JSObject* args
|
||||
# that got added.
|
||||
assert args[0].name == "cx" and args[0].argType == "SafeJSContext"
|
||||
|
@ -7936,7 +7935,7 @@ class CGCallback(CGClass):
|
|||
args.insert(0, Argument(None, "&self"))
|
||||
argsWithoutThis.insert(0, Argument(None, "&self"))
|
||||
|
||||
setupCall = "let s = CallSetup::new(self, aExceptionHandling);\n"
|
||||
setupCall = "let s = CallSetup::<D>::new(self, aExceptionHandling);\n"
|
||||
|
||||
bodyWithThis = (
|
||||
f"{setupCall}rooted!(in(*s.get_context()) let mut thisValue: JSVal);\n"
|
||||
|
@ -7948,15 +7947,14 @@ class CGCallback(CGClass):
|
|||
bodyWithoutThis = (
|
||||
f"{setupCall}\n"
|
||||
f"unsafe {{ self.{method.name}({', '.join(argnamesWithoutThis)}) }}")
|
||||
method.body = method.body.replace('D::', '').replace('<D as DomHelpers<D>>::', '')
|
||||
return [ClassMethod(f'{method.name}_', method.returnType, args,
|
||||
bodyInHeader=True,
|
||||
templateArgs=["T: ThisReflector"],
|
||||
body=bodyWithThis.replace('D::', ''),
|
||||
body=bodyWithThis,
|
||||
visibility='pub'),
|
||||
ClassMethod(f'{method.name}__', method.returnType, argsWithoutThis,
|
||||
bodyInHeader=True,
|
||||
body=bodyWithoutThis.replace('D::', ''),
|
||||
body=bodyWithoutThis,
|
||||
visibility='pub'),
|
||||
method]
|
||||
|
||||
|
@ -7976,7 +7974,7 @@ def callbackSetterName(attr, descriptor):
|
|||
class CGCallbackFunction(CGCallback):
|
||||
def __init__(self, callback, descriptorProvider):
|
||||
CGCallback.__init__(self, callback, descriptorProvider,
|
||||
"CallbackFunction",
|
||||
"CallbackFunction<D>",
|
||||
methods=[CallCallback(callback, descriptorProvider)])
|
||||
|
||||
def getConstructors(self):
|
||||
|
@ -7985,23 +7983,23 @@ class CGCallbackFunction(CGCallback):
|
|||
|
||||
class CGCallbackFunctionImpl(CGGeneric):
|
||||
def __init__(self, callback):
|
||||
type = callback.identifier.name
|
||||
type = f"{callback.identifier.name}<D>"
|
||||
impl = (f"""
|
||||
impl CallbackContainer for {type} {{
|
||||
impl<D: DomTypes> CallbackContainer<D> for {type} {{
|
||||
unsafe fn new(cx: SafeJSContext, callback: *mut JSObject) -> Rc<{type}> {{
|
||||
{type}::new(cx, callback)
|
||||
{type.replace('<D>', '')}::new(cx, callback)
|
||||
}}
|
||||
|
||||
fn callback_holder(&self) -> &CallbackObject {{
|
||||
fn callback_holder(&self) -> &CallbackObject<D> {{
|
||||
self.parent.callback_holder()
|
||||
}}
|
||||
}}
|
||||
|
||||
impl ToJSValConvertible for {type} {{
|
||||
impl<D: DomTypes> ToJSValConvertible for {type} {{
|
||||
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {{
|
||||
self.callback().to_jsval(cx, rval);
|
||||
}}
|
||||
}}\
|
||||
}}
|
||||
""")
|
||||
CGGeneric.__init__(self, impl)
|
||||
|
||||
|
@ -8016,7 +8014,7 @@ class CGCallbackInterface(CGCallback):
|
|||
methods = [CallbackOperation(m, sig, descriptor) for m in methods
|
||||
for sig in m.signatures()]
|
||||
assert not iface.isJSImplemented() or not iface.ctor()
|
||||
CGCallback.__init__(self, iface, descriptor, "CallbackInterface", methods)
|
||||
CGCallback.__init__(self, iface, descriptor, "CallbackInterface<D>", methods)
|
||||
|
||||
|
||||
class FakeMember():
|
||||
|
|
|
@ -228,9 +228,9 @@ class Descriptor(DescriptorProvider):
|
|||
self.nativeType = typeName
|
||||
pathDefault = 'crate::dom::types::%s' % typeName
|
||||
elif self.interface.isCallback():
|
||||
ty = 'crate::dom::bindings::codegen::Bindings::%sBinding::%s' % (ifaceName, ifaceName)
|
||||
ty = 'crate::dom::bindings::codegen::GenericBindings::%sBinding::%s' % (ifaceName, ifaceName)
|
||||
pathDefault = ty
|
||||
self.returnType = "Rc<%s>" % ty
|
||||
self.returnType = "Rc<%s<D>>" % ty
|
||||
self.argumentType = "???"
|
||||
self.nativeType = ty
|
||||
else:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue