Browse Source

LibWeb: Support MouseEvent.{pageX,pageY}

Unlike client{X,Y} which is relative to the current viewport, these
offsets are relative to the left edge of the document (i.e they take
scroll offset into account).
Itamar 2 years ago
parent
commit
a802fb2023

+ 21 - 6
Userland/Libraries/LibWeb/Page/EventHandler.cpp

@@ -248,12 +248,13 @@ bool EventHandler::handle_mouseup(CSSPixelPoint position, unsigned button, unsig
 
 
             auto offset = compute_mouse_event_offset(position, *layout_node);
             auto offset = compute_mouse_event_offset(position, *layout_node);
             auto client_offset = compute_mouse_event_client_offset(position);
             auto client_offset = compute_mouse_event_client_offset(position);
-            node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, offset, client_offset, buttons, button));
+            auto page_offset = compute_mouse_event_page_offset(client_offset);
+            node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, offset, client_offset, page_offset, buttons, button));
             handled_event = true;
             handled_event = true;
 
 
             bool run_activation_behavior = true;
             bool run_activation_behavior = true;
             if (node.ptr() == m_mousedown_target && button == GUI::MouseButton::Primary) {
             if (node.ptr() == m_mousedown_target && button == GUI::MouseButton::Primary) {
-                run_activation_behavior = node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, offset, client_offset, button));
+                run_activation_behavior = node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, offset, client_offset, page_offset, button));
             }
             }
 
 
             if (run_activation_behavior) {
             if (run_activation_behavior) {
@@ -370,7 +371,8 @@ bool EventHandler::handle_mousedown(CSSPixelPoint position, unsigned button, uns
         m_mousedown_target = node.ptr();
         m_mousedown_target = node.ptr();
         auto offset = compute_mouse_event_offset(position, *layout_node);
         auto offset = compute_mouse_event_offset(position, *layout_node);
         auto client_offset = compute_mouse_event_client_offset(position);
         auto client_offset = compute_mouse_event_client_offset(position);
-        node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, offset, client_offset, buttons, button));
+        auto page_offset = compute_mouse_event_page_offset(client_offset);
+        node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, offset, client_offset, page_offset, buttons, button));
     }
     }
 
 
     // NOTE: Dispatching an event may have disturbed the world.
     // NOTE: Dispatching an event may have disturbed the world.
@@ -483,7 +485,8 @@ bool EventHandler::handle_mousemove(CSSPixelPoint position, unsigned buttons, un
 
 
             auto offset = compute_mouse_event_offset(position, *layout_node);
             auto offset = compute_mouse_event_offset(position, *layout_node);
             auto client_offset = compute_mouse_event_client_offset(position);
             auto client_offset = compute_mouse_event_client_offset(position);
-            node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, offset, client_offset, buttons));
+            auto page_offset = compute_mouse_event_page_offset(client_offset);
+            node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, offset, client_offset, page_offset, buttons));
             // NOTE: Dispatching an event may have disturbed the world.
             // NOTE: Dispatching an event may have disturbed the world.
             if (!paint_root() || paint_root() != node->document().paint_box())
             if (!paint_root() || paint_root() != node->document().paint_box())
                 return true;
                 return true;
@@ -565,7 +568,8 @@ bool EventHandler::handle_doubleclick(CSSPixelPoint position, unsigned button, u
 
 
     auto offset = compute_mouse_event_offset(position, *layout_node);
     auto offset = compute_mouse_event_offset(position, *layout_node);
     auto client_offset = compute_mouse_event_client_offset(position);
     auto client_offset = compute_mouse_event_client_offset(position);
-    node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, offset, client_offset, buttons, button));
+    auto page_offset = compute_mouse_event_page_offset(client_offset);
+    node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, offset, client_offset, page_offset, buttons, button));
 
 
     // NOTE: Dispatching an event may have disturbed the world.
     // NOTE: Dispatching an event may have disturbed the world.
     if (!paint_root() || paint_root() != node->document().paint_box())
     if (!paint_root() || paint_root() != node->document().paint_box())
@@ -793,9 +797,20 @@ CSSPixelPoint EventHandler::compute_mouse_event_client_offset(CSSPixelPoint even
 {
 {
     // https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-clientx
     // https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-clientx
     // The clientX attribute must return the x-coordinate of the position where the event occurred relative to the origin of the viewport.
     // The clientX attribute must return the x-coordinate of the position where the event occurred relative to the origin of the viewport.
-    
+
     auto scroll_offset = m_browsing_context.viewport_scroll_offset();
     auto scroll_offset = m_browsing_context.viewport_scroll_offset();
     return event_page_position.translated(-scroll_offset.to_rounded<CSSPixels>());
     return event_page_position.translated(-scroll_offset.to_rounded<CSSPixels>());
 }
 }
 
 
+CSSPixelPoint EventHandler::compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const
+{
+    // https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-pagex
+    // FIXME: 1. If the event’s dispatch flag is set, return the horizontal coordinate of the position where the event occurred relative to the origin of the initial containing block and terminate these steps.
+
+    // 2. Let offset be the value of the scrollX attribute of the event’s associated Window object, if there is one, or zero otherwise.
+    auto scroll_offset = m_browsing_context.viewport_scroll_offset();
+
+    // 3. Return the sum of offset and the value of the event’s clientX attribute.
+    return event_client_offset.translated(scroll_offset.to_rounded<CSSPixels>());
+}
 }
 }

+ 1 - 0
Userland/Libraries/LibWeb/Page/EventHandler.h

@@ -42,6 +42,7 @@ private:
 
 
     bool fire_keyboard_event(FlyString const& event_name, HTML::BrowsingContext& browsing_context, KeyCode key, unsigned modifiers, u32 code_point);
     bool fire_keyboard_event(FlyString const& event_name, HTML::BrowsingContext& browsing_context, KeyCode key, unsigned modifiers, u32 code_point);
     CSSPixelPoint compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const;
     CSSPixelPoint compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const;
+    CSSPixelPoint compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const;
 
 
     Layout::InitialContainingBlock* layout_root();
     Layout::InitialContainingBlock* layout_root();
     Layout::InitialContainingBlock const* layout_root() const;
     Layout::InitialContainingBlock const* layout_root() const;

+ 5 - 1
Userland/Libraries/LibWeb/UIEvents/MouseEvent.cpp

@@ -19,6 +19,8 @@ MouseEvent::MouseEvent(JS::Realm& realm, FlyString const& event_name, MouseEvent
     , m_offset_y(event_init.offset_y)
     , m_offset_y(event_init.offset_y)
     , m_client_x(event_init.client_x)
     , m_client_x(event_init.client_x)
     , m_client_y(event_init.client_y)
     , m_client_y(event_init.client_y)
+    , m_page_x(event_init.page_x)
+    , m_page_y(event_init.page_y)
     , m_button(event_init.button)
     , m_button(event_init.button)
     , m_buttons(event_init.buttons)
     , m_buttons(event_init.buttons)
 {
 {
@@ -52,13 +54,15 @@ MouseEvent* MouseEvent::create(JS::Realm& realm, FlyString const& event_name, Mo
     return realm.heap().allocate<MouseEvent>(realm, realm, event_name, event_init);
     return realm.heap().allocate<MouseEvent>(realm, realm, event_name, event_init);
 }
 }
 
 
-MouseEvent* MouseEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint offset, CSSPixelPoint client_offset, unsigned buttons, unsigned mouse_button)
+MouseEvent* MouseEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint offset, CSSPixelPoint client_offset, CSSPixelPoint page_offset, unsigned buttons, unsigned mouse_button)
 {
 {
     MouseEventInit event_init {};
     MouseEventInit event_init {};
     event_init.offset_x = static_cast<double>(offset.x().value());
     event_init.offset_x = static_cast<double>(offset.x().value());
     event_init.offset_y = static_cast<double>(offset.y().value());
     event_init.offset_y = static_cast<double>(offset.y().value());
     event_init.client_x = static_cast<double>(client_offset.x().value());
     event_init.client_x = static_cast<double>(client_offset.x().value());
     event_init.client_y = static_cast<double>(client_offset.y().value());
     event_init.client_y = static_cast<double>(client_offset.y().value());
+    event_init.page_x = static_cast<double>(page_offset.x().value());
+    event_init.page_y = static_cast<double>(page_offset.y().value());
     event_init.button = determine_button(mouse_button);
     event_init.button = determine_button(mouse_button);
     event_init.buttons = buttons;
     event_init.buttons = buttons;
     return MouseEvent::create(realm, event_name, event_init);
     return MouseEvent::create(realm, event_name, event_init);

+ 8 - 1
Userland/Libraries/LibWeb/UIEvents/MouseEvent.h

@@ -18,6 +18,8 @@ struct MouseEventInit : public EventModifierInit {
     double offset_y = 0;
     double offset_y = 0;
     double client_x = 0;
     double client_x = 0;
     double client_y = 0;
     double client_y = 0;
+    double page_x = 0;
+    double page_y = 0;
 
 
     i16 button = 0;
     i16 button = 0;
     u16 buttons = 0;
     u16 buttons = 0;
@@ -28,7 +30,7 @@ class MouseEvent : public UIEvent {
 
 
 public:
 public:
     static MouseEvent* create(JS::Realm&, FlyString const& event_name, MouseEventInit const& event_init = {});
     static MouseEvent* create(JS::Realm&, FlyString const& event_name, MouseEventInit const& event_init = {});
-    static MouseEvent* create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint offset, CSSPixelPoint client_offset, unsigned buttons, unsigned mouse_button = 1);
+    static MouseEvent* create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint offset, CSSPixelPoint client_offset, CSSPixelPoint page_offset, unsigned buttons, unsigned mouse_button = 1);
 
 
     virtual ~MouseEvent() override;
     virtual ~MouseEvent() override;
 
 
@@ -42,6 +44,9 @@ public:
     double screen_x() const { return m_client_x; }
     double screen_x() const { return m_client_x; }
     double screen_y() const { return m_client_y; }
     double screen_y() const { return m_client_y; }
 
 
+    double page_x() const { return m_page_x; }
+    double page_y() const { return m_page_y; }
+
     double x() const { return client_x(); }
     double x() const { return client_x(); }
     double y() const { return client_y(); }
     double y() const { return client_y(); }
 
 
@@ -60,6 +65,8 @@ private:
     double m_offset_y { 0 };
     double m_offset_y { 0 };
     double m_client_x { 0 };
     double m_client_x { 0 };
     double m_client_y { 0 };
     double m_client_y { 0 };
+    double m_page_x { 0 };
+    double m_page_y { 0 };
     i16 m_button { 0 };
     i16 m_button { 0 };
     u16 m_buttons { 0 };
     u16 m_buttons { 0 };
 };
 };

+ 2 - 0
Userland/Libraries/LibWeb/UIEvents/MouseEvent.idl

@@ -10,6 +10,8 @@ interface MouseEvent : UIEvent {
     readonly attribute double screenY;
     readonly attribute double screenY;
     readonly attribute double x;
     readonly attribute double x;
     readonly attribute double y;
     readonly attribute double y;
+    readonly attribute double pageX;
+    readonly attribute double pageY;
 
 
     readonly attribute short button;
     readonly attribute short button;
     readonly attribute unsigned short buttons;
     readonly attribute unsigned short buttons;