From 61e18c681baacca25dffadeab688730402b6c443 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Tue, 23 Aug 2022 17:44:31 +0100 Subject: [PATCH] LibWeb: Restore realm retrieval from 'this' in activate_event_handler() Removing the FIXME'd code in b99cc7d was a bit too eager, and relying on the main thread VM's current realm only works when JS is being executed. Restore a simplified version of the old code to determine the realm this time instead of the global object, following the assumptions already made in get_current_value_of_event_handler() regarding what kind of event target 'this' can be. --- Userland/Libraries/LibWeb/DOM/EventTarget.cpp | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp index ab622f323f..3c4851390c 100644 --- a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp @@ -506,8 +506,6 @@ void EventTarget::set_event_handler_attribute(FlyString const& name, Optional()) { + realm = &event_handler.value.get().callback_context.realm(); + } else if (is(this)) { + realm = &verify_cast(*this).document().realm(); + } else { + auto& window = verify_cast(*this); + // If an element attribute is set on a element before any script is run, Window::wrapper() will be null. + // Force creation of the global object via the Document::interpreter() lazy initialization mechanism. + if (window.wrapper() == nullptr) + window.associated_document().interpreter(); + realm = &window.wrapper()->shape().realm(); + } + VERIFY(realm); + // 4. Let callback be the result of creating a Web IDL EventListener instance representing a reference to a function of one argument that executes the steps of the event handler processing algorithm, given eventTarget, name, and its argument. // The EventListener's callback context can be arbitrary; it does not impact the steps of the event handler processing algorithm. [DOM] @@ -524,22 +538,24 @@ void EventTarget::activate_event_handler(FlyString const& name, HTML::EventHandl // document.body.remove(); // location.reload(); // The body element is no longer in the DOM and there is no variable holding onto it. However, the onunload handler is still called, meaning the callback keeps the body element alive. - auto callback_function = JS::NativeFunction::create(realm, "", [event_target = NonnullRefPtr(*this), name](JS::VM& vm) mutable -> JS::ThrowCompletionOr { - // The event dispatcher should only call this with one argument. - VERIFY(vm.argument_count() == 1); + auto callback_function = JS::NativeFunction::create( + *realm, [event_target = NonnullRefPtr(*this), name](JS::VM& vm) mutable -> JS::ThrowCompletionOr { + // The event dispatcher should only call this with one argument. + VERIFY(vm.argument_count() == 1); - // The argument must be an object and it must be an EventWrapper. - auto event_wrapper_argument = vm.argument(0); - VERIFY(event_wrapper_argument.is_object()); - auto& event_wrapper = verify_cast(event_wrapper_argument.as_object()); - auto& event = event_wrapper.impl(); + // The argument must be an object and it must be an EventWrapper. + auto event_wrapper_argument = vm.argument(0); + VERIFY(event_wrapper_argument.is_object()); + auto& event_wrapper = verify_cast(event_wrapper_argument.as_object()); + auto& event = event_wrapper.impl(); - TRY(event_target->process_event_handler_for_event(name, event)); - return JS::js_undefined(); - }); + TRY(event_target->process_event_handler_for_event(name, event)); + return JS::js_undefined(); + }, + 0, "", realm); // NOTE: As per the spec, the callback context is arbitrary. - Bindings::CallbackType callback { JS::make_handle(static_cast(callback_function)), verify_cast(*realm.host_defined()) }; + Bindings::CallbackType callback { JS::make_handle(static_cast(callback_function)), verify_cast(*realm->host_defined()) }; // 5. Let listener be a new event listener whose type is the event handler event type corresponding to eventHandler and callback is callback. auto listener = adopt_ref(*new DOMEventListener);