| // Copyright 2013 The Flutter 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 "flutter/shell/platform/linux/fl_scrolling_manager.h" |
| |
| #include <cstring> |
| #include <vector> |
| |
| #include "gtest/gtest.h" |
| namespace { |
| typedef std::function<void(FlutterPointerPhase phase, |
| size_t timestamp, |
| double x, |
| double y, |
| double scroll_delta_x, |
| double scroll_delta_y, |
| int64_t buttons)> |
| MousePointerCallHandler; |
| typedef std::function<void(size_t timestamp, |
| double x, |
| double y, |
| FlutterPointerPhase phase, |
| double pan_x, |
| double pan_y, |
| double scale, |
| double rotation)> |
| PointerPanZoomCallHandler; |
| |
| typedef struct { |
| FlutterPointerPhase phase; |
| size_t timestamp; |
| double x; |
| double y; |
| double scroll_delta_x; |
| double scroll_delta_y; |
| int64_t buttons; |
| } MousePointerEventRecord; |
| |
| typedef struct { |
| size_t timestamp; |
| double x; |
| double y; |
| FlutterPointerPhase phase; |
| double pan_x; |
| double pan_y; |
| double scale; |
| double rotation; |
| } PointerPanZoomEventRecord; |
| |
| G_BEGIN_DECLS |
| |
| G_DECLARE_FINAL_TYPE(FlMockScrollingViewDelegate, |
| fl_mock_scrolling_view_delegate, |
| FL, |
| MOCK_SCROLLING_VIEW_DELEGATE, |
| GObject) |
| |
| G_END_DECLS |
| |
| /***** FlMockScrollingViewDelegate *****/ |
| |
| struct _FlMockScrollingViewDelegate { |
| GObject parent_instance; |
| |
| MousePointerCallHandler mouse_handler; |
| PointerPanZoomCallHandler pan_zoom_handler; |
| }; |
| |
| static void fl_mock_view_scroll_delegate_iface_init( |
| FlScrollingViewDelegateInterface* iface); |
| |
| G_DEFINE_TYPE_WITH_CODE( |
| FlMockScrollingViewDelegate, |
| fl_mock_scrolling_view_delegate, |
| G_TYPE_OBJECT, |
| G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(), |
| fl_mock_view_scroll_delegate_iface_init)) |
| |
| static void fl_mock_scrolling_view_delegate_init( |
| FlMockScrollingViewDelegate* self) {} |
| |
| static void fl_mock_scrolling_view_delegate_dispose(GObject* object) { |
| G_OBJECT_CLASS(fl_mock_scrolling_view_delegate_parent_class)->dispose(object); |
| } |
| |
| static void fl_mock_scrolling_view_delegate_class_init( |
| FlMockScrollingViewDelegateClass* klass) { |
| G_OBJECT_CLASS(klass)->dispose = fl_mock_scrolling_view_delegate_dispose; |
| } |
| |
| static void fl_mock_view_send_mouse_pointer_event( |
| FlScrollingViewDelegate* delegate, |
| FlutterPointerPhase phase, |
| size_t timestamp, |
| double x, |
| double y, |
| double scroll_delta_x, |
| double scroll_delta_y, |
| int64_t buttons) { |
| FlMockScrollingViewDelegate* self = FL_MOCK_SCROLLING_VIEW_DELEGATE(delegate); |
| self->mouse_handler(phase, timestamp, x, y, scroll_delta_x, scroll_delta_y, |
| buttons); |
| } |
| |
| static void fl_mock_view_send_pointer_pan_zoom_event( |
| FlScrollingViewDelegate* delegate, |
| size_t timestamp, |
| double x, |
| double y, |
| FlutterPointerPhase phase, |
| double pan_x, |
| double pan_y, |
| double scale, |
| double rotation) { |
| FlMockScrollingViewDelegate* self = FL_MOCK_SCROLLING_VIEW_DELEGATE(delegate); |
| self->pan_zoom_handler(timestamp, x, y, phase, pan_x, pan_y, scale, rotation); |
| } |
| |
| static void fl_mock_view_scroll_delegate_iface_init( |
| FlScrollingViewDelegateInterface* iface) { |
| iface->send_mouse_pointer_event = fl_mock_view_send_mouse_pointer_event; |
| iface->send_pointer_pan_zoom_event = fl_mock_view_send_pointer_pan_zoom_event; |
| } |
| |
| static FlMockScrollingViewDelegate* fl_mock_scrolling_view_delegate_new() { |
| FlMockScrollingViewDelegate* self = FL_MOCK_SCROLLING_VIEW_DELEGATE( |
| g_object_new(fl_mock_scrolling_view_delegate_get_type(), nullptr)); |
| |
| // Added to stop compiler complaining about an unused function. |
| FL_IS_MOCK_SCROLLING_VIEW_DELEGATE(self); |
| |
| return self; |
| } |
| |
| static void fl_mock_scrolling_view_set_mouse_handler( |
| FlMockScrollingViewDelegate* self, |
| MousePointerCallHandler handler) { |
| self->mouse_handler = std::move(handler); |
| } |
| |
| static void fl_mock_scrolling_view_set_pan_zoom_handler( |
| FlMockScrollingViewDelegate* self, |
| PointerPanZoomCallHandler handler) { |
| self->pan_zoom_handler = std::move(handler); |
| } |
| |
| /***** End FlMockScrollingViewDelegate *****/ |
| |
| class ScrollingTester { |
| public: |
| ScrollingTester() { |
| view_ = fl_mock_scrolling_view_delegate_new(); |
| manager_ = fl_scrolling_manager_new(FL_SCROLLING_VIEW_DELEGATE(view_)); |
| fl_mock_scrolling_view_set_mouse_handler( |
| view_, |
| [](FlutterPointerPhase phase, size_t timestamp, double x, double y, |
| double scroll_delta_x, double scroll_delta_y, int64_t buttons) { |
| // do nothing |
| }); |
| fl_mock_scrolling_view_set_pan_zoom_handler( |
| view_, |
| [](size_t timestamp, double x, double y, FlutterPointerPhase phase, |
| double pan_x, double pan_y, double scale, double rotation) { |
| // do nothing |
| }); |
| } |
| |
| ~ScrollingTester() { |
| g_clear_object(&view_); |
| g_clear_object(&manager_); |
| } |
| |
| FlScrollingManager* manager() { return manager_; } |
| |
| void recordMousePointerCallsTo( |
| std::vector<MousePointerEventRecord>& storage) { |
| fl_mock_scrolling_view_set_mouse_handler( |
| view_, [&storage](FlutterPointerPhase phase, size_t timestamp, double x, |
| double y, double scroll_delta_x, |
| double scroll_delta_y, int64_t buttons) { |
| storage.push_back(MousePointerEventRecord{ |
| .phase = phase, |
| .timestamp = timestamp, |
| .x = x, |
| .y = y, |
| .scroll_delta_x = scroll_delta_x, |
| .scroll_delta_y = scroll_delta_y, |
| .buttons = buttons, |
| }); |
| }); |
| } |
| |
| void recordPointerPanZoomCallsTo( |
| std::vector<PointerPanZoomEventRecord>& storage) { |
| fl_mock_scrolling_view_set_pan_zoom_handler( |
| view_, [&storage](size_t timestamp, double x, double y, |
| FlutterPointerPhase phase, double pan_x, double pan_y, |
| double scale, double rotation) { |
| storage.push_back(PointerPanZoomEventRecord{ |
| .timestamp = timestamp, |
| .x = x, |
| .y = y, |
| .phase = phase, |
| .pan_x = pan_x, |
| .pan_y = pan_y, |
| .scale = scale, |
| .rotation = rotation, |
| }); |
| }); |
| } |
| |
| private: |
| FlMockScrollingViewDelegate* view_; |
| FlScrollingManager* manager_; |
| }; |
| |
| // Disgusting hack but could not find any way to create a GdkDevice |
| struct _FakeGdkDevice { |
| GObject parent_instance; |
| gchar* name; |
| GdkInputSource source; |
| }; |
| GdkDevice* makeFakeDevice(GdkInputSource source) { |
| _FakeGdkDevice* device = (_FakeGdkDevice*)g_malloc0(sizeof(_FakeGdkDevice)); |
| device->source = source; |
| // Bully the type checker |
| ((GTypeInstance*)device)->g_class = |
| (GTypeClass*)g_malloc0(sizeof(GTypeClass)); |
| ((GTypeInstance*)device)->g_class->g_type = GDK_TYPE_DEVICE; |
| return (GdkDevice*)device; |
| } |
| |
| TEST(FlScrollingManagerTest, DiscreteDirectionional) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| GdkDevice* mouse = makeFakeDevice(GDK_SOURCE_MOUSE); |
| GdkEventScroll* event = (GdkEventScroll*)gdk_event_new(GDK_SCROLL); |
| event->time = 1; |
| event->x = 4.0; |
| event->y = 8.0; |
| event->device = mouse; |
| event->direction = GDK_SCROLL_UP; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 0u); |
| EXPECT_EQ(mouse_records.size(), 1u); |
| EXPECT_EQ(mouse_records[0].x, 4.0); |
| EXPECT_EQ(mouse_records[0].y, 8.0); |
| EXPECT_EQ(mouse_records[0].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(mouse_records[0].scroll_delta_x, 0); |
| EXPECT_EQ(mouse_records[0].scroll_delta_y, 53 * -1.0); |
| event->direction = GDK_SCROLL_DOWN; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 0u); |
| EXPECT_EQ(mouse_records.size(), 2u); |
| EXPECT_EQ(mouse_records[1].x, 4.0); |
| EXPECT_EQ(mouse_records[1].y, 8.0); |
| EXPECT_EQ(mouse_records[1].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(mouse_records[1].scroll_delta_x, 0); |
| EXPECT_EQ(mouse_records[1].scroll_delta_y, 53 * 1.0); |
| event->direction = GDK_SCROLL_LEFT; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 0u); |
| EXPECT_EQ(mouse_records.size(), 3u); |
| EXPECT_EQ(mouse_records[2].x, 4.0); |
| EXPECT_EQ(mouse_records[2].y, 8.0); |
| EXPECT_EQ(mouse_records[2].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(mouse_records[2].scroll_delta_x, 53 * -1.0); |
| EXPECT_EQ(mouse_records[2].scroll_delta_y, 0); |
| event->direction = GDK_SCROLL_RIGHT; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 0u); |
| EXPECT_EQ(mouse_records.size(), 4u); |
| EXPECT_EQ(mouse_records[3].x, 4.0); |
| EXPECT_EQ(mouse_records[3].y, 8.0); |
| EXPECT_EQ(mouse_records[3].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(mouse_records[3].scroll_delta_x, 53 * 1.0); |
| EXPECT_EQ(mouse_records[3].scroll_delta_y, 0); |
| } |
| |
| TEST(FlScrollingManagerTest, DiscreteScrolling) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| GdkDevice* mouse = makeFakeDevice(GDK_SOURCE_MOUSE); |
| GdkEventScroll* event = (GdkEventScroll*)gdk_event_new(GDK_SCROLL); |
| event->time = 1; |
| event->x = 4.0; |
| event->y = 8.0; |
| event->delta_x = 1.0; |
| event->delta_y = 2.0; |
| event->device = mouse; |
| event->direction = GDK_SCROLL_SMOOTH; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 0u); |
| EXPECT_EQ(mouse_records.size(), 1u); |
| EXPECT_EQ(mouse_records[0].x, 4.0); |
| EXPECT_EQ(mouse_records[0].y, 8.0); |
| EXPECT_EQ(mouse_records[0].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(mouse_records[0].scroll_delta_x, 53 * 1.0); |
| EXPECT_EQ(mouse_records[0].scroll_delta_y, 53 * 2.0); |
| } |
| |
| TEST(FlScrollingManagerTest, Panning) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| GdkDevice* touchpad = makeFakeDevice(GDK_SOURCE_TOUCHPAD); |
| GdkEventScroll* event = (GdkEventScroll*)gdk_event_new(GDK_SCROLL); |
| event->time = 1; |
| event->x = 4.0; |
| event->y = 8.0; |
| event->delta_x = 1.0; |
| event->delta_y = 2.0; |
| event->device = touchpad; |
| event->direction = GDK_SCROLL_SMOOTH; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[0].x, 4.0); |
| EXPECT_EQ(pan_zoom_records[0].y, 8.0); |
| EXPECT_EQ(pan_zoom_records[0].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(pan_zoom_records[0].phase, kPanZoomStart); |
| EXPECT_EQ(pan_zoom_records[1].x, 4.0); |
| EXPECT_EQ(pan_zoom_records[1].y, 8.0); |
| EXPECT_EQ(pan_zoom_records[1].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(pan_zoom_records[1].phase, kPanZoomUpdate); |
| EXPECT_EQ(pan_zoom_records[1].pan_x, 53 * -1.0); // directions get swapped |
| EXPECT_EQ(pan_zoom_records[1].pan_y, 53 * -2.0); |
| EXPECT_EQ(pan_zoom_records[1].scale, 1.0); |
| EXPECT_EQ(pan_zoom_records[1].rotation, 0.0); |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[2].x, 4.0); |
| EXPECT_EQ(pan_zoom_records[2].y, 8.0); |
| EXPECT_EQ(pan_zoom_records[2].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(pan_zoom_records[2].phase, kPanZoomUpdate); |
| EXPECT_EQ(pan_zoom_records[2].pan_x, 53 * -2.0); // directions get swapped |
| EXPECT_EQ(pan_zoom_records[2].pan_y, 53 * -4.0); |
| EXPECT_EQ(pan_zoom_records[2].scale, 1.0); |
| EXPECT_EQ(pan_zoom_records[2].rotation, 0.0); |
| event->is_stop = true; |
| fl_scrolling_manager_handle_scroll_event(tester.manager(), event, 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 4u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[3].x, 4.0); |
| EXPECT_EQ(pan_zoom_records[3].y, 8.0); |
| EXPECT_EQ(pan_zoom_records[3].timestamp, |
| 1000lu); // Milliseconds -> Microseconds |
| EXPECT_EQ(pan_zoom_records[3].phase, kPanZoomEnd); |
| } |
| |
| TEST(FlScrollingManagerTest, Zooming) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| size_t time_start = g_get_real_time(); |
| fl_scrolling_manager_handle_zoom_begin(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 1u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[0].x, 0); |
| EXPECT_EQ(pan_zoom_records[0].y, 0); |
| EXPECT_EQ(pan_zoom_records[0].phase, kPanZoomStart); |
| EXPECT_GE(pan_zoom_records[0].timestamp, time_start); |
| fl_scrolling_manager_handle_zoom_update(tester.manager(), 1.1); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[1].x, 0); |
| EXPECT_EQ(pan_zoom_records[1].y, 0); |
| EXPECT_EQ(pan_zoom_records[1].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp); |
| EXPECT_EQ(pan_zoom_records[1].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[1].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[1].scale, 1.1); |
| EXPECT_EQ(pan_zoom_records[1].rotation, 0); |
| fl_scrolling_manager_handle_zoom_end(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[2].x, 0); |
| EXPECT_EQ(pan_zoom_records[2].y, 0); |
| EXPECT_EQ(pan_zoom_records[2].phase, kPanZoomEnd); |
| EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp); |
| } |
| |
| TEST(FlScrollingManagerTest, Rotating) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| size_t time_start = g_get_real_time(); |
| fl_scrolling_manager_handle_rotation_begin(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 1u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[0].x, 0); |
| EXPECT_EQ(pan_zoom_records[0].y, 0); |
| EXPECT_EQ(pan_zoom_records[0].phase, kPanZoomStart); |
| EXPECT_GE(pan_zoom_records[0].timestamp, time_start); |
| fl_scrolling_manager_handle_rotation_update(tester.manager(), 0.5); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[1].x, 0); |
| EXPECT_EQ(pan_zoom_records[1].y, 0); |
| EXPECT_EQ(pan_zoom_records[1].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp); |
| EXPECT_EQ(pan_zoom_records[1].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[1].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[1].scale, 1.0); |
| EXPECT_EQ(pan_zoom_records[1].rotation, 0.5); |
| fl_scrolling_manager_handle_rotation_end(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[2].x, 0); |
| EXPECT_EQ(pan_zoom_records[2].y, 0); |
| EXPECT_EQ(pan_zoom_records[2].phase, kPanZoomEnd); |
| EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp); |
| } |
| |
| TEST(FlScrollingManagerTest, SynchronizedZoomingAndRotating) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| size_t time_start = g_get_real_time(); |
| fl_scrolling_manager_handle_zoom_begin(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 1u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[0].x, 0); |
| EXPECT_EQ(pan_zoom_records[0].y, 0); |
| EXPECT_EQ(pan_zoom_records[0].phase, kPanZoomStart); |
| EXPECT_GE(pan_zoom_records[0].timestamp, time_start); |
| fl_scrolling_manager_handle_zoom_update(tester.manager(), 1.1); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[1].x, 0); |
| EXPECT_EQ(pan_zoom_records[1].y, 0); |
| EXPECT_EQ(pan_zoom_records[1].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp); |
| EXPECT_EQ(pan_zoom_records[1].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[1].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[1].scale, 1.1); |
| EXPECT_EQ(pan_zoom_records[1].rotation, 0); |
| fl_scrolling_manager_handle_rotation_begin(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| fl_scrolling_manager_handle_rotation_update(tester.manager(), 0.5); |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| EXPECT_EQ(pan_zoom_records[2].x, 0); |
| EXPECT_EQ(pan_zoom_records[2].y, 0); |
| EXPECT_EQ(pan_zoom_records[2].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp); |
| EXPECT_EQ(pan_zoom_records[2].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[2].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[2].scale, 1.1); |
| EXPECT_EQ(pan_zoom_records[2].rotation, 0.5); |
| fl_scrolling_manager_handle_zoom_end(tester.manager()); |
| // End event should only be sent after both zoom and rotate complete. |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| fl_scrolling_manager_handle_rotation_end(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 4u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[3].x, 0); |
| EXPECT_EQ(pan_zoom_records[3].y, 0); |
| EXPECT_EQ(pan_zoom_records[3].phase, kPanZoomEnd); |
| EXPECT_GE(pan_zoom_records[3].timestamp, pan_zoom_records[2].timestamp); |
| } |
| |
| // Make sure that zoom and rotate sequences which don't end at the same time |
| // don't cause any problems. |
| TEST(FlScrollingManagerTest, UnsynchronizedZoomingAndRotating) { |
| ScrollingTester tester; |
| std::vector<MousePointerEventRecord> mouse_records; |
| std::vector<PointerPanZoomEventRecord> pan_zoom_records; |
| tester.recordMousePointerCallsTo(mouse_records); |
| tester.recordPointerPanZoomCallsTo(pan_zoom_records); |
| size_t time_start = g_get_real_time(); |
| fl_scrolling_manager_handle_zoom_begin(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 1u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[0].x, 0); |
| EXPECT_EQ(pan_zoom_records[0].y, 0); |
| EXPECT_EQ(pan_zoom_records[0].phase, kPanZoomStart); |
| EXPECT_GE(pan_zoom_records[0].timestamp, time_start); |
| fl_scrolling_manager_handle_zoom_update(tester.manager(), 1.1); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[1].x, 0); |
| EXPECT_EQ(pan_zoom_records[1].y, 0); |
| EXPECT_EQ(pan_zoom_records[1].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp); |
| EXPECT_EQ(pan_zoom_records[1].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[1].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[1].scale, 1.1); |
| EXPECT_EQ(pan_zoom_records[1].rotation, 0); |
| fl_scrolling_manager_handle_rotation_begin(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 2u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| fl_scrolling_manager_handle_rotation_update(tester.manager(), 0.5); |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| EXPECT_EQ(pan_zoom_records[2].x, 0); |
| EXPECT_EQ(pan_zoom_records[2].y, 0); |
| EXPECT_EQ(pan_zoom_records[2].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp); |
| EXPECT_EQ(pan_zoom_records[2].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[2].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[2].scale, 1.1); |
| EXPECT_EQ(pan_zoom_records[2].rotation, 0.5); |
| fl_scrolling_manager_handle_zoom_end(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 3u); |
| fl_scrolling_manager_handle_rotation_update(tester.manager(), 1.0); |
| EXPECT_EQ(pan_zoom_records.size(), 4u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[3].x, 0); |
| EXPECT_EQ(pan_zoom_records[3].y, 0); |
| EXPECT_EQ(pan_zoom_records[3].phase, kPanZoomUpdate); |
| EXPECT_GE(pan_zoom_records[3].timestamp, pan_zoom_records[2].timestamp); |
| EXPECT_EQ(pan_zoom_records[3].pan_x, 0); |
| EXPECT_EQ(pan_zoom_records[3].pan_y, 0); |
| EXPECT_EQ(pan_zoom_records[3].scale, 1.1); |
| EXPECT_EQ(pan_zoom_records[3].rotation, 1.0); |
| fl_scrolling_manager_handle_rotation_end(tester.manager()); |
| EXPECT_EQ(pan_zoom_records.size(), 5u); |
| EXPECT_EQ(mouse_records.size(), 0u); |
| EXPECT_EQ(pan_zoom_records[4].x, 0); |
| EXPECT_EQ(pan_zoom_records[4].y, 0); |
| EXPECT_EQ(pan_zoom_records[4].phase, kPanZoomEnd); |
| EXPECT_GE(pan_zoom_records[4].timestamp, pan_zoom_records[3].timestamp); |
| } |
| |
| } // namespace |