diff options
-rw-r--r-- | components/script/dom/bindings/callback.rs | 82 | ||||
-rw-r--r-- | components/script/dom/bindings/settings_stack.rs | 57 | ||||
-rw-r--r-- | components/script/dom/bindings/utils.rs | 9 | ||||
-rw-r--r-- | components/script/dom/document.rs | 11 | ||||
-rw-r--r-- | components/script/dom/eventtarget.rs | 10 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 12 | ||||
-rw-r--r-- | components/script_bindings/codegen/Bindings.conf | 1 | ||||
-rw-r--r-- | components/script_bindings/codegen/CodegenRust.py | 52 | ||||
-rw-r--r-- | components/script_bindings/codegen/Configuration.py | 4 |
9 files changed, 141 insertions, 97 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index a33cc49e8f0..bd73ec37d52 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -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); diff --git a/components/script/dom/bindings/settings_stack.rs b/components/script/dom/bindings/settings_stack.rs index 28e48ea4d93..1f566a59052 100644 --- a/components/script/dom/bindings/settings_stack.rs +++ b/components/script/dom/bindings/settings_stack.rs @@ -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); diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 631ba43c4d5..b3f3219cf1a 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -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 + } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 5307a6f29cd..e7a0e6813b8 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -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) + } +} diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index 0d879bca452..b66a54cb5a5 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -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, diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index b16e404ccbd..4cc27bea3f0 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -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) + } } diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index ae6ee4a5617..23a26d98f39 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -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'], }, diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py index b6c223ff53a..06f993d8b5d 100644 --- a/components/script_bindings/codegen/CodegenRust.py +++ b/components/script_bindings/codegen/CodegenRust.py @@ -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(): diff --git a/components/script_bindings/codegen/Configuration.py b/components/script_bindings/codegen/Configuration.py index 3f7b9ad6d9b..a4a6a538fdc 100644 --- a/components/script_bindings/codegen/Configuration.py +++ b/components/script_bindings/codegen/Configuration.py @@ -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: |