Flutter Engine
 
Loading...
Searching...
No Matches
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
8
9#include <gdk/gdkwayland.h>
10#include <cstring>
11#include <vector>
12
13#include "gtest/gtest.h"
14
15TEST(FlScrollingManagerTest, DiscreteDirectional) {
16 g_autoptr(FlDartProject) project = fl_dart_project_new();
17 g_autoptr(FlEngine) engine = fl_engine_new(project);
18
19 g_autoptr(GError) error = nullptr;
20 EXPECT_TRUE(fl_engine_start(engine, &error));
21 EXPECT_EQ(error, nullptr);
22
23 std::vector<FlutterPointerEvent> pointer_events;
25 SendPointerEvent,
26 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
27 size_t events_count) {
28 for (size_t i = 0; i < events_count; i++) {
29 pointer_events.push_back(events[i]);
30 }
31
32 return kSuccess;
33 }));
34
35 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
36
37 GdkDevice* mouse =
38 GDK_DEVICE(g_object_new(gdk_wayland_device_get_type(), "input-source",
39 GDK_SOURCE_MOUSE, nullptr));
40 GdkEventScroll* event =
41 reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
42 event->time = 1;
43 event->x = 4.0;
44 event->y = 8.0;
45 event->device = mouse;
46 event->direction = GDK_SCROLL_UP;
48 EXPECT_EQ(pointer_events.size(), 1u);
49 EXPECT_EQ(pointer_events[0].x, 4.0);
50 EXPECT_EQ(pointer_events[0].y, 8.0);
51 EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindMouse);
52 EXPECT_EQ(pointer_events[0].timestamp,
53 1000lu); // Milliseconds -> Microseconds
54 EXPECT_EQ(pointer_events[0].scroll_delta_x, 0);
55 EXPECT_EQ(pointer_events[0].scroll_delta_y, 53 * -1.0);
56 event->direction = GDK_SCROLL_DOWN;
58 EXPECT_EQ(pointer_events.size(), 2u);
59 EXPECT_EQ(pointer_events[1].x, 4.0);
60 EXPECT_EQ(pointer_events[1].y, 8.0);
61 EXPECT_EQ(pointer_events[1].device_kind, kFlutterPointerDeviceKindMouse);
62 EXPECT_EQ(pointer_events[1].timestamp,
63 1000lu); // Milliseconds -> Microseconds
64 EXPECT_EQ(pointer_events[1].scroll_delta_x, 0);
65 EXPECT_EQ(pointer_events[1].scroll_delta_y, 53 * 1.0);
66 event->direction = GDK_SCROLL_LEFT;
68 EXPECT_EQ(pointer_events.size(), 3u);
69 EXPECT_EQ(pointer_events[2].x, 4.0);
70 EXPECT_EQ(pointer_events[2].y, 8.0);
71 EXPECT_EQ(pointer_events[2].device_kind, kFlutterPointerDeviceKindMouse);
72 EXPECT_EQ(pointer_events[2].timestamp,
73 1000lu); // Milliseconds -> Microseconds
74 EXPECT_EQ(pointer_events[2].scroll_delta_x, 53 * -1.0);
75 EXPECT_EQ(pointer_events[2].scroll_delta_y, 0);
76 event->direction = GDK_SCROLL_RIGHT;
78 EXPECT_EQ(pointer_events.size(), 4u);
79 EXPECT_EQ(pointer_events[3].x, 4.0);
80 EXPECT_EQ(pointer_events[3].y, 8.0);
81 EXPECT_EQ(pointer_events[3].device_kind, kFlutterPointerDeviceKindMouse);
82 EXPECT_EQ(pointer_events[3].timestamp,
83 1000lu); // Milliseconds -> Microseconds
84 EXPECT_EQ(pointer_events[3].scroll_delta_x, 53 * 1.0);
85 EXPECT_EQ(pointer_events[3].scroll_delta_y, 0);
86}
87
88TEST(FlScrollingManagerTest, DiscreteScrolling) {
89 g_autoptr(FlDartProject) project = fl_dart_project_new();
90 g_autoptr(FlEngine) engine = fl_engine_new(project);
91
92 g_autoptr(GError) error = nullptr;
93 EXPECT_TRUE(fl_engine_start(engine, &error));
94 EXPECT_EQ(error, nullptr);
95
96 std::vector<FlutterPointerEvent> pointer_events;
98 SendPointerEvent,
99 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
100 size_t events_count) {
101 for (size_t i = 0; i < events_count; i++) {
102 pointer_events.push_back(events[i]);
103 }
104
105 return kSuccess;
106 }));
107
108 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
109
110 GdkDevice* mouse =
111 GDK_DEVICE(g_object_new(gdk_wayland_device_get_type(), "input-source",
112 GDK_SOURCE_MOUSE, nullptr));
113 GdkEventScroll* event =
114 reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
115 event->time = 1;
116 event->x = 4.0;
117 event->y = 8.0;
118 event->delta_x = 1.0;
119 event->delta_y = 2.0;
120 event->device = mouse;
121 event->direction = GDK_SCROLL_SMOOTH;
122 fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
123 EXPECT_EQ(pointer_events.size(), 1u);
124 EXPECT_EQ(pointer_events[0].x, 4.0);
125 EXPECT_EQ(pointer_events[0].y, 8.0);
126 EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindMouse);
127 EXPECT_EQ(pointer_events[0].timestamp,
128 1000lu); // Milliseconds -> Microseconds
129 EXPECT_EQ(pointer_events[0].scroll_delta_x, 53 * 1.0);
130 EXPECT_EQ(pointer_events[0].scroll_delta_y, 53 * 2.0);
131}
132
133TEST(FlScrollingManagerTest, Panning) {
134 g_autoptr(FlDartProject) project = fl_dart_project_new();
135 g_autoptr(FlEngine) engine = fl_engine_new(project);
136
137 g_autoptr(GError) error = nullptr;
138 EXPECT_TRUE(fl_engine_start(engine, &error));
139 EXPECT_EQ(error, nullptr);
140
141 std::vector<FlutterPointerEvent> pointer_events;
143 SendPointerEvent,
144 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
145 size_t events_count) {
146 for (size_t i = 0; i < events_count; i++) {
147 pointer_events.push_back(events[i]);
148 }
149
150 return kSuccess;
151 }));
152
153 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
154
155 GdkDevice* touchpad =
156 GDK_DEVICE(g_object_new(gdk_wayland_device_get_type(), "input-source",
157 GDK_SOURCE_TOUCHPAD, nullptr));
158 GdkEventScroll* event =
159 reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
160 event->time = 1;
161 event->x = 4.0;
162 event->y = 8.0;
163 event->delta_x = 1.0;
164 event->delta_y = 2.0;
165 event->device = touchpad;
166 event->direction = GDK_SCROLL_SMOOTH;
167 fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
168 EXPECT_EQ(pointer_events.size(), 2u);
169 EXPECT_EQ(pointer_events[0].x, 4.0);
170 EXPECT_EQ(pointer_events[0].y, 8.0);
171 EXPECT_EQ(pointer_events[0].timestamp,
172 1000lu); // Milliseconds -> Microseconds
173 EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
174 EXPECT_EQ(pointer_events[1].x, 4.0);
175 EXPECT_EQ(pointer_events[1].y, 8.0);
176 EXPECT_EQ(pointer_events[1].timestamp,
177 1000lu); // Milliseconds -> Microseconds
178 EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
179 EXPECT_EQ(pointer_events[1].pan_x, 53 * -1.0); // directions get swapped
180 EXPECT_EQ(pointer_events[1].pan_y, 53 * -2.0);
181 EXPECT_EQ(pointer_events[1].scale, 1.0);
182 EXPECT_EQ(pointer_events[1].rotation, 0.0);
183 fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
184 EXPECT_EQ(pointer_events.size(), 3u);
185 EXPECT_EQ(pointer_events[2].x, 4.0);
186 EXPECT_EQ(pointer_events[2].y, 8.0);
187 EXPECT_EQ(pointer_events[2].timestamp,
188 1000lu); // Milliseconds -> Microseconds
189 EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
190 EXPECT_EQ(pointer_events[2].pan_x, 53 * -2.0); // directions get swapped
191 EXPECT_EQ(pointer_events[2].pan_y, 53 * -4.0);
192 EXPECT_EQ(pointer_events[2].scale, 1.0);
193 EXPECT_EQ(pointer_events[2].rotation, 0.0);
194 event->is_stop = true;
195 fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
196 EXPECT_EQ(pointer_events.size(), 4u);
197 EXPECT_EQ(pointer_events[3].x, 4.0);
198 EXPECT_EQ(pointer_events[3].y, 8.0);
199 EXPECT_EQ(pointer_events[3].timestamp,
200 1000lu); // Milliseconds -> Microseconds
201 EXPECT_EQ(pointer_events[3].phase, kPanZoomEnd);
202}
203
204TEST(FlScrollingManagerTest, Zooming) {
205 g_autoptr(FlDartProject) project = fl_dart_project_new();
206 g_autoptr(FlEngine) engine = fl_engine_new(project);
207
208 g_autoptr(GError) error = nullptr;
209 EXPECT_TRUE(fl_engine_start(engine, &error));
210 EXPECT_EQ(error, nullptr);
211
212 std::vector<FlutterPointerEvent> pointer_events;
214 SendPointerEvent,
215 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
216 size_t events_count) {
217 for (size_t i = 0; i < events_count; i++) {
218 pointer_events.push_back(events[i]);
219 }
220
221 return kSuccess;
222 }));
223
224 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
225
226 size_t time_start = g_get_real_time();
228 EXPECT_EQ(pointer_events.size(), 1u);
229 EXPECT_EQ(pointer_events[0].x, 0);
230 EXPECT_EQ(pointer_events[0].y, 0);
231 EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
232 EXPECT_GE(pointer_events[0].timestamp, time_start);
234 EXPECT_EQ(pointer_events.size(), 2u);
235 EXPECT_EQ(pointer_events[1].x, 0);
236 EXPECT_EQ(pointer_events[1].y, 0);
237 EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
238 EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
239 EXPECT_EQ(pointer_events[1].pan_x, 0);
240 EXPECT_EQ(pointer_events[1].pan_y, 0);
241 EXPECT_EQ(pointer_events[1].scale, 1.1);
242 EXPECT_EQ(pointer_events[1].rotation, 0);
244 EXPECT_EQ(pointer_events.size(), 3u);
245 EXPECT_EQ(pointer_events[2].x, 0);
246 EXPECT_EQ(pointer_events[2].y, 0);
247 EXPECT_EQ(pointer_events[2].phase, kPanZoomEnd);
248 EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
249}
250
251TEST(FlScrollingManagerTest, Rotating) {
252 g_autoptr(FlDartProject) project = fl_dart_project_new();
253 g_autoptr(FlEngine) engine = fl_engine_new(project);
254
255 g_autoptr(GError) error = nullptr;
256 EXPECT_TRUE(fl_engine_start(engine, &error));
257 EXPECT_EQ(error, nullptr);
258
259 std::vector<FlutterPointerEvent> pointer_events;
261 SendPointerEvent,
262 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
263 size_t events_count) {
264 for (size_t i = 0; i < events_count; i++) {
265 pointer_events.push_back(events[i]);
266 }
267
268 return kSuccess;
269 }));
270
271 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
272
273 size_t time_start = g_get_real_time();
275 EXPECT_EQ(pointer_events.size(), 1u);
276 EXPECT_EQ(pointer_events[0].x, 0);
277 EXPECT_EQ(pointer_events[0].y, 0);
278 EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
279 EXPECT_GE(pointer_events[0].timestamp, time_start);
281 EXPECT_EQ(pointer_events.size(), 2u);
282 EXPECT_EQ(pointer_events[1].x, 0);
283 EXPECT_EQ(pointer_events[1].y, 0);
284 EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
285 EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
286 EXPECT_EQ(pointer_events[1].pan_x, 0);
287 EXPECT_EQ(pointer_events[1].pan_y, 0);
288 EXPECT_EQ(pointer_events[1].scale, 1.0);
289 EXPECT_EQ(pointer_events[1].rotation, 0.5);
291 EXPECT_EQ(pointer_events.size(), 3u);
292 EXPECT_EQ(pointer_events[2].x, 0);
293 EXPECT_EQ(pointer_events[2].y, 0);
294 EXPECT_EQ(pointer_events[2].phase, kPanZoomEnd);
295 EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
296}
297
298TEST(FlScrollingManagerTest, SynchronizedZoomingAndRotating) {
299 g_autoptr(FlDartProject) project = fl_dart_project_new();
300 g_autoptr(FlEngine) engine = fl_engine_new(project);
301
302 g_autoptr(GError) error = nullptr;
303 EXPECT_TRUE(fl_engine_start(engine, &error));
304 EXPECT_EQ(error, nullptr);
305
306 std::vector<FlutterPointerEvent> pointer_events;
308 SendPointerEvent,
309 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
310 size_t events_count) {
311 for (size_t i = 0; i < events_count; i++) {
312 pointer_events.push_back(events[i]);
313 }
314
315 return kSuccess;
316 }));
317
318 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
319
320 size_t time_start = g_get_real_time();
322 EXPECT_EQ(pointer_events.size(), 1u);
323 EXPECT_EQ(pointer_events[0].x, 0);
324 EXPECT_EQ(pointer_events[0].y, 0);
325 EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
326 EXPECT_GE(pointer_events[0].timestamp, time_start);
328 EXPECT_EQ(pointer_events.size(), 2u);
329 EXPECT_EQ(pointer_events[1].x, 0);
330 EXPECT_EQ(pointer_events[1].y, 0);
331 EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
332 EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
333 EXPECT_EQ(pointer_events[1].pan_x, 0);
334 EXPECT_EQ(pointer_events[1].pan_y, 0);
335 EXPECT_EQ(pointer_events[1].scale, 1.1);
336 EXPECT_EQ(pointer_events[1].rotation, 0);
338 EXPECT_EQ(pointer_events.size(), 2u);
340 EXPECT_EQ(pointer_events.size(), 3u);
341 EXPECT_EQ(pointer_events[2].x, 0);
342 EXPECT_EQ(pointer_events[2].y, 0);
343 EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
344 EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
345 EXPECT_EQ(pointer_events[2].pan_x, 0);
346 EXPECT_EQ(pointer_events[2].pan_y, 0);
347 EXPECT_EQ(pointer_events[2].scale, 1.1);
348 EXPECT_EQ(pointer_events[2].rotation, 0.5);
350 // End event should only be sent after both zoom and rotate complete.
351 EXPECT_EQ(pointer_events.size(), 3u);
353 EXPECT_EQ(pointer_events.size(), 4u);
354 EXPECT_EQ(pointer_events[3].x, 0);
355 EXPECT_EQ(pointer_events[3].y, 0);
356 EXPECT_EQ(pointer_events[3].phase, kPanZoomEnd);
357 EXPECT_GE(pointer_events[3].timestamp, pointer_events[2].timestamp);
358}
359
360// Make sure that zoom and rotate sequences which don't end at the same time
361// don't cause any problems.
362TEST(FlScrollingManagerTest, UnsynchronizedZoomingAndRotating) {
363 g_autoptr(FlDartProject) project = fl_dart_project_new();
364 g_autoptr(FlEngine) engine = fl_engine_new(project);
365
366 g_autoptr(GError) error = nullptr;
367 EXPECT_TRUE(fl_engine_start(engine, &error));
368 EXPECT_EQ(error, nullptr);
369
370 std::vector<FlutterPointerEvent> pointer_events;
372 SendPointerEvent,
373 ([&pointer_events](auto engine, const FlutterPointerEvent* events,
374 size_t events_count) {
375 for (size_t i = 0; i < events_count; i++) {
376 pointer_events.push_back(events[i]);
377 }
378
379 return kSuccess;
380 }));
381
382 g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
383
384 size_t time_start = g_get_real_time();
386 EXPECT_EQ(pointer_events.size(), 1u);
387 EXPECT_EQ(pointer_events[0].x, 0);
388 EXPECT_EQ(pointer_events[0].y, 0);
389 EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
390 EXPECT_GE(pointer_events[0].timestamp, time_start);
392 EXPECT_EQ(pointer_events.size(), 2u);
393 EXPECT_EQ(pointer_events[1].x, 0);
394 EXPECT_EQ(pointer_events[1].y, 0);
395 EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
396 EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
397 EXPECT_EQ(pointer_events[1].pan_x, 0);
398 EXPECT_EQ(pointer_events[1].pan_y, 0);
399 EXPECT_EQ(pointer_events[1].scale, 1.1);
400 EXPECT_EQ(pointer_events[1].rotation, 0);
402 EXPECT_EQ(pointer_events.size(), 2u);
404 EXPECT_EQ(pointer_events.size(), 3u);
405 EXPECT_EQ(pointer_events[2].x, 0);
406 EXPECT_EQ(pointer_events[2].y, 0);
407 EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
408 EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
409 EXPECT_EQ(pointer_events[2].pan_x, 0);
410 EXPECT_EQ(pointer_events[2].pan_y, 0);
411 EXPECT_EQ(pointer_events[2].scale, 1.1);
412 EXPECT_EQ(pointer_events[2].rotation, 0.5);
414 EXPECT_EQ(pointer_events.size(), 3u);
416 EXPECT_EQ(pointer_events.size(), 4u);
417 EXPECT_EQ(pointer_events[3].x, 0);
418 EXPECT_EQ(pointer_events[3].y, 0);
419 EXPECT_EQ(pointer_events[3].phase, kPanZoomUpdate);
420 EXPECT_GE(pointer_events[3].timestamp, pointer_events[2].timestamp);
421 EXPECT_EQ(pointer_events[3].pan_x, 0);
422 EXPECT_EQ(pointer_events[3].pan_y, 0);
423 EXPECT_EQ(pointer_events[3].scale, 1.1);
424 EXPECT_EQ(pointer_events[3].rotation, 1.0);
426 EXPECT_EQ(pointer_events.size(), 5u);
427 EXPECT_EQ(pointer_events[4].x, 0);
428 EXPECT_EQ(pointer_events[4].y, 0);
429 EXPECT_EQ(pointer_events[4].phase, kPanZoomEnd);
430 EXPECT_GE(pointer_events[4].timestamp, pointer_events[3].timestamp);
431}
int32_t x
@ kPanZoomUpdate
The pan/zoom updated.
Definition embedder.h:1273
@ kPanZoomStart
A pan/zoom started on this pointer.
Definition embedder.h:1271
@ kPanZoomEnd
The pan/zoom ended.
Definition embedder.h:1275
@ kSuccess
Definition embedder.h:73
@ kFlutterPointerDeviceKindMouse
Definition embedder.h:1280
FlutterEngine engine
Definition main.cc:84
g_autoptr(GMutexLocker) locker
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition fl_engine.cc:697
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition fl_engine.cc:868
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition fl_engine.cc:726
const uint8_t uint32_t uint32_t GError ** error
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)
void fl_scrolling_manager_handle_zoom_update(FlScrollingManager *self, gdouble scale)
void fl_scrolling_manager_handle_rotation_update(FlScrollingManager *self, gdouble rotation)
FlScrollingManager * fl_scrolling_manager_new(FlEngine *engine, FlutterViewId view_id)
void fl_scrolling_manager_handle_zoom_begin(FlScrollingManager *self)
void fl_scrolling_manager_handle_zoom_end(FlScrollingManager *self)
TEST(FlScrollingManagerTest, DiscreteDirectional)
double y
#define MOCK_ENGINE_PROC(proc, mock_impl)
FlutterEngineSendPointerEventFnPtr SendPointerEvent
Definition embedder.h:3716