From 83b1ead1e7d5d188a0c20a69e3d98c0d4971cd7e Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Wed, 20 Aug 2025 00:59:03 +0100 Subject: [PATCH] LibWeb: Ensure `UIEventInit.view` is set for mouse and pointer events --- Libraries/LibWeb/DOM/Document.cpp | 4 ++ Libraries/LibWeb/Page/EventHandler.cpp | 24 +++++----- Libraries/LibWeb/UIEvents/MouseEvent.cpp | 3 +- Libraries/LibWeb/UIEvents/MouseEvent.h | 2 +- Libraries/LibWeb/UIEvents/PointerEvent.cpp | 3 +- Libraries/LibWeb/UIEvents/PointerEvent.h | 2 +- Libraries/LibWeb/UIEvents/WheelEvent.cpp | 3 +- Libraries/LibWeb/UIEvents/WheelEvent.h | 2 +- .../expected/UIEvents/UIEventInit-view.txt | 11 +++++ .../Text/input/UIEvents/UIEventInit-view.html | 45 +++++++++++++++++++ 10 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/UIEvents/UIEventInit-view.txt create mode 100644 Tests/LibWeb/Text/input/UIEvents/UIEventInit-view.html diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 2e86d993693..c539b602212 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1908,6 +1908,8 @@ void Document::set_hovered_node(GC::Ptr node) mouse_event_init.cancelable = true; mouse_event_init.composed = true; mouse_event_init.related_target = m_hovered_node; + if (auto navigable = this->navigable()) + mouse_event_init.view = navigable->active_window_proxy(); auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseout, mouse_event_init); old_hovered_node->dispatch_event(event); } @@ -1930,6 +1932,8 @@ void Document::set_hovered_node(GC::Ptr node) mouse_event_init.cancelable = true; mouse_event_init.composed = true; mouse_event_init.related_target = old_hovered_node; + if (auto navigable = this->navigable()) + mouse_event_init.view = navigable->active_window_proxy(); auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseover, mouse_event_init); m_hovered_node->dispatch_event(event); } diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index cb80ba8261a..263fbd8b090 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -433,7 +433,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS auto page_offset = compute_mouse_event_page_offset(viewport_position); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); - if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::wheel, screen_position, page_offset, viewport_position, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) { + if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::wheel, screen_position, page_offset, viewport_position, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) { m_navigable->active_window()->scroll_by(wheel_delta_x, wheel_delta_y); } @@ -498,22 +498,22 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix auto page_offset = compute_mouse_event_page_offset(viewport_position); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); - auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::pointerup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors(); + auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::pointerup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors(); light_dismiss_activities(pointer_event, node); node->dispatch_event(pointer_event); - node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::mouseup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); handled_event = EventResult::Handled; bool run_activation_behavior = false; if (node.ptr() == m_mousedown_target) { if (button == UIEvents::MouseButton::Primary) { - run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); } else if (button == UIEvents::MouseButton::Middle) { - run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::auxclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::auxclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); } else if (button == UIEvents::MouseButton::Secondary) { // Allow the user to bypass custom context menus by holding shift, like Firefox. if ((modifiers & UIEvents::Mod_Shift) == 0) - run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); else run_activation_behavior = true; } @@ -576,7 +576,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix if (auto input_control = input_control_associated_with_ancestor_label_element(*paintable)) { if (button == UIEvents::MouseButton::Primary && input_control != node) { - input_control->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + input_control->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); } } } @@ -651,10 +651,10 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP m_mousedown_target = node.ptr(); auto page_offset = compute_mouse_event_page_offset(viewport_position); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); - auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::pointerdown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors(); + auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::pointerdown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors(); light_dismiss_activities(pointer_event, node); node->dispatch_event(pointer_event); - node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::mousedown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); } // NOTE: Dispatching an event may have disturbed the world. @@ -802,10 +802,10 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP m_mousemove_previous_screen_position = screen_position; - bool continue_ = node->dispatch_event(UIEvents::PointerEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::pointermove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + bool continue_ = node->dispatch_event(UIEvents::PointerEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::pointermove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); if (!continue_) return EventResult::Cancelled; - continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::mousemove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); if (!continue_) return EventResult::Cancelled; @@ -959,7 +959,7 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS auto page_offset = compute_mouse_event_page_offset(viewport_position); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); - node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); + node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::dblclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); // NOTE: Dispatching an event may have disturbed the world. if (!paint_root() || paint_root() != node->document().paintable_box()) diff --git a/Libraries/LibWeb/UIEvents/MouseEvent.cpp b/Libraries/LibWeb/UIEvents/MouseEvent.cpp index 5db9422a090..882718d2065 100644 --- a/Libraries/LibWeb/UIEvents/MouseEvent.cpp +++ b/Libraries/LibWeb/UIEvents/MouseEvent.cpp @@ -133,7 +133,7 @@ WebIDL::ExceptionOr> MouseEvent::construct_impl(JS::Realm& r return create(realm, event_name, event_init); } -WebIDL::ExceptionOr> MouseEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers) +WebIDL::ExceptionOr> MouseEvent::create_from_platform_event(JS::Realm& realm, GC::Ptr window_proxy, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers) { MouseEventInit event_init {}; event_init.ctrl_key = modifiers & Mod_Ctrl; @@ -144,6 +144,7 @@ WebIDL::ExceptionOr> MouseEvent::create_from_platform_event( event_init.screen_y = screen.y().to_double(); event_init.client_x = client.x().to_double(); event_init.client_y = client.y().to_double(); + event_init.view = window_proxy; if (movement.has_value()) { event_init.movement_x = movement.value().x().to_double(); event_init.movement_y = movement.value().y().to_double(); diff --git a/Libraries/LibWeb/UIEvents/MouseEvent.h b/Libraries/LibWeb/UIEvents/MouseEvent.h index 16b393154c7..f12bd0e0de7 100644 --- a/Libraries/LibWeb/UIEvents/MouseEvent.h +++ b/Libraries/LibWeb/UIEvents/MouseEvent.h @@ -31,7 +31,7 @@ class MouseEvent : public UIEvent { public: [[nodiscard]] static GC::Ref create(JS::Realm&, FlyString const& event_name, MouseEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); - static WebIDL::ExceptionOr> create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers); + static WebIDL::ExceptionOr> create_from_platform_event(JS::Realm&, GC::Ptr, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers); static WebIDL::ExceptionOr> construct_impl(JS::Realm&, FlyString const& event_name, MouseEventInit const&); virtual ~MouseEvent() override; diff --git a/Libraries/LibWeb/UIEvents/PointerEvent.cpp b/Libraries/LibWeb/UIEvents/PointerEvent.cpp index dc5df5fb823..839bc346630 100644 --- a/Libraries/LibWeb/UIEvents/PointerEvent.cpp +++ b/Libraries/LibWeb/UIEvents/PointerEvent.cpp @@ -11,7 +11,7 @@ namespace Web::UIEvents { GC_DEFINE_ALLOCATOR(PointerEvent); -WebIDL::ExceptionOr> PointerEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers) +WebIDL::ExceptionOr> PointerEvent::create_from_platform_event(JS::Realm& realm, GC::Ptr window_proxy, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers) { PointerEventInit event_init {}; event_init.ctrl_key = modifiers & Mod_Ctrl; @@ -22,6 +22,7 @@ WebIDL::ExceptionOr> PointerEvent::create_from_platform_ev event_init.screen_y = screen.y().to_double(); event_init.client_x = client.x().to_double(); event_init.client_y = client.y().to_double(); + event_init.view = window_proxy; if (movement.has_value()) { event_init.movement_x = movement.value().x().to_double(); event_init.movement_y = movement.value().y().to_double(); diff --git a/Libraries/LibWeb/UIEvents/PointerEvent.h b/Libraries/LibWeb/UIEvents/PointerEvent.h index cabca7b8a45..0b26f938ca4 100644 --- a/Libraries/LibWeb/UIEvents/PointerEvent.h +++ b/Libraries/LibWeb/UIEvents/PointerEvent.h @@ -36,7 +36,7 @@ class PointerEvent : public MouseEvent { public: [[nodiscard]] static GC::Ref create(JS::Realm&, FlyString const& type, PointerEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); - [[nodiscard]] static WebIDL::ExceptionOr> create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers); + [[nodiscard]] static WebIDL::ExceptionOr> create_from_platform_event(JS::Realm&, GC::Ptr, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional movement, unsigned button, unsigned buttons, unsigned modifiers); static WebIDL::ExceptionOr> construct_impl(JS::Realm&, FlyString const& type, PointerEventInit const&); virtual ~PointerEvent() override; diff --git a/Libraries/LibWeb/UIEvents/WheelEvent.cpp b/Libraries/LibWeb/UIEvents/WheelEvent.cpp index 1cdf022410a..b1816abefc0 100644 --- a/Libraries/LibWeb/UIEvents/WheelEvent.cpp +++ b/Libraries/LibWeb/UIEvents/WheelEvent.cpp @@ -43,7 +43,7 @@ GC::Ref WheelEvent::create(JS::Realm& realm, FlyString const& event_ return realm.create(realm, event_name, event_init, page_x, page_y, offset_x, offset_y); } -WebIDL::ExceptionOr> WheelEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers) +WebIDL::ExceptionOr> WheelEvent::create_from_platform_event(JS::Realm& realm, GC::Ptr window_proxy, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers) { WheelEventInit event_init {}; event_init.ctrl_key = modifiers & Mod_Ctrl; @@ -59,6 +59,7 @@ WebIDL::ExceptionOr> WheelEvent::create_from_platform_event( event_init.delta_x = delta_x; event_init.delta_y = delta_y; event_init.delta_mode = WheelDeltaMode::DOM_DELTA_PIXEL; + event_init.view = window_proxy; auto event = WheelEvent::create(realm, event_name, event_init, page.x().to_double(), page.y().to_double(), offset.x().to_double(), offset.y().to_double()); event->set_is_trusted(true); event->set_bubbles(true); diff --git a/Libraries/LibWeb/UIEvents/WheelEvent.h b/Libraries/LibWeb/UIEvents/WheelEvent.h index ac28fd7f8b9..b8b8d842ea1 100644 --- a/Libraries/LibWeb/UIEvents/WheelEvent.h +++ b/Libraries/LibWeb/UIEvents/WheelEvent.h @@ -34,7 +34,7 @@ public: [[nodiscard]] static GC::Ref create(JS::Realm&, FlyString const& event_name, WheelEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); [[nodiscard]] static GC::Ref construct_impl(JS::Realm&, FlyString const& event_name, WheelEventInit const& = {}); - static WebIDL::ExceptionOr> create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers); + static WebIDL::ExceptionOr> create_from_platform_event(JS::Realm&, GC::Ptr, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers); virtual ~WheelEvent() override; diff --git a/Tests/LibWeb/Text/expected/UIEvents/UIEventInit-view.txt b/Tests/LibWeb/Text/expected/UIEvents/UIEventInit-view.txt new file mode 100644 index 00000000000..6105f2955c8 --- /dev/null +++ b/Tests/LibWeb/Text/expected/UIEvents/UIEventInit-view.txt @@ -0,0 +1,11 @@ +click event view is set to the active window: true +dblclick event view is set to the active window: true +mousedown event view is set to the active window: true +pointerdown event view is set to the active window: true +mouseup event view is set to the active window: true +pointerup event view is set to the active window: true +mousemove event view is set to the active window: true +pointermove event view is set to the active window: true +mouseover event view is set to the active window: true +mouseout event view is set to the active window: true +wheel event view is set to the active window: true diff --git a/Tests/LibWeb/Text/input/UIEvents/UIEventInit-view.html b/Tests/LibWeb/Text/input/UIEvents/UIEventInit-view.html new file mode 100644 index 00000000000..3a6e1b91e2d --- /dev/null +++ b/Tests/LibWeb/Text/input/UIEvents/UIEventInit-view.html @@ -0,0 +1,45 @@ + + + + +