| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/input/pointer_event_manager.h" |
| |
| #include <limits> |
| #include <memory> |
| |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/dom/events/native_event_listener.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/html/html_element.h" |
| #include "third_party/blink/renderer/core/input/event_handler.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_request.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_test.h" |
| #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" |
| |
| namespace blink { |
| |
| namespace { |
| class CheckPointerEventListenerCallback final : public NativeEventListener { |
| public: |
| void Invoke(ExecutionContext*, Event* event) override { |
| num_events_received_++; |
| |
| const String pointer_type = |
| static_cast<PointerEvent*>(event)->pointerType(); |
| if (pointer_type == "mouse") |
| num_type_mouse_received_++; |
| else if (pointer_type == "touch") |
| num_type_touch_received_++; |
| else if (pointer_type == "pen") |
| num_type_pen_received_++; |
| } |
| |
| int numEventsReceived() const { return num_events_received_; } |
| |
| int numTypeMouseReceived() const { return num_type_mouse_received_; } |
| int numTypeTouchReceived() const { return num_type_touch_received_; } |
| int numTypePenReceived() const { return num_type_pen_received_; } |
| |
| private: |
| int num_events_received_ = 0; |
| int num_type_mouse_received_ = 0; |
| int num_type_touch_received_ = 0; |
| int num_type_pen_received_ = 0; |
| }; |
| |
| class PointerEventCoordinateListenerCallback final |
| : public NativeEventListener { |
| public: |
| static PointerEventCoordinateListenerCallback* Create() { |
| return MakeGarbageCollected<PointerEventCoordinateListenerCallback>(); |
| } |
| |
| void Invoke(ExecutionContext*, Event* event) override { |
| const PointerEvent* pointer_event = static_cast<PointerEvent*>(event); |
| last_client_x_ = pointer_event->clientX(); |
| last_client_y_ = pointer_event->clientY(); |
| last_page_x_ = pointer_event->pageX(); |
| last_page_y_ = pointer_event->pageY(); |
| last_screen_x_ = pointer_event->screenX(); |
| last_screen_y_ = pointer_event->screenY(); |
| last_width_ = pointer_event->width(); |
| last_height_ = pointer_event->height(); |
| last_movement_x_ = pointer_event->movementX(); |
| last_movement_y_ = pointer_event->movementY(); |
| } |
| |
| double last_client_x_ = 0; |
| double last_client_y_ = 0; |
| double last_page_x_ = 0; |
| double last_page_y_ = 0; |
| double last_screen_x_ = 0; |
| double last_screen_y_ = 0; |
| double last_width_ = 0; |
| double last_height_ = 0; |
| double last_movement_x_ = 0; |
| double last_movement_y_ = 0; |
| }; |
| |
| } // namespace |
| |
| class PointerEventManagerTest : public SimTest { |
| protected: |
| EventHandler& GetEventHandler() { |
| return GetDocument().GetFrame()->GetEventHandler(); |
| } |
| std::unique_ptr<WebPointerEvent> CreateTestPointerEvent( |
| WebInputEvent::Type type, |
| WebPointerProperties::PointerType pointer_type, |
| PointerId id = 1) { |
| return CreateTestPointerEvent(type, pointer_type, id, gfx::PointF(100, 100), |
| gfx::PointF(100, 100), 0, 0, 1, 1); |
| } |
| std::unique_ptr<WebPointerEvent> CreateTestPointerEvent( |
| WebInputEvent::Type type, |
| WebPointerProperties::PointerType pointer_type, |
| gfx::PointF position_in_widget, |
| gfx::PointF position_in_screen, |
| int movement_x, |
| int movement_y, |
| float width = 1, |
| float height = 1) { |
| return CreateTestPointerEvent(type, pointer_type, 1, position_in_widget, |
| position_in_screen, movement_x, movement_y, |
| width, height); |
| } |
| WebMouseEvent CreateTestMouseEvent(WebInputEvent::Type type, |
| const gfx::PointF& coordinates) { |
| WebMouseEvent event(type, coordinates, coordinates, |
| WebPointerProperties::Button::kLeft, 0, |
| WebInputEvent::kLeftButtonDown, |
| WebInputEvent::GetStaticTimeStampForTests()); |
| event.SetFrameScale(1); |
| return event; |
| } |
| |
| private: |
| std::unique_ptr<WebPointerEvent> CreateTestPointerEvent( |
| WebInputEvent::Type type, |
| WebPointerProperties::PointerType pointer_type, |
| PointerId id, |
| gfx::PointF position_in_widget, |
| gfx::PointF position_in_screen, |
| int movement_x, |
| int movement_y, |
| float width, |
| float height) { |
| return std::make_unique<WebPointerEvent>( |
| type, |
| WebPointerProperties( |
| id, pointer_type, WebPointerProperties::Button::kLeft, |
| position_in_widget, position_in_screen, movement_x, movement_y), |
| width, height); |
| } |
| }; |
| |
| TEST_F(PointerEventManagerTest, HasPointerCapture) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "</body>"); |
| ASSERT_FALSE(GetDocument().body()->hasPointerCapture(4)); |
| ASSERT_FALSE(GetDocument().body()->hasPointerCapture( |
| std::numeric_limits<PointerId>::max())); |
| ASSERT_FALSE(GetDocument().body()->hasPointerCapture(0)); |
| ASSERT_FALSE(GetDocument().body()->hasPointerCapture(-1)); |
| ASSERT_FALSE( |
| GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId)); |
| |
| ExceptionState exception(nullptr, ExceptionState::kExecutionContext, "", ""); |
| |
| GetEventHandler().HandleMousePressEvent(CreateTestMouseEvent( |
| WebInputEvent::Type::kMouseDown, gfx::PointF(100, 100))); |
| |
| ASSERT_FALSE( |
| GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId)); |
| |
| GetDocument().body()->setPointerCapture(PointerEventFactory::kMouseId, |
| exception); |
| ASSERT_TRUE( |
| GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId)); |
| |
| GetEventHandler().HandleMouseMoveEvent( |
| CreateTestMouseEvent(WebInputEvent::Type::kMouseMove, |
| gfx::PointF(200, 200)), |
| Vector<WebMouseEvent>(), Vector<WebMouseEvent>()); |
| |
| ASSERT_TRUE( |
| GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId)); |
| |
| GetDocument().body()->releasePointerCapture(PointerEventFactory::kMouseId, |
| exception); |
| ASSERT_FALSE( |
| GetDocument().body()->hasPointerCapture(PointerEventFactory::kMouseId)); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "<div draggable='true' style='width: 150px; height: 150px;'></div>" |
| "</body>"); |
| auto* callback = MakeGarbageCollected<CheckPointerEventListenerCallback>(); |
| GetDocument().body()->addEventListener(event_type_names::kPointercancel, |
| callback); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerDown, |
| WebPointerProperties::PointerType::kTouch), |
| {}, {}, ui::LatencyInfo())); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerDown, |
| WebPointerProperties::PointerType::kPen), |
| {}, {}, ui::LatencyInfo())); |
| |
| GetEventHandler().HandleMousePressEvent(CreateTestMouseEvent( |
| WebInputEvent::Type::kMouseDown, gfx::PointF(100, 100))); |
| |
| ASSERT_EQ(callback->numTypeMouseReceived(), 0); |
| ASSERT_EQ(callback->numTypeTouchReceived(), 0); |
| ASSERT_EQ(callback->numTypePenReceived(), 0); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerCausedUaAction, |
| WebPointerProperties::PointerType::kPen), |
| {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->numTypeMouseReceived(), 0); |
| ASSERT_EQ(callback->numTypeTouchReceived(), 1); |
| ASSERT_EQ(callback->numTypePenReceived(), 1); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerCausedUaAction, |
| WebPointerProperties::PointerType::kTouch), |
| {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->numTypeMouseReceived(), 0); |
| ASSERT_EQ(callback->numTypeTouchReceived(), 1); |
| ASSERT_EQ(callback->numTypePenReceived(), 1); |
| |
| GetEventHandler().HandleMouseMoveEvent( |
| CreateTestMouseEvent(WebInputEvent::Type::kMouseMove, |
| gfx::PointF(200, 200)), |
| Vector<WebMouseEvent>(), Vector<WebMouseEvent>()); |
| |
| ASSERT_EQ(callback->numTypeMouseReceived(), 1); |
| ASSERT_EQ(callback->numTypeTouchReceived(), 1); |
| ASSERT_EQ(callback->numTypePenReceived(), 1); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerCancelForNonExistentid) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "<div draggable='true' style='width: 150px; height: 150px;'></div>" |
| "</body>"); |
| auto* callback = MakeGarbageCollected<CheckPointerEventListenerCallback>(); |
| GetDocument().body()->addEventListener(event_type_names::kPointercancel, |
| callback); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerCancel, |
| WebPointerProperties::PointerType::kTouch, 100), |
| {}, {}, ui::LatencyInfo())); |
| |
| ASSERT_EQ(callback->numEventsReceived(), 0); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerDown, |
| WebPointerProperties::PointerType::kTouch, 100), |
| {}, {}, ui::LatencyInfo())); |
| |
| ASSERT_EQ(callback->numEventsReceived(), 0); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerCancel, |
| WebPointerProperties::PointerType::kTouch, 100), |
| {}, {}, ui::LatencyInfo())); |
| |
| ASSERT_EQ(callback->numEventsReceived(), 1); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerCancel, |
| WebPointerProperties::PointerType::kTouch, 200), |
| {}, {}, ui::LatencyInfo())); |
| |
| ASSERT_EQ(callback->numEventsReceived(), 1); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerEventCoordinates) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "</body>"); |
| WebView().SetPageScaleFactor(2); |
| PointerEventCoordinateListenerCallback* callback = |
| PointerEventCoordinateListenerCallback::Create(); |
| GetDocument().body()->addEventListener(event_type_names::kPointerdown, |
| callback); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerDown, |
| WebPointerProperties::PointerType::kTouch, |
| gfx::PointF(150, 200), gfx::PointF(100, 50), 10, |
| 10, 16, 24), |
| {}, {}, ui::LatencyInfo())); |
| |
| ASSERT_EQ(callback->last_client_x_, 75); |
| ASSERT_EQ(callback->last_client_y_, 100); |
| ASSERT_EQ(callback->last_page_x_, 75); |
| ASSERT_EQ(callback->last_page_y_, 100); |
| ASSERT_EQ(callback->last_screen_x_, 100); |
| ASSERT_EQ(callback->last_screen_y_, 50); |
| ASSERT_EQ(callback->last_width_, 8); |
| ASSERT_EQ(callback->last_height_, 12); |
| ASSERT_EQ(callback->last_movement_x_, 10); |
| ASSERT_EQ(callback->last_movement_y_, 10); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerEventMovements) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "</body>"); |
| PointerEventCoordinateListenerCallback* callback = |
| PointerEventCoordinateListenerCallback::Create(); |
| GetDocument().body()->addEventListener(event_type_names::kPointermove, |
| callback); |
| |
| { |
| // Turn on the flag for test. |
| ScopedConsolidatedMovementXYForTest scoped_feature(true); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 210), gfx::PointF(100, 50), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| // The first pointermove event has movement_x/y 0. |
| ASSERT_EQ(callback->last_screen_x_, 100); |
| ASSERT_EQ(callback->last_screen_y_, 50); |
| ASSERT_EQ(callback->last_movement_x_, 0); |
| ASSERT_EQ(callback->last_movement_y_, 0); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 200), gfx::PointF(132, 29), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| // pointermove event movement = event.screenX/Y - last_event.screenX/Y. |
| ASSERT_EQ(callback->last_screen_x_, 132); |
| ASSERT_EQ(callback->last_screen_y_, 29); |
| ASSERT_EQ(callback->last_movement_x_, 32); |
| ASSERT_EQ(callback->last_movement_y_, -21); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 210), gfx::PointF(113.8, 32.7), |
| 10, 10), |
| {}, {}, ui::LatencyInfo())); |
| // fractional screen coordinates result in fractional movement. |
| ASSERT_FLOAT_EQ(callback->last_screen_x_, 113.8); |
| ASSERT_FLOAT_EQ(callback->last_screen_y_, 32.7); |
| // TODO(eirage): These should be float value once mouse_event.idl change. |
| ASSERT_FLOAT_EQ(callback->last_movement_x_, -19); |
| ASSERT_FLOAT_EQ(callback->last_movement_y_, 3); |
| } |
| |
| { |
| // When flag is off, movementX/Y follows the value in WebPointerProperties. |
| ScopedConsolidatedMovementXYForTest scoped_feature(false); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 210), gfx::PointF(100, 16.25), |
| 1024, -8765), |
| {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->last_screen_x_, 100); |
| ASSERT_EQ(callback->last_screen_y_, 16.25); |
| ASSERT_EQ(callback->last_movement_x_, 1024); |
| ASSERT_EQ(callback->last_movement_y_, -8765); |
| } |
| } |
| |
| // Test that we are not losing fractions when truncating movements. |
| TEST_F(PointerEventManagerTest, PointerEventSmallFractionMovements) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "</body>"); |
| PointerEventCoordinateListenerCallback* callback = |
| PointerEventCoordinateListenerCallback::Create(); |
| GetDocument().body()->addEventListener(event_type_names::kPointermove, |
| callback); |
| |
| // Turn on the flag for test. |
| ScopedConsolidatedMovementXYForTest scoped_feature(true); |
| |
| std::unique_ptr<WebPointerEvent> pointer_event = CreateTestPointerEvent( |
| WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, gfx::PointF(150, 210), |
| gfx::PointF(113.8, 32.7), 0, 0); |
| ASSERT_NE(nullptr, pointer_event); |
| WebView().MainFrameWidget()->HandleInputEvent( |
| WebCoalescedInputEvent(pointer_event->Clone(), ui::LatencyInfo())); |
| ASSERT_FLOAT_EQ(callback->last_movement_x_, 0); |
| ASSERT_FLOAT_EQ(callback->last_movement_y_, 0); |
| |
| pointer_event->SetPositionInScreen(113.4, 32.9); |
| WebView().MainFrameWidget()->HandleInputEvent( |
| WebCoalescedInputEvent(pointer_event->Clone(), ui::LatencyInfo())); |
| ASSERT_FLOAT_EQ(callback->last_movement_x_, 0); |
| ASSERT_FLOAT_EQ(callback->last_movement_y_, 0); |
| |
| pointer_event->SetPositionInScreen(113.0, 33.1); |
| WebView().MainFrameWidget()->HandleInputEvent( |
| WebCoalescedInputEvent(pointer_event->Clone(), ui::LatencyInfo())); |
| ASSERT_FLOAT_EQ(callback->last_movement_x_, 0); |
| ASSERT_FLOAT_EQ(callback->last_movement_y_, 1); |
| |
| pointer_event->SetPositionInScreen(112.6, 33.3); |
| WebView().MainFrameWidget()->HandleInputEvent( |
| WebCoalescedInputEvent(std::move(pointer_event), ui::LatencyInfo())); |
| ASSERT_FLOAT_EQ(callback->last_movement_x_, -1); |
| ASSERT_FLOAT_EQ(callback->last_movement_y_, 0); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerRawUpdateMovements) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "</body>"); |
| PointerEventCoordinateListenerCallback* callback = |
| PointerEventCoordinateListenerCallback::Create(); |
| GetDocument().body()->addEventListener(event_type_names::kPointermove, |
| callback); |
| GetDocument().body()->addEventListener(event_type_names::kPointerrawupdate, |
| callback); |
| |
| // Turn on the flag for test. |
| ScopedConsolidatedMovementXYForTest scoped_feature(true); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 210), gfx::PointF(100, 50), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| // The first pointerrawupdate event has movement_x/y 0. |
| ASSERT_EQ(callback->last_screen_x_, 100); |
| ASSERT_EQ(callback->last_screen_y_, 50); |
| ASSERT_EQ(callback->last_movement_x_, 0); |
| ASSERT_EQ(callback->last_movement_y_, 0); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 200), gfx::PointF(132, 29), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| // pointerrawupdate event movement = event.screenX/Y - last_event.screenX/Y. |
| ASSERT_EQ(callback->last_screen_x_, 132); |
| ASSERT_EQ(callback->last_screen_y_, 29); |
| ASSERT_EQ(callback->last_movement_x_, 32); |
| ASSERT_EQ(callback->last_movement_y_, -21); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 200), gfx::PointF(144, 30), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| // First pointermove, have 0 movements. |
| ASSERT_EQ(callback->last_screen_x_, 144); |
| ASSERT_EQ(callback->last_screen_y_, 30); |
| ASSERT_EQ(callback->last_movement_x_, 0); |
| ASSERT_EQ(callback->last_movement_y_, 0); |
| |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(150, 200), gfx::PointF(142, 32), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| // pointerrawupdate event's movement is independent from pointermoves. |
| ASSERT_EQ(callback->last_screen_x_, 142); |
| ASSERT_EQ(callback->last_screen_y_, 32); |
| ASSERT_EQ(callback->last_movement_x_, 10); |
| ASSERT_EQ(callback->last_movement_y_, 3); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerRawUpdateWithRelativeMotionEvent) { |
| ScopedConsolidatedMovementXYForTest scoped_feature(true); |
| |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding:0px; width:400px; height:400px;'></body>"); |
| |
| PointerEventCoordinateListenerCallback* callback = |
| PointerEventCoordinateListenerCallback::Create(); |
| GetDocument().body()->addEventListener(event_type_names::kPointerrawupdate, |
| callback); |
| |
| // Initial movement_x/y are both 0. |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(350, 350), gfx::PointF(350, 350), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->last_movement_x_, 0); |
| ASSERT_EQ(callback->last_movement_y_, 0); |
| |
| // After moving the mouse by (+40,+20), movement_x/y have same deltas. |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(390, 370), gfx::PointF(390, 370), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->last_movement_x_, 40); |
| ASSERT_EQ(callback->last_movement_y_, 20); |
| |
| // A relative motion event to pull the mouse pointer back towards the center |
| // is not exposed to JS, so the event handler is not called and the cached |
| // coordinates remain unchanged. |
| std::unique_ptr<WebInputEvent> synthetic_event = CreateTestPointerEvent( |
| WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, gfx::PointF(200, 200), |
| gfx::PointF(200, 200), 10, 10); |
| synthetic_event->SetModifiers(WebInputEvent::Modifiers::kRelativeMotionEvent); |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| std::move(synthetic_event), {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->last_movement_x_, 40); |
| ASSERT_EQ(callback->last_movement_y_, 20); |
| |
| // After moving the mouse by (+15,-10) from the last unexposed event, |
| // movement_x/y have deltas from the last event, not the deltas from the last |
| // exposed event. |
| WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent( |
| CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate, |
| WebPointerProperties::PointerType::kMouse, |
| gfx::PointF(215, 190), gfx::PointF(215, 190), 10, |
| 10), |
| {}, {}, ui::LatencyInfo())); |
| ASSERT_EQ(callback->last_movement_x_, 15); |
| ASSERT_EQ(callback->last_movement_y_, -10); |
| } |
| |
| TEST_F(PointerEventManagerTest, PointerUnadjustedMovement) { |
| WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400)); |
| SimRequest request("https://example.com/test.html", "text/html"); |
| LoadURL("https://example.com/test.html"); |
| request.Complete( |
| "<body style='padding: 0px; width: 400px; height: 400px;'>" |
| "</body>"); |
| PointerEventCoordinateListenerCallback* callback = |
| PointerEventCoordinateListenerCallback::Create(); |
| GetDocument().body()->addEventListener(event_type_names::kPointermove, |
| callback); |
| |
| std::unique_ptr<WebPointerEvent> event = CreateTestPointerEvent( |
| WebInputEvent::Type::kPointerMove, |
| WebPointerProperties::PointerType::kMouse, gfx::PointF(150, 210), |
| gfx::PointF(100, 50), 120, -321); |
| ASSERT_NE(nullptr, event); |
| event->is_raw_movement_event = true; |
| WebView().MainFrameWidget()->HandleInputEvent( |
| WebCoalescedInputEvent(std::move(event), {}, {}, ui::LatencyInfo())); |
| |
| // If is_raw_movement_event is true, PE use the raw movement value from |
| // movement_x/y. |
| ASSERT_EQ(callback->last_screen_x_, 100); |
| ASSERT_EQ(callback->last_screen_y_, 50); |
| ASSERT_EQ(callback->last_movement_x_, 120); |
| ASSERT_EQ(callback->last_movement_y_, -321); |
| } |
| |
| } // namespace blink |