From 0639e778986877ef0a6883eb9011ad8b4f56b642 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 18 Jan 2021 12:15:02 +0100 Subject: [PATCH] LibWeb: Make the Window object "inherit" from EventTarget :^) Since Web::Bindings::WindowObject inherits from JS::GlobalObject, it cannot also inherit from Web::Bindings::EventTargetWrapper. However, that's not actually necessary. Instead, we simply set the Window object's prototype to the EventTargetPrototype, and add a little extra branch in the impl_from() function that turns the JS "this" value into a DOM::EventTarget*. With this, you can now call window.addEventListener()! Very cool :^) Fixes #4758. --- .../LibWeb/Bindings/EventTargetWrapperFactory.cpp | 2 +- .../LibWeb/Bindings/EventTargetWrapperFactory.h | 2 +- .../Libraries/LibWeb/Bindings/WindowObject.cpp | 2 ++ .../LibWeb/CodeGenerators/WrapperGenerator.cpp | 14 ++++++++++++-- Userland/Libraries/LibWeb/DOM/EventTarget.h | 2 +- Userland/Libraries/LibWeb/DOM/Node.cpp | 2 +- Userland/Libraries/LibWeb/DOM/Node.h | 2 +- Userland/Libraries/LibWeb/DOM/Window.cpp | 4 ++-- Userland/Libraries/LibWeb/DOM/Window.h | 2 +- Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp | 2 +- Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h | 2 +- .../LibWeb/HighResolutionTime/Performance.cpp | 2 +- .../LibWeb/HighResolutionTime/Performance.h | 2 +- 13 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp b/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp index 4a6e6344e9c..a7152b522c9 100644 --- a/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp +++ b/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp @@ -29,7 +29,7 @@ namespace Web::Bindings { -EventTargetWrapper* wrap(JS::GlobalObject& global_object, DOM::EventTarget& target) +JS::Object* wrap(JS::GlobalObject& global_object, DOM::EventTarget& target) { return target.create_wrapper(global_object); } diff --git a/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h b/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h index c28c7724ca7..193c2d812d0 100644 --- a/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h +++ b/Userland/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h @@ -31,6 +31,6 @@ namespace Web::Bindings { -EventTargetWrapper* wrap(JS::GlobalObject&, DOM::EventTarget&); +JS::Object* wrap(JS::GlobalObject&, DOM::EventTarget&); } diff --git a/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp b/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp index b4e27233dcc..072b494370c 100644 --- a/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp +++ b/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp @@ -67,6 +67,8 @@ void WindowObject::initialize() { GlobalObject::initialize(); + set_prototype(&ensure_web_prototype("EventTarget")); + define_property("window", this, JS::Attribute::Enumerable); define_property("frames", this, JS::Attribute::Enumerable); define_property("self", this, JS::Attribute::Enumerable); diff --git a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp index d008fc41ad9..7578776aec8 100644 --- a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp +++ b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp @@ -840,6 +840,7 @@ void generate_prototype_implementation(const IDL::Interface& interface) #include #include #include +#include #include #include @@ -927,9 +928,18 @@ static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_ob auto* this_object = vm.this_value(global_object).to_object(global_object); if (!this_object) return {}; +)~~~"); + + if (interface.name == "EventTarget") { + generator.append(R"~~~( + if (is(this_object)) { + return &static_cast(this_object)->impl(); + } +)~~~"); + } + + generator.append(R"~~~( if (!is<@wrapper_class@>(this_object)) { - dbgln("expected @wrapper_class@ but got {}", this_object->class_name()); - ASSERT_NOT_REACHED(); vm.throw_exception(global_object, JS::ErrorType::NotA, "@fully_qualified_name@"); return nullptr; } diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.h b/Userland/Libraries/LibWeb/DOM/EventTarget.h index 32399a6a7a1..f03d4a4fb2e 100644 --- a/Userland/Libraries/LibWeb/DOM/EventTarget.h +++ b/Userland/Libraries/LibWeb/DOM/EventTarget.h @@ -51,7 +51,7 @@ public: void remove_from_event_listener_list(NonnullRefPtr); virtual bool dispatch_event(NonnullRefPtr) = 0; - virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) = 0; + virtual JS::Object* create_wrapper(JS::GlobalObject&) = 0; Bindings::ScriptExecutionContext* script_execution_context() { return m_script_execution_context; } virtual EventTarget* get_parent(const Event&) { return nullptr; } diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 6890e4fda57..9bfe3aeccad 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -213,7 +213,7 @@ bool Node::is_editable() const return parent() && parent()->is_editable(); } -Bindings::EventTargetWrapper* Node::create_wrapper(JS::GlobalObject& global_object) +JS::Object* Node::create_wrapper(JS::GlobalObject& global_object) { return wrap(global_object, *this); } diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index d3eaab1b8b1..d29f0a471fa 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -61,7 +61,7 @@ public: virtual void ref_event_target() final { ref(); } virtual void unref_event_target() final { unref(); } virtual bool dispatch_event(NonnullRefPtr) final; - virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override; + virtual JS::Object* create_wrapper(JS::GlobalObject&) override; virtual ~Node(); diff --git a/Userland/Libraries/LibWeb/DOM/Window.cpp b/Userland/Libraries/LibWeb/DOM/Window.cpp index d10620bc1eb..648d0836965 100644 --- a/Userland/Libraries/LibWeb/DOM/Window.cpp +++ b/Userland/Libraries/LibWeb/DOM/Window.cpp @@ -169,9 +169,9 @@ bool Window::dispatch_event(NonnullRefPtr event) return EventDispatcher::dispatch(*this, event, true); } -Bindings::EventTargetWrapper* Window::create_wrapper(JS::GlobalObject&) +JS::Object* Window::create_wrapper(JS::GlobalObject& global_object) { - ASSERT_NOT_REACHED(); + return &global_object; } } diff --git a/Userland/Libraries/LibWeb/DOM/Window.h b/Userland/Libraries/LibWeb/DOM/Window.h index 4118bebbe24..725da546d75 100644 --- a/Userland/Libraries/LibWeb/DOM/Window.h +++ b/Userland/Libraries/LibWeb/DOM/Window.h @@ -50,7 +50,7 @@ public: virtual void ref_event_target() override { RefCounted::ref(); } virtual void unref_event_target() override { RefCounted::unref(); } virtual bool dispatch_event(NonnullRefPtr) override; - virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override; + virtual JS::Object* create_wrapper(JS::GlobalObject&) override; const Document& document() const { return m_document; } Document& document() { return m_document; } diff --git a/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp b/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp index e763a2f3377..a6485d33f41 100644 --- a/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp +++ b/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp @@ -113,7 +113,7 @@ bool XMLHttpRequest::dispatch_event(NonnullRefPtr event) return DOM::EventDispatcher::dispatch(*this, move(event)); } -Bindings::EventTargetWrapper* XMLHttpRequest::create_wrapper(JS::GlobalObject& global_object) +JS::Object* XMLHttpRequest::create_wrapper(JS::GlobalObject& global_object) { return wrap(global_object, *this); } diff --git a/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h b/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h index 33a60388634..2bb7b73e282 100644 --- a/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h +++ b/Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h @@ -66,7 +66,7 @@ private: virtual void ref_event_target() override { ref(); } virtual void unref_event_target() override { unref(); } virtual bool dispatch_event(NonnullRefPtr) override; - virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override; + virtual JS::Object* create_wrapper(JS::GlobalObject&) override; void set_ready_state(ReadyState); diff --git a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp index cdefa63effc..1de64d81fb7 100644 --- a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp +++ b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp @@ -65,7 +65,7 @@ bool Performance::dispatch_event(NonnullRefPtr event) return DOM::EventDispatcher::dispatch(*this, event); } -Bindings::EventTargetWrapper* Performance::create_wrapper(JS::GlobalObject& global_object) +JS::Object* Performance::create_wrapper(JS::GlobalObject& global_object) { return Bindings::wrap(global_object, *this); } diff --git a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h index d5a9effbf55..7848beedccd 100644 --- a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h +++ b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h @@ -50,7 +50,7 @@ public: virtual void unref_event_target() override; virtual bool dispatch_event(NonnullRefPtr) override; - virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override; + virtual JS::Object* create_wrapper(JS::GlobalObject&) override; private: DOM::Window& m_window;