From 1921bba601db9353770ca4df15b05d03d2ff5836 Mon Sep 17 00:00:00 2001 From: Psychpsyo Date: Tue, 19 Nov 2024 22:26:00 +0100 Subject: [PATCH] LibWeb: Make MouseEvent.offsetX/Y ignore transforms That is what the spec calls it, at least. In code, this manifests as making the offset very aware of the element's transform, because the click position comes relative to the viewport, not to the transformed element. --- Libraries/LibWeb/Page/EventHandler.cpp | 39 +++++++++++++++++-- .../CSSOMView/mouse-event-offset-values.txt | 2 + .../CSSOMView/mouse-event-offset-values.html | 21 ++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/CSSOMView/mouse-event-offset-values.txt create mode 100644 Tests/LibWeb/Text/input/CSSOMView/mouse-event-offset-values.html diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 4d3c5859de1..870fc064410 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -136,13 +136,44 @@ static Gfx::StandardCursor cursor_css_to_gfx(Optional cursor) } } +// https://drafts.csswg.org/cssom-view/#dom-mouseevent-offsetx static CSSPixelPoint compute_mouse_event_offset(CSSPixelPoint position, Layout::Node const& layout_node) { - auto top_left_of_layout_node = layout_node.first_paintable()->box_type_agnostic_position(); - return { - position.x() - top_left_of_layout_node.x(), - position.y() - top_left_of_layout_node.y() + // If the event’s dispatch flag is set, + // FIXME: Is this guaranteed to be dispatched? + + // return the x-coordinate of the position where the event occurred, + Gfx::Point precision_offset = { + position.x().to_double(), + position.y().to_double() }; + + // ignoring the transforms that apply to the element and its ancestors, + if (layout_node.has_css_transform()) { + auto const& paintable_box = layout_node.dom_node()->paintable_box(); + auto const affine_transform = Gfx::extract_2d_affine_transform(paintable_box->transform().inverse()); + + auto const& origin = paintable_box->transform_origin(); + Gfx::Point const precision_origin = { + origin.x().to_double(), + origin.y().to_double() + }; + + precision_offset.translate_by(-precision_origin); + precision_offset.transform_by(affine_transform); + precision_offset.translate_by(precision_origin); + } + + // relative to the origin of the padding edge of the target node + auto const top_left_of_layout_node = layout_node.first_paintable()->box_type_agnostic_position(); + CSSPixelPoint offset = { + CSSPixels(precision_offset.x()), + CSSPixels(precision_offset.y()) + }; + offset -= top_left_of_layout_node; + + // and terminate these steps. + return offset; } EventHandler::EventHandler(Badge, HTML::Navigable& navigable) diff --git a/Tests/LibWeb/Text/expected/CSSOMView/mouse-event-offset-values.txt b/Tests/LibWeb/Text/expected/CSSOMView/mouse-event-offset-values.txt new file mode 100644 index 00000000000..cab2f2a7f70 --- /dev/null +++ b/Tests/LibWeb/Text/expected/CSSOMView/mouse-event-offset-values.txt @@ -0,0 +1,2 @@ +offsetX: 45.75 +offsetY: 57.078125 diff --git a/Tests/LibWeb/Text/input/CSSOMView/mouse-event-offset-values.html b/Tests/LibWeb/Text/input/CSSOMView/mouse-event-offset-values.html new file mode 100644 index 00000000000..39067557c7f --- /dev/null +++ b/Tests/LibWeb/Text/input/CSSOMView/mouse-event-offset-values.html @@ -0,0 +1,21 @@ + + +
+ + + +