Flutter Linux Embedder
fl_scrolling_manager_test.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
8 
9 #include <gdk/gdkwayland.h>
10 #include <cstring>
11 #include <vector>
12 
13 #include "flutter/shell/platform/linux/testing/linux_test.h"
14 #include "gtest/gtest.h"
15 
16 class FlScrollingManagerTest : public flutter::testing::LinuxTest {};
17 
18 TEST_F(FlScrollingManagerTest, DiscreteDirectional) {
19  StartEngine();
20 
21  std::vector<FlutterPointerEvent> pointer_events;
22  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
23  SendPointerEvent,
24  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
25  size_t events_count) {
26  for (size_t i = 0; i < events_count; i++) {
27  pointer_events.push_back(events[i]);
28  }
29 
30  return kSuccess;
31  }));
32 
33  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
34 
35  GdkDevice* mouse =
36  GDK_DEVICE(g_object_new(gdk_wayland_device_get_type(), "input-source",
37  GDK_SOURCE_MOUSE, nullptr));
38  GdkEventScroll* event =
39  reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
40  event->time = 1;
41  event->x = 4.0;
42  event->y = 8.0;
43  event->device = mouse;
44  event->direction = GDK_SCROLL_UP;
45  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
46  EXPECT_EQ(pointer_events.size(), 1u);
47  EXPECT_EQ(pointer_events[0].x, 4.0);
48  EXPECT_EQ(pointer_events[0].y, 8.0);
49  EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindMouse);
50  EXPECT_EQ(pointer_events[0].timestamp,
51  1000lu); // Milliseconds -> Microseconds
52  EXPECT_EQ(pointer_events[0].scroll_delta_x, 0);
53  EXPECT_EQ(pointer_events[0].scroll_delta_y, 53 * -1.0);
54  event->direction = GDK_SCROLL_DOWN;
55  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
56  EXPECT_EQ(pointer_events.size(), 2u);
57  EXPECT_EQ(pointer_events[1].x, 4.0);
58  EXPECT_EQ(pointer_events[1].y, 8.0);
59  EXPECT_EQ(pointer_events[1].device_kind, kFlutterPointerDeviceKindMouse);
60  EXPECT_EQ(pointer_events[1].timestamp,
61  1000lu); // Milliseconds -> Microseconds
62  EXPECT_EQ(pointer_events[1].scroll_delta_x, 0);
63  EXPECT_EQ(pointer_events[1].scroll_delta_y, 53 * 1.0);
64  event->direction = GDK_SCROLL_LEFT;
65  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
66  EXPECT_EQ(pointer_events.size(), 3u);
67  EXPECT_EQ(pointer_events[2].x, 4.0);
68  EXPECT_EQ(pointer_events[2].y, 8.0);
69  EXPECT_EQ(pointer_events[2].device_kind, kFlutterPointerDeviceKindMouse);
70  EXPECT_EQ(pointer_events[2].timestamp,
71  1000lu); // Milliseconds -> Microseconds
72  EXPECT_EQ(pointer_events[2].scroll_delta_x, 53 * -1.0);
73  EXPECT_EQ(pointer_events[2].scroll_delta_y, 0);
74  event->direction = GDK_SCROLL_RIGHT;
75  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
76  EXPECT_EQ(pointer_events.size(), 4u);
77  EXPECT_EQ(pointer_events[3].x, 4.0);
78  EXPECT_EQ(pointer_events[3].y, 8.0);
79  EXPECT_EQ(pointer_events[3].device_kind, kFlutterPointerDeviceKindMouse);
80  EXPECT_EQ(pointer_events[3].timestamp,
81  1000lu); // Milliseconds -> Microseconds
82  EXPECT_EQ(pointer_events[3].scroll_delta_x, 53 * 1.0);
83  EXPECT_EQ(pointer_events[3].scroll_delta_y, 0);
84 }
85 
86 TEST_F(FlScrollingManagerTest, DiscreteScrolling) {
87  StartEngine();
88 
89  std::vector<FlutterPointerEvent> pointer_events;
90  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
91  SendPointerEvent,
92  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
93  size_t events_count) {
94  for (size_t i = 0; i < events_count; i++) {
95  pointer_events.push_back(events[i]);
96  }
97 
98  return kSuccess;
99  }));
100 
101  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
102 
103  GdkDevice* mouse =
104  GDK_DEVICE(g_object_new(gdk_wayland_device_get_type(), "input-source",
105  GDK_SOURCE_MOUSE, nullptr));
106  GdkEventScroll* event =
107  reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
108  event->time = 1;
109  event->x = 4.0;
110  event->y = 8.0;
111  event->delta_x = 1.0;
112  event->delta_y = 2.0;
113  event->device = mouse;
114  event->direction = GDK_SCROLL_SMOOTH;
115  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
116  EXPECT_EQ(pointer_events.size(), 1u);
117  EXPECT_EQ(pointer_events[0].x, 4.0);
118  EXPECT_EQ(pointer_events[0].y, 8.0);
119  EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindMouse);
120  EXPECT_EQ(pointer_events[0].timestamp,
121  1000lu); // Milliseconds -> Microseconds
122  EXPECT_EQ(pointer_events[0].scroll_delta_x, 53 * 1.0);
123  EXPECT_EQ(pointer_events[0].scroll_delta_y, 53 * 2.0);
124 }
125 
127  StartEngine();
128 
129  std::vector<FlutterPointerEvent> pointer_events;
130  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
131  SendPointerEvent,
132  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
133  size_t events_count) {
134  for (size_t i = 0; i < events_count; i++) {
135  pointer_events.push_back(events[i]);
136  }
137 
138  return kSuccess;
139  }));
140 
141  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
142 
143  GdkDevice* touchpad =
144  GDK_DEVICE(g_object_new(gdk_wayland_device_get_type(), "input-source",
145  GDK_SOURCE_TOUCHPAD, nullptr));
146  GdkEventScroll* event =
147  reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
148  event->time = 1;
149  event->x = 4.0;
150  event->y = 8.0;
151  event->delta_x = 1.0;
152  event->delta_y = 2.0;
153  event->device = touchpad;
154  event->direction = GDK_SCROLL_SMOOTH;
155  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
156  EXPECT_EQ(pointer_events.size(), 2u);
157  EXPECT_EQ(pointer_events[0].x, 4.0);
158  EXPECT_EQ(pointer_events[0].y, 8.0);
159  EXPECT_EQ(pointer_events[0].timestamp,
160  1000lu); // Milliseconds -> Microseconds
161  EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
162  EXPECT_EQ(pointer_events[1].x, 4.0);
163  EXPECT_EQ(pointer_events[1].y, 8.0);
164  EXPECT_EQ(pointer_events[1].timestamp,
165  1000lu); // Milliseconds -> Microseconds
166  EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
167  EXPECT_EQ(pointer_events[1].pan_x, 53 * -1.0); // directions get swapped
168  EXPECT_EQ(pointer_events[1].pan_y, 53 * -2.0);
169  EXPECT_EQ(pointer_events[1].scale, 1.0);
170  EXPECT_EQ(pointer_events[1].rotation, 0.0);
171  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
172  EXPECT_EQ(pointer_events.size(), 3u);
173  EXPECT_EQ(pointer_events[2].x, 4.0);
174  EXPECT_EQ(pointer_events[2].y, 8.0);
175  EXPECT_EQ(pointer_events[2].timestamp,
176  1000lu); // Milliseconds -> Microseconds
177  EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
178  EXPECT_EQ(pointer_events[2].pan_x, 53 * -2.0); // directions get swapped
179  EXPECT_EQ(pointer_events[2].pan_y, 53 * -4.0);
180  EXPECT_EQ(pointer_events[2].scale, 1.0);
181  EXPECT_EQ(pointer_events[2].rotation, 0.0);
182  event->is_stop = true;
183  fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
184  EXPECT_EQ(pointer_events.size(), 4u);
185  EXPECT_EQ(pointer_events[3].x, 4.0);
186  EXPECT_EQ(pointer_events[3].y, 8.0);
187  EXPECT_EQ(pointer_events[3].timestamp,
188  1000lu); // Milliseconds -> Microseconds
189  EXPECT_EQ(pointer_events[3].phase, kPanZoomEnd);
190 }
191 
193  StartEngine();
194 
195  std::vector<FlutterPointerEvent> pointer_events;
196  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
197  SendPointerEvent,
198  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
199  size_t events_count) {
200  for (size_t i = 0; i < events_count; i++) {
201  pointer_events.push_back(events[i]);
202  }
203 
204  return kSuccess;
205  }));
206 
207  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
208 
209  size_t time_start = g_get_real_time();
211  EXPECT_EQ(pointer_events.size(), 1u);
212  EXPECT_EQ(pointer_events[0].x, 0);
213  EXPECT_EQ(pointer_events[0].y, 0);
214  EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
215  EXPECT_GE(pointer_events[0].timestamp, time_start);
217  EXPECT_EQ(pointer_events.size(), 2u);
218  EXPECT_EQ(pointer_events[1].x, 0);
219  EXPECT_EQ(pointer_events[1].y, 0);
220  EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
221  EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
222  EXPECT_EQ(pointer_events[1].pan_x, 0);
223  EXPECT_EQ(pointer_events[1].pan_y, 0);
224  EXPECT_EQ(pointer_events[1].scale, 1.1);
225  EXPECT_EQ(pointer_events[1].rotation, 0);
227  EXPECT_EQ(pointer_events.size(), 3u);
228  EXPECT_EQ(pointer_events[2].x, 0);
229  EXPECT_EQ(pointer_events[2].y, 0);
230  EXPECT_EQ(pointer_events[2].phase, kPanZoomEnd);
231  EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
232 }
233 
235  StartEngine();
236 
237  std::vector<FlutterPointerEvent> pointer_events;
238  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
239  SendPointerEvent,
240  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
241  size_t events_count) {
242  for (size_t i = 0; i < events_count; i++) {
243  pointer_events.push_back(events[i]);
244  }
245 
246  return kSuccess;
247  }));
248 
249  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
250 
251  size_t time_start = g_get_real_time();
253  EXPECT_EQ(pointer_events.size(), 1u);
254  EXPECT_EQ(pointer_events[0].x, 0);
255  EXPECT_EQ(pointer_events[0].y, 0);
256  EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
257  EXPECT_GE(pointer_events[0].timestamp, time_start);
259  EXPECT_EQ(pointer_events.size(), 2u);
260  EXPECT_EQ(pointer_events[1].x, 0);
261  EXPECT_EQ(pointer_events[1].y, 0);
262  EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
263  EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
264  EXPECT_EQ(pointer_events[1].pan_x, 0);
265  EXPECT_EQ(pointer_events[1].pan_y, 0);
266  EXPECT_EQ(pointer_events[1].scale, 1.0);
267  EXPECT_EQ(pointer_events[1].rotation, 0.5);
269  EXPECT_EQ(pointer_events.size(), 3u);
270  EXPECT_EQ(pointer_events[2].x, 0);
271  EXPECT_EQ(pointer_events[2].y, 0);
272  EXPECT_EQ(pointer_events[2].phase, kPanZoomEnd);
273  EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
274 }
275 
276 TEST_F(FlScrollingManagerTest, SynchronizedZoomingAndRotating) {
277  StartEngine();
278 
279  std::vector<FlutterPointerEvent> pointer_events;
280  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
281  SendPointerEvent,
282  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
283  size_t events_count) {
284  for (size_t i = 0; i < events_count; i++) {
285  pointer_events.push_back(events[i]);
286  }
287 
288  return kSuccess;
289  }));
290 
291  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
292 
293  size_t time_start = g_get_real_time();
295  EXPECT_EQ(pointer_events.size(), 1u);
296  EXPECT_EQ(pointer_events[0].x, 0);
297  EXPECT_EQ(pointer_events[0].y, 0);
298  EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
299  EXPECT_GE(pointer_events[0].timestamp, time_start);
301  EXPECT_EQ(pointer_events.size(), 2u);
302  EXPECT_EQ(pointer_events[1].x, 0);
303  EXPECT_EQ(pointer_events[1].y, 0);
304  EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
305  EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
306  EXPECT_EQ(pointer_events[1].pan_x, 0);
307  EXPECT_EQ(pointer_events[1].pan_y, 0);
308  EXPECT_EQ(pointer_events[1].scale, 1.1);
309  EXPECT_EQ(pointer_events[1].rotation, 0);
311  EXPECT_EQ(pointer_events.size(), 2u);
313  EXPECT_EQ(pointer_events.size(), 3u);
314  EXPECT_EQ(pointer_events[2].x, 0);
315  EXPECT_EQ(pointer_events[2].y, 0);
316  EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
317  EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
318  EXPECT_EQ(pointer_events[2].pan_x, 0);
319  EXPECT_EQ(pointer_events[2].pan_y, 0);
320  EXPECT_EQ(pointer_events[2].scale, 1.1);
321  EXPECT_EQ(pointer_events[2].rotation, 0.5);
323  // End event should only be sent after both zoom and rotate complete.
324  EXPECT_EQ(pointer_events.size(), 3u);
326  EXPECT_EQ(pointer_events.size(), 4u);
327  EXPECT_EQ(pointer_events[3].x, 0);
328  EXPECT_EQ(pointer_events[3].y, 0);
329  EXPECT_EQ(pointer_events[3].phase, kPanZoomEnd);
330  EXPECT_GE(pointer_events[3].timestamp, pointer_events[2].timestamp);
331 }
332 
333 // Make sure that zoom and rotate sequences which don't end at the same time
334 // don't cause any problems.
335 TEST_F(FlScrollingManagerTest, UnsynchronizedZoomingAndRotating) {
336  StartEngine();
337 
338  std::vector<FlutterPointerEvent> pointer_events;
339  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
340  SendPointerEvent,
341  ([&pointer_events](auto engine, const FlutterPointerEvent* events,
342  size_t events_count) {
343  for (size_t i = 0; i < events_count; i++) {
344  pointer_events.push_back(events[i]);
345  }
346 
347  return kSuccess;
348  }));
349 
350  g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
351 
352  size_t time_start = g_get_real_time();
354  EXPECT_EQ(pointer_events.size(), 1u);
355  EXPECT_EQ(pointer_events[0].x, 0);
356  EXPECT_EQ(pointer_events[0].y, 0);
357  EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
358  EXPECT_GE(pointer_events[0].timestamp, time_start);
360  EXPECT_EQ(pointer_events.size(), 2u);
361  EXPECT_EQ(pointer_events[1].x, 0);
362  EXPECT_EQ(pointer_events[1].y, 0);
363  EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
364  EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
365  EXPECT_EQ(pointer_events[1].pan_x, 0);
366  EXPECT_EQ(pointer_events[1].pan_y, 0);
367  EXPECT_EQ(pointer_events[1].scale, 1.1);
368  EXPECT_EQ(pointer_events[1].rotation, 0);
370  EXPECT_EQ(pointer_events.size(), 2u);
372  EXPECT_EQ(pointer_events.size(), 3u);
373  EXPECT_EQ(pointer_events[2].x, 0);
374  EXPECT_EQ(pointer_events[2].y, 0);
375  EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
376  EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
377  EXPECT_EQ(pointer_events[2].pan_x, 0);
378  EXPECT_EQ(pointer_events[2].pan_y, 0);
379  EXPECT_EQ(pointer_events[2].scale, 1.1);
380  EXPECT_EQ(pointer_events[2].rotation, 0.5);
382  EXPECT_EQ(pointer_events.size(), 3u);
384  EXPECT_EQ(pointer_events.size(), 4u);
385  EXPECT_EQ(pointer_events[3].x, 0);
386  EXPECT_EQ(pointer_events[3].y, 0);
387  EXPECT_EQ(pointer_events[3].phase, kPanZoomUpdate);
388  EXPECT_GE(pointer_events[3].timestamp, pointer_events[2].timestamp);
389  EXPECT_EQ(pointer_events[3].pan_x, 0);
390  EXPECT_EQ(pointer_events[3].pan_y, 0);
391  EXPECT_EQ(pointer_events[3].scale, 1.1);
392  EXPECT_EQ(pointer_events[3].rotation, 1.0);
394  EXPECT_EQ(pointer_events.size(), 5u);
395  EXPECT_EQ(pointer_events[4].x, 0);
396  EXPECT_EQ(pointer_events[4].y, 0);
397  EXPECT_EQ(pointer_events[4].phase, kPanZoomEnd);
398  EXPECT_GE(pointer_events[4].timestamp, pointer_events[3].timestamp);
399 }
g_autoptr(FlEngine) engine
FlFramebuffer double x
FlFramebuffer double double y
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:920
void fl_scrolling_manager_handle_rotation_begin(FlScrollingManager *self)
void fl_scrolling_manager_handle_rotation_end(FlScrollingManager *self)
void fl_scrolling_manager_handle_scroll_event(FlScrollingManager *self, GdkEventScroll *scroll_event, gint scale_factor)
FlScrollingManager * fl_scrolling_manager_new(FlEngine *engine, FlutterViewId view_id)
void fl_scrolling_manager_handle_zoom_update(FlScrollingManager *self, gdouble scale)
void fl_scrolling_manager_handle_rotation_update(FlScrollingManager *self, gdouble rotation)
void fl_scrolling_manager_handle_zoom_begin(FlScrollingManager *self)
void fl_scrolling_manager_handle_zoom_end(FlScrollingManager *self)
TEST_F(FlScrollingManagerTest, DiscreteDirectional)