LibWeb: Fix MouseEvent position values

The clientX and clientY values are, as per the spec, the offset from
the viewport.
This makes them actually be that and also fixes up the calculations
for offsetX, offsetY, pageX and pageY.
I assume all of these got messed up in some sort of refactor in the
past.

The spec comment from the now-removed
compute_mouse_event_client_offset() function sadly has no convenient
place to be anymore so, for now, it is just gone as well.
Personally, I think it'd make sense to refactor a lot of this file so
that not every mouse event repeats a large chunk of (almost) identical
code. That way there'd be a nice place to put the comment without
repeating it all over the file.
But that is out of the scope of this PR.

Also: I know, offsetX and Y are not fully fixed yet, they still
don't ignore the element's CSS transforms but I am working on that
in a new PR.
This commit is contained in:
Psychpsyo 2024-11-15 17:36:32 +01:00 committed by Alexander Kalenik
parent 41c172c663
commit 7f989765f5
Notes: github-actions[bot] 2024-11-21 12:23:20 +00:00
3 changed files with 85 additions and 69 deletions

View file

@ -177,8 +177,6 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
if (!m_navigable->active_document()->is_fully_active()) if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped; return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout(); m_navigable->active_document()->update_layout();
if (!paint_root()) if (!paint_root())
@ -190,20 +188,20 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
auto handled_event = EventResult::Dropped; auto handled_event = EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable; GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value()) if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable; paintable = result->paintable;
if (paintable) { if (paintable) {
auto* containing_block = paintable->containing_block(); auto* containing_block = paintable->containing_block();
while (containing_block) { while (containing_block) {
auto handled_scroll_event = containing_block->handle_mousewheel({}, position, buttons, modifiers, wheel_delta_x, wheel_delta_y); auto handled_scroll_event = containing_block->handle_mousewheel({}, viewport_position, buttons, modifiers, wheel_delta_x, wheel_delta_y);
if (handled_scroll_event) if (handled_scroll_event)
return EventResult::Handled; return EventResult::Handled;
containing_block = containing_block->containing_block(); containing_block = containing_block->containing_block();
} }
if (paintable->handle_mousewheel({}, position, buttons, modifiers, wheel_delta_x, wheel_delta_y)) if (paintable->handle_mousewheel({}, viewport_position, buttons, modifiers, wheel_delta_x, wheel_delta_y))
return EventResult::Handled; return EventResult::Handled;
auto node = dom_node_for_event_dispatch(*paintable); auto node = dom_node_for_event_dispatch(*paintable);
@ -212,7 +210,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
// FIXME: Support wheel events in nested browsing contexts. // FIXME: Support wheel events in nested browsing contexts.
if (is<HTML::HTMLIFrameElement>(*node)) { if (is<HTML::HTMLIFrameElement>(*node)) {
auto& iframe = static_cast<HTML::HTMLIFrameElement&>(*node); auto& iframe = static_cast<HTML::HTMLIFrameElement&>(*node);
auto position_in_iframe = position.translated(compute_mouse_event_offset({}, paintable->layout_node())); auto position_in_iframe = viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node()));
iframe.content_navigable()->event_handler().handle_mousewheel(position_in_iframe, screen_position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y); iframe.content_navigable()->event_handler().handle_mousewheel(position_in_iframe, screen_position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y);
return EventResult::Dropped; return EventResult::Dropped;
} }
@ -222,10 +220,9 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
if (!parent_element_for_event_dispatch(*paintable, node, layout_node)) if (!parent_element_for_event_dispatch(*paintable, node, layout_node))
return EventResult::Dropped; return EventResult::Dropped;
auto offset = compute_mouse_event_offset(position, *layout_node); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto client_offset = compute_mouse_event_client_offset(position); auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto page_offset = compute_mouse_event_page_offset(client_offset); 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(), UIEvents::EventNames::wheel, screen_position, page_offset, client_offset, 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); m_navigable->active_window()->scroll_by(wheel_delta_x, wheel_delta_y);
} }
@ -246,26 +243,24 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (!m_navigable->active_document()->is_fully_active()) if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped; return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout(); m_navigable->active_document()->update_layout();
if (!paint_root()) if (!paint_root())
return EventResult::Dropped; return EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable; GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value()) if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable; paintable = result->paintable;
if (paintable && paintable->wants_mouse_events()) { if (paintable && paintable->wants_mouse_events()) {
if (paintable->handle_mouseup({}, position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No) if (paintable->handle_mouseup({}, viewport_position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled; return EventResult::Cancelled;
// Things may have changed as a consequence of Layout::Node::handle_mouseup(). Hit test again. // Things may have changed as a consequence of Layout::Node::handle_mouseup(). Hit test again.
if (!paint_root()) if (!paint_root())
return EventResult::Handled; return EventResult::Handled;
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::Exact); result.has_value()) if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::Exact); result.has_value())
paintable = result->paintable; paintable = result->paintable;
} }
@ -277,7 +272,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (node) { if (node) {
if (is<HTML::HTMLIFrameElement>(*node)) { if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable()) if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mouseup(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers); return content_navigable->event_handler().handle_mouseup(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped; return EventResult::Dropped;
} }
@ -290,22 +285,21 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
goto after_node_use; goto after_node_use;
} }
auto offset = compute_mouse_event_offset(position, *layout_node); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto client_offset = compute_mouse_event_client_offset(position); auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto page_offset = compute_mouse_event_page_offset(client_offset); 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(), UIEvents::EventNames::mouseup, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
handled_event = EventResult::Handled; handled_event = EventResult::Handled;
bool run_activation_behavior = false; bool run_activation_behavior = false;
if (node.ptr() == m_mousedown_target) { if (node.ptr() == m_mousedown_target) {
if (button == UIEvents::MouseButton::Primary) { 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, client_offset, 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(), 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) { } 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, client_offset, 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(), 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) { } else if (button == UIEvents::MouseButton::Secondary) {
// Allow the user to bypass custom context menus by holding shift, like Firefox. // Allow the user to bypass custom context menus by holding shift, like Firefox.
if ((modifiers & UIEvents::Mod_Shift) == 0) 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, client_offset, 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(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
else else
run_activation_behavior = true; run_activation_behavior = true;
} }
@ -378,8 +372,6 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (!m_navigable->active_document()->is_fully_active()) if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped; return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout(); m_navigable->active_document()->update_layout();
if (!paint_root()) if (!paint_root())
@ -390,7 +382,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
{ {
GC::Ptr<Painting::Paintable> paintable; GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value()) if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable; paintable = result->paintable;
else else
return EventResult::Dropped; return EventResult::Dropped;
@ -403,7 +395,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
document->set_hovered_node(node); document->set_hovered_node(node);
if (paintable->wants_mouse_events()) { if (paintable->wants_mouse_events()) {
if (paintable->handle_mousedown({}, position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No) if (paintable->handle_mousedown({}, viewport_position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled; return EventResult::Cancelled;
} }
@ -412,7 +404,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (is<HTML::HTMLIFrameElement>(*node)) { if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable()) if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers); return content_navigable->event_handler().handle_mousedown(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped; return EventResult::Dropped;
} }
@ -426,10 +418,9 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
return EventResult::Dropped; return EventResult::Dropped;
m_mousedown_target = node.ptr(); m_mousedown_target = node.ptr();
auto offset = compute_mouse_event_offset(position, *layout_node); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto client_offset = compute_mouse_event_client_offset(position); auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto page_offset = compute_mouse_event_page_offset(client_offset); 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(), UIEvents::EventNames::mousedown, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} }
// NOTE: Dispatching an event may have disturbed the world. // NOTE: Dispatching an event may have disturbed the world.
@ -437,7 +428,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
return EventResult::Accepted; return EventResult::Accepted;
if (button == UIEvents::MouseButton::Primary) { if (button == UIEvents::MouseButton::Primary) {
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); result.has_value()) { if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor); result.has_value()) {
auto paintable = result->paintable; auto paintable = result->paintable;
auto dom_node = paintable->dom_node(); auto dom_node = paintable->dom_node();
if (dom_node) { if (dom_node) {
@ -494,8 +485,6 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (!m_navigable->active_document()->is_fully_active()) if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped; return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout(); m_navigable->active_document()->update_layout();
if (!paint_root()) if (!paint_root())
@ -510,7 +499,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
GC::Ptr<Painting::Paintable> paintable; GC::Ptr<Painting::Paintable> paintable;
Optional<int> start_index; Optional<int> start_index;
if (auto result = target_for_mouse_position(position); result.has_value()) { if (auto result = target_for_mouse_position(viewport_position); result.has_value()) {
paintable = result->paintable; paintable = result->paintable;
start_index = result->index_in_node; start_index = result->index_in_node;
} }
@ -519,7 +508,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (paintable) { if (paintable) {
if (paintable->wants_mouse_events()) { if (paintable->wants_mouse_events()) {
document.set_hovered_node(paintable->dom_node()); document.set_hovered_node(paintable->dom_node());
if (paintable->handle_mousemove({}, position, buttons, modifiers) == Painting::Paintable::DispatchEventOfSameName::No) if (paintable->handle_mousemove({}, viewport_position, buttons, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled; return EventResult::Cancelled;
// FIXME: It feels a bit aggressive to always update the cursor like this. // FIXME: It feels a bit aggressive to always update the cursor like this.
@ -530,7 +519,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (node && is<HTML::HTMLIFrameElement>(*node)) { if (node && is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable()) if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mousemove(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, buttons, modifiers); return content_navigable->event_handler().handle_mousemove(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, buttons, modifiers);
return EventResult::Dropped; return EventResult::Dropped;
} }
@ -563,14 +552,13 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
hovered_node_cursor = cursor_css_to_gfx(cursor); hovered_node_cursor = cursor_css_to_gfx(cursor);
} }
auto offset = compute_mouse_event_offset(position, *layout_node); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto client_offset = compute_mouse_event_client_offset(position); auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto page_offset = compute_mouse_event_page_offset(client_offset);
auto movement = compute_mouse_event_movement(screen_position); auto movement = compute_mouse_event_movement(screen_position);
m_mousemove_previous_screen_position = screen_position; m_mousemove_previous_screen_position = screen_position;
bool continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, client_offset, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); bool 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());
if (!continue_) if (!continue_)
return EventResult::Cancelled; return EventResult::Cancelled;
@ -580,7 +568,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
} }
if (m_in_mouse_selection) { if (m_in_mouse_selection) {
auto hit = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); auto hit = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor);
if (m_mouse_selection_target) { if (m_mouse_selection_target) {
if (hit.has_value()) { if (hit.has_value()) {
m_mouse_selection_target->set_selection_focus(*hit->paintable->dom_node(), hit->index_in_node); m_mouse_selection_target->set_selection_focus(*hit->paintable->dom_node(), hit->index_in_node);
@ -635,16 +623,13 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
auto& document = *m_navigable->active_document(); auto& document = *m_navigable->active_document();
auto scroll_offset = document.navigable()->viewport_scroll_offset();
auto position = viewport_position.translated(scroll_offset);
document.update_layout(); document.update_layout();
if (!paint_root()) if (!paint_root())
return EventResult::Dropped; return EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable; GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value()) if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable; paintable = result->paintable;
else else
return EventResult::Dropped; return EventResult::Dropped;
@ -665,7 +650,7 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
if (is<HTML::HTMLIFrameElement>(*node)) { if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable()) if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_doubleclick(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers); return content_navigable->event_handler().handle_doubleclick(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped; return EventResult::Dropped;
} }
@ -675,17 +660,16 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
if (!parent_element_for_event_dispatch(*paintable, node, layout_node)) if (!parent_element_for_event_dispatch(*paintable, node, layout_node))
return EventResult::Dropped; return EventResult::Dropped;
auto offset = compute_mouse_event_offset(position, *layout_node); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto client_offset = compute_mouse_event_client_offset(position); auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto page_offset = compute_mouse_event_page_offset(client_offset); 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(), UIEvents::EventNames::dblclick, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
// 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().paintable_box()) if (!paint_root() || paint_root() != node->document().paintable_box())
return EventResult::Accepted; return EventResult::Accepted;
if (button == UIEvents::MouseButton::Primary) { if (button == UIEvents::MouseButton::Primary) {
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); result.has_value()) { if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor); result.has_value()) {
if (!result->paintable->dom_node()) if (!result->paintable->dom_node())
return EventResult::Accepted; return EventResult::Accepted;
if (!is<Painting::TextPaintable>(*result->paintable)) if (!is<Painting::TextPaintable>(*result->paintable))
@ -738,19 +722,18 @@ EventResult EventHandler::handle_drag_and_drop_event(DragEvent::Type type, CSSPi
return EventResult::Dropped; return EventResult::Dropped;
} }
auto offset = compute_mouse_event_offset(viewport_position, paintable->layout_node()); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto client_offset = compute_mouse_event_client_offset(viewport_position); auto offset = compute_mouse_event_offset(page_offset, paintable->layout_node());
auto page_offset = compute_mouse_event_page_offset(client_offset);
switch (type) { switch (type) {
case DragEvent::Type::DragStart: case DragEvent::Type::DragStart:
return m_drag_and_drop_event_handler->handle_drag_start(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers, move(files)); return m_drag_and_drop_event_handler->handle_drag_start(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers, move(files));
case DragEvent::Type::DragMove: case DragEvent::Type::DragMove:
return m_drag_and_drop_event_handler->handle_drag_move(document.realm(), document, *node, screen_position, page_offset, client_offset, offset, button, buttons, modifiers); return m_drag_and_drop_event_handler->handle_drag_move(document.realm(), document, *node, screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
case DragEvent::Type::DragEnd: case DragEvent::Type::DragEnd:
return m_drag_and_drop_event_handler->handle_drag_leave(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers); return m_drag_and_drop_event_handler->handle_drag_leave(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
case DragEvent::Type::Drop: case DragEvent::Type::Drop:
return m_drag_and_drop_event_handler->handle_drop(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers); return m_drag_and_drop_event_handler->handle_drop(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -1113,15 +1096,6 @@ void EventHandler::set_mouse_event_tracking_paintable(Painting::Paintable* paint
m_mouse_event_tracking_paintable = paintable; m_mouse_event_tracking_paintable = paintable;
} }
CSSPixelPoint EventHandler::compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const
{
// 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.
auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset();
return event_page_position.translated(-scroll_offset);
}
CSSPixelPoint EventHandler::compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const CSSPixelPoint EventHandler::compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const
{ {
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-pagex // https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-pagex

View file

@ -0,0 +1,10 @@
x: 50
y: 50
screenX: 50
screenY: 50
clientX: 50
clientY: 50
pageX: 50
pageY: 60
offsetX: 42
offsetY: 52

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<style>
div {
width: 100px;
height: 100px;
background-color: gray;
}
body {
height: 200vh;
}
</style>
<div onClick="
println(`x: ${event.x}`);
println(`y: ${event.y}`);
println(`screenX: ${event.screenX}`);
println(`screenY: ${event.screenY}`);
println(`clientX: ${event.clientX}`);
println(`clientY: ${event.clientY}`);
println(`pageX: ${event.pageX}`);
println(`pageY: ${event.pageY}`);
println(`offsetX: ${event.offsetX}`);
println(`offsetY: ${event.offsetY}`);
"></div>
<script src="../include.js"></script>
<script>
test(() => {
window.scrollBy(0, 10)
internals.click(50, 50);
});
</script>