5#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
10#include "gtest/gtest.h"
17 double scroll_delta_x,
18 double scroll_delta_y,
20 MousePointerCallHandler;
29 PointerPanZoomCallHandler;
37 double scroll_delta_x;
38 double scroll_delta_y;
40} MousePointerEventRecord;
51} PointerPanZoomEventRecord;
56 fl_mock_scrolling_view_delegate,
58 MOCK_SCROLLING_VIEW_DELEGATE,
65struct _FlMockScrollingViewDelegate {
66 GObject parent_instance;
69struct FlMockScrollingViewDelegatePrivate {
70 MousePointerCallHandler mouse_handler;
71 PointerPanZoomCallHandler pan_zoom_handler;
74static void fl_mock_view_scroll_delegate_iface_init(
75 FlScrollingViewDelegateInterface* iface);
78 FlMockScrollingViewDelegate,
79 fl_mock_scrolling_view_delegate,
81 G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(),
82 fl_mock_view_scroll_delegate_iface_init);
83 G_ADD_PRIVATE(FlMockScrollingViewDelegate))
86 static_cast<FlMockScrollingViewDelegatePrivate*>( \
87 fl_mock_scrolling_view_delegate_get_instance_private( \
88 FL_MOCK_SCROLLING_VIEW_DELEGATE(obj)))
90static void fl_mock_scrolling_view_delegate_init(
91 FlMockScrollingViewDelegate*
self) {
92 FlMockScrollingViewDelegatePrivate*
priv =
95 new (
priv) FlMockScrollingViewDelegatePrivate();
98static void fl_mock_scrolling_view_delegate_finalize(GObject*
object) {
100 ->~FlMockScrollingViewDelegatePrivate();
103static void fl_mock_scrolling_view_delegate_dispose(GObject*
object) {
104 G_OBJECT_CLASS(fl_mock_scrolling_view_delegate_parent_class)->dispose(
object);
107static void fl_mock_scrolling_view_delegate_class_init(
108 FlMockScrollingViewDelegateClass* klass) {
109 G_OBJECT_CLASS(klass)->dispose = fl_mock_scrolling_view_delegate_dispose;
110 G_OBJECT_CLASS(klass)->finalize = fl_mock_scrolling_view_delegate_finalize;
113static void fl_mock_view_send_mouse_pointer_event(
114 FlScrollingViewDelegate* delegate,
120 double scroll_delta_x,
121 double scroll_delta_y,
123 FlMockScrollingViewDelegatePrivate*
priv =
125 priv->mouse_handler(phase, timestamp,
x,
y, device_kind, scroll_delta_x,
126 scroll_delta_y, buttons);
129static void fl_mock_view_send_pointer_pan_zoom_event(
130 FlScrollingViewDelegate* delegate,
139 FlMockScrollingViewDelegatePrivate*
priv =
141 priv->pan_zoom_handler(timestamp,
x,
y, phase, pan_x, pan_y,
scale, rotation);
144static void fl_mock_view_scroll_delegate_iface_init(
145 FlScrollingViewDelegateInterface* iface) {
146 iface->send_mouse_pointer_event = fl_mock_view_send_mouse_pointer_event;
147 iface->send_pointer_pan_zoom_event = fl_mock_view_send_pointer_pan_zoom_event;
150static FlMockScrollingViewDelegate* fl_mock_scrolling_view_delegate_new() {
151 FlMockScrollingViewDelegate*
self = FL_MOCK_SCROLLING_VIEW_DELEGATE(
152 g_object_new(fl_mock_scrolling_view_delegate_get_type(),
nullptr));
155 FL_IS_MOCK_SCROLLING_VIEW_DELEGATE(
self);
160static void fl_mock_scrolling_view_set_mouse_handler(
161 FlMockScrollingViewDelegate*
self,
162 MousePointerCallHandler handler) {
163 FlMockScrollingViewDelegatePrivate*
priv =
166 priv->mouse_handler = std::move(handler);
169static void fl_mock_scrolling_view_set_pan_zoom_handler(
170 FlMockScrollingViewDelegate*
self,
171 PointerPanZoomCallHandler handler) {
172 FlMockScrollingViewDelegatePrivate*
priv =
175 priv->pan_zoom_handler = std::move(handler);
180class ScrollingTester {
183 view_ = fl_mock_scrolling_view_delegate_new();
185 fl_mock_scrolling_view_set_mouse_handler(
189 double scroll_delta_y, int64_t buttons) {
192 fl_mock_scrolling_view_set_pan_zoom_handler(
195 double pan_x,
double pan_y,
double scale,
double rotation) {
201 g_clear_object(&view_);
202 g_clear_object(&manager_);
205 FlScrollingManager*
manager() {
return manager_; }
207 void recordMousePointerCallsTo(
208 std::vector<MousePointerEventRecord>& storage) {
209 fl_mock_scrolling_view_set_mouse_handler(
212 double scroll_delta_x,
double scroll_delta_y,
214 storage.push_back(MousePointerEventRecord{
216 .timestamp = timestamp,
219 .device_kind = device_kind,
220 .scroll_delta_x = scroll_delta_x,
221 .scroll_delta_y = scroll_delta_y,
227 void recordPointerPanZoomCallsTo(
228 std::vector<PointerPanZoomEventRecord>& storage) {
229 fl_mock_scrolling_view_set_pan_zoom_handler(
230 view_, [&storage](
size_t timestamp,
double x,
double y,
232 double scale,
double rotation) {
233 storage.push_back(PointerPanZoomEventRecord{
234 .timestamp = timestamp,
241 .rotation = rotation,
247 FlMockScrollingViewDelegate* view_;
248 FlScrollingManager* manager_;
252struct _FakeGdkDevice {
253 GObject parent_instance;
257GdkDevice* makeFakeDevice(GdkInputSource
source) {
259 static_cast<_FakeGdkDevice*
>(g_malloc0(
sizeof(_FakeGdkDevice)));
262 (
reinterpret_cast<GTypeInstance*
>(
device))->g_class =
263 static_cast<GTypeClass*
>(g_malloc0(
sizeof(GTypeClass)));
264 (
reinterpret_cast<GTypeInstance*
>(
device))->g_class->g_type = GDK_TYPE_DEVICE;
265 return reinterpret_cast<GdkDevice*
>(
device);
268TEST(FlScrollingManagerTest, DiscreteDirectionional) {
270 std::vector<MousePointerEventRecord> mouse_records;
271 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
272 tester.recordMousePointerCallsTo(mouse_records);
273 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
274 GdkDevice* mouse = makeFakeDevice(GDK_SOURCE_MOUSE);
275 GdkEventScroll*
event =
276 reinterpret_cast<GdkEventScroll*
>(gdk_event_new(GDK_SCROLL));
280 event->device = mouse;
281 event->direction = GDK_SCROLL_UP;
283 EXPECT_EQ(pan_zoom_records.size(), 0u);
284 EXPECT_EQ(mouse_records.size(), 1u);
285 EXPECT_EQ(mouse_records[0].
x, 4.0);
286 EXPECT_EQ(mouse_records[0].
y, 8.0);
288 EXPECT_EQ(mouse_records[0].timestamp,
290 EXPECT_EQ(mouse_records[0].scroll_delta_x, 0);
291 EXPECT_EQ(mouse_records[0].scroll_delta_y, 53 * -1.0);
292 event->direction = GDK_SCROLL_DOWN;
294 EXPECT_EQ(pan_zoom_records.size(), 0u);
295 EXPECT_EQ(mouse_records.size(), 2u);
296 EXPECT_EQ(mouse_records[1].
x, 4.0);
297 EXPECT_EQ(mouse_records[1].
y, 8.0);
299 EXPECT_EQ(mouse_records[1].timestamp,
301 EXPECT_EQ(mouse_records[1].scroll_delta_x, 0);
302 EXPECT_EQ(mouse_records[1].scroll_delta_y, 53 * 1.0);
303 event->direction = GDK_SCROLL_LEFT;
305 EXPECT_EQ(pan_zoom_records.size(), 0u);
306 EXPECT_EQ(mouse_records.size(), 3u);
307 EXPECT_EQ(mouse_records[2].
x, 4.0);
308 EXPECT_EQ(mouse_records[2].
y, 8.0);
310 EXPECT_EQ(mouse_records[2].timestamp,
312 EXPECT_EQ(mouse_records[2].scroll_delta_x, 53 * -1.0);
313 EXPECT_EQ(mouse_records[2].scroll_delta_y, 0);
314 event->direction = GDK_SCROLL_RIGHT;
316 EXPECT_EQ(pan_zoom_records.size(), 0u);
317 EXPECT_EQ(mouse_records.size(), 4u);
318 EXPECT_EQ(mouse_records[3].
x, 4.0);
319 EXPECT_EQ(mouse_records[3].
y, 8.0);
321 EXPECT_EQ(mouse_records[3].timestamp,
323 EXPECT_EQ(mouse_records[3].scroll_delta_x, 53 * 1.0);
324 EXPECT_EQ(mouse_records[3].scroll_delta_y, 0);
327TEST(FlScrollingManagerTest, DiscreteScrolling) {
329 std::vector<MousePointerEventRecord> mouse_records;
330 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
331 tester.recordMousePointerCallsTo(mouse_records);
332 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
333 GdkDevice* mouse = makeFakeDevice(GDK_SOURCE_MOUSE);
334 GdkEventScroll*
event =
335 reinterpret_cast<GdkEventScroll*
>(gdk_event_new(GDK_SCROLL));
339 event->delta_x = 1.0;
340 event->delta_y = 2.0;
341 event->device = mouse;
342 event->direction = GDK_SCROLL_SMOOTH;
344 EXPECT_EQ(pan_zoom_records.size(), 0u);
345 EXPECT_EQ(mouse_records.size(), 1u);
346 EXPECT_EQ(mouse_records[0].
x, 4.0);
347 EXPECT_EQ(mouse_records[0].
y, 8.0);
349 EXPECT_EQ(mouse_records[0].timestamp,
351 EXPECT_EQ(mouse_records[0].scroll_delta_x, 53 * 1.0);
352 EXPECT_EQ(mouse_records[0].scroll_delta_y, 53 * 2.0);
355TEST(FlScrollingManagerTest, Panning) {
357 std::vector<MousePointerEventRecord> mouse_records;
358 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
359 tester.recordMousePointerCallsTo(mouse_records);
360 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
361 GdkDevice* touchpad = makeFakeDevice(GDK_SOURCE_TOUCHPAD);
362 GdkEventScroll*
event =
363 reinterpret_cast<GdkEventScroll*
>(gdk_event_new(GDK_SCROLL));
367 event->delta_x = 1.0;
368 event->delta_y = 2.0;
369 event->device = touchpad;
370 event->direction = GDK_SCROLL_SMOOTH;
372 EXPECT_EQ(pan_zoom_records.size(), 2u);
373 EXPECT_EQ(mouse_records.size(), 0u);
374 EXPECT_EQ(pan_zoom_records[0].
x, 4.0);
375 EXPECT_EQ(pan_zoom_records[0].
y, 8.0);
376 EXPECT_EQ(pan_zoom_records[0].timestamp,
379 EXPECT_EQ(pan_zoom_records[1].
x, 4.0);
380 EXPECT_EQ(pan_zoom_records[1].
y, 8.0);
381 EXPECT_EQ(pan_zoom_records[1].timestamp,
384 EXPECT_EQ(pan_zoom_records[1].pan_x, 53 * -1.0);
385 EXPECT_EQ(pan_zoom_records[1].pan_y, 53 * -2.0);
386 EXPECT_EQ(pan_zoom_records[1].
scale, 1.0);
387 EXPECT_EQ(pan_zoom_records[1].rotation, 0.0);
389 EXPECT_EQ(pan_zoom_records.size(), 3u);
390 EXPECT_EQ(mouse_records.size(), 0u);
391 EXPECT_EQ(pan_zoom_records[2].
x, 4.0);
392 EXPECT_EQ(pan_zoom_records[2].
y, 8.0);
393 EXPECT_EQ(pan_zoom_records[2].timestamp,
396 EXPECT_EQ(pan_zoom_records[2].pan_x, 53 * -2.0);
397 EXPECT_EQ(pan_zoom_records[2].pan_y, 53 * -4.0);
398 EXPECT_EQ(pan_zoom_records[2].
scale, 1.0);
399 EXPECT_EQ(pan_zoom_records[2].rotation, 0.0);
400 event->is_stop =
true;
402 EXPECT_EQ(pan_zoom_records.size(), 4u);
403 EXPECT_EQ(mouse_records.size(), 0u);
404 EXPECT_EQ(pan_zoom_records[3].
x, 4.0);
405 EXPECT_EQ(pan_zoom_records[3].
y, 8.0);
406 EXPECT_EQ(pan_zoom_records[3].timestamp,
411TEST(FlScrollingManagerTest, Zooming) {
413 std::vector<MousePointerEventRecord> mouse_records;
414 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
415 tester.recordMousePointerCallsTo(mouse_records);
416 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
417 size_t time_start = g_get_real_time();
419 EXPECT_EQ(pan_zoom_records.size(), 1u);
420 EXPECT_EQ(mouse_records.size(), 0u);
421 EXPECT_EQ(pan_zoom_records[0].
x, 0);
422 EXPECT_EQ(pan_zoom_records[0].
y, 0);
424 EXPECT_GE(pan_zoom_records[0].timestamp, time_start);
426 EXPECT_EQ(pan_zoom_records.size(), 2u);
427 EXPECT_EQ(mouse_records.size(), 0u);
428 EXPECT_EQ(pan_zoom_records[1].
x, 0);
429 EXPECT_EQ(pan_zoom_records[1].
y, 0);
431 EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp);
432 EXPECT_EQ(pan_zoom_records[1].pan_x, 0);
433 EXPECT_EQ(pan_zoom_records[1].pan_y, 0);
434 EXPECT_EQ(pan_zoom_records[1].
scale, 1.1);
435 EXPECT_EQ(pan_zoom_records[1].rotation, 0);
437 EXPECT_EQ(pan_zoom_records.size(), 3u);
438 EXPECT_EQ(mouse_records.size(), 0u);
439 EXPECT_EQ(pan_zoom_records[2].
x, 0);
440 EXPECT_EQ(pan_zoom_records[2].
y, 0);
442 EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp);
445TEST(FlScrollingManagerTest, Rotating) {
447 std::vector<MousePointerEventRecord> mouse_records;
448 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
449 tester.recordMousePointerCallsTo(mouse_records);
450 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
451 size_t time_start = g_get_real_time();
453 EXPECT_EQ(pan_zoom_records.size(), 1u);
454 EXPECT_EQ(mouse_records.size(), 0u);
455 EXPECT_EQ(pan_zoom_records[0].
x, 0);
456 EXPECT_EQ(pan_zoom_records[0].
y, 0);
458 EXPECT_GE(pan_zoom_records[0].timestamp, time_start);
460 EXPECT_EQ(pan_zoom_records.size(), 2u);
461 EXPECT_EQ(mouse_records.size(), 0u);
462 EXPECT_EQ(pan_zoom_records[1].
x, 0);
463 EXPECT_EQ(pan_zoom_records[1].
y, 0);
465 EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp);
466 EXPECT_EQ(pan_zoom_records[1].pan_x, 0);
467 EXPECT_EQ(pan_zoom_records[1].pan_y, 0);
468 EXPECT_EQ(pan_zoom_records[1].
scale, 1.0);
469 EXPECT_EQ(pan_zoom_records[1].rotation, 0.5);
471 EXPECT_EQ(pan_zoom_records.size(), 3u);
472 EXPECT_EQ(mouse_records.size(), 0u);
473 EXPECT_EQ(pan_zoom_records[2].
x, 0);
474 EXPECT_EQ(pan_zoom_records[2].
y, 0);
476 EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp);
479TEST(FlScrollingManagerTest, SynchronizedZoomingAndRotating) {
481 std::vector<MousePointerEventRecord> mouse_records;
482 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
483 tester.recordMousePointerCallsTo(mouse_records);
484 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
485 size_t time_start = g_get_real_time();
487 EXPECT_EQ(pan_zoom_records.size(), 1u);
488 EXPECT_EQ(mouse_records.size(), 0u);
489 EXPECT_EQ(pan_zoom_records[0].
x, 0);
490 EXPECT_EQ(pan_zoom_records[0].
y, 0);
492 EXPECT_GE(pan_zoom_records[0].timestamp, time_start);
494 EXPECT_EQ(pan_zoom_records.size(), 2u);
495 EXPECT_EQ(mouse_records.size(), 0u);
496 EXPECT_EQ(pan_zoom_records[1].
x, 0);
497 EXPECT_EQ(pan_zoom_records[1].
y, 0);
499 EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp);
500 EXPECT_EQ(pan_zoom_records[1].pan_x, 0);
501 EXPECT_EQ(pan_zoom_records[1].pan_y, 0);
502 EXPECT_EQ(pan_zoom_records[1].
scale, 1.1);
503 EXPECT_EQ(pan_zoom_records[1].rotation, 0);
505 EXPECT_EQ(pan_zoom_records.size(), 2u);
506 EXPECT_EQ(mouse_records.size(), 0u);
508 EXPECT_EQ(pan_zoom_records.size(), 3u);
509 EXPECT_EQ(pan_zoom_records[2].
x, 0);
510 EXPECT_EQ(pan_zoom_records[2].
y, 0);
512 EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp);
513 EXPECT_EQ(pan_zoom_records[2].pan_x, 0);
514 EXPECT_EQ(pan_zoom_records[2].pan_y, 0);
515 EXPECT_EQ(pan_zoom_records[2].
scale, 1.1);
516 EXPECT_EQ(pan_zoom_records[2].rotation, 0.5);
519 EXPECT_EQ(pan_zoom_records.size(), 3u);
521 EXPECT_EQ(pan_zoom_records.size(), 4u);
522 EXPECT_EQ(mouse_records.size(), 0u);
523 EXPECT_EQ(pan_zoom_records[3].
x, 0);
524 EXPECT_EQ(pan_zoom_records[3].
y, 0);
526 EXPECT_GE(pan_zoom_records[3].timestamp, pan_zoom_records[2].timestamp);
531TEST(FlScrollingManagerTest, UnsynchronizedZoomingAndRotating) {
533 std::vector<MousePointerEventRecord> mouse_records;
534 std::vector<PointerPanZoomEventRecord> pan_zoom_records;
535 tester.recordMousePointerCallsTo(mouse_records);
536 tester.recordPointerPanZoomCallsTo(pan_zoom_records);
537 size_t time_start = g_get_real_time();
539 EXPECT_EQ(pan_zoom_records.size(), 1u);
540 EXPECT_EQ(mouse_records.size(), 0u);
541 EXPECT_EQ(pan_zoom_records[0].
x, 0);
542 EXPECT_EQ(pan_zoom_records[0].
y, 0);
544 EXPECT_GE(pan_zoom_records[0].timestamp, time_start);
546 EXPECT_EQ(pan_zoom_records.size(), 2u);
547 EXPECT_EQ(mouse_records.size(), 0u);
548 EXPECT_EQ(pan_zoom_records[1].
x, 0);
549 EXPECT_EQ(pan_zoom_records[1].
y, 0);
551 EXPECT_GE(pan_zoom_records[1].timestamp, pan_zoom_records[0].timestamp);
552 EXPECT_EQ(pan_zoom_records[1].pan_x, 0);
553 EXPECT_EQ(pan_zoom_records[1].pan_y, 0);
554 EXPECT_EQ(pan_zoom_records[1].
scale, 1.1);
555 EXPECT_EQ(pan_zoom_records[1].rotation, 0);
557 EXPECT_EQ(pan_zoom_records.size(), 2u);
558 EXPECT_EQ(mouse_records.size(), 0u);
560 EXPECT_EQ(pan_zoom_records.size(), 3u);
561 EXPECT_EQ(pan_zoom_records[2].
x, 0);
562 EXPECT_EQ(pan_zoom_records[2].
y, 0);
564 EXPECT_GE(pan_zoom_records[2].timestamp, pan_zoom_records[1].timestamp);
565 EXPECT_EQ(pan_zoom_records[2].pan_x, 0);
566 EXPECT_EQ(pan_zoom_records[2].pan_y, 0);
567 EXPECT_EQ(pan_zoom_records[2].
scale, 1.1);
568 EXPECT_EQ(pan_zoom_records[2].rotation, 0.5);
570 EXPECT_EQ(pan_zoom_records.size(), 3u);
572 EXPECT_EQ(pan_zoom_records.size(), 4u);
573 EXPECT_EQ(mouse_records.size(), 0u);
574 EXPECT_EQ(pan_zoom_records[3].
x, 0);
575 EXPECT_EQ(pan_zoom_records[3].
y, 0);
577 EXPECT_GE(pan_zoom_records[3].timestamp, pan_zoom_records[2].timestamp);
578 EXPECT_EQ(pan_zoom_records[3].pan_x, 0);
579 EXPECT_EQ(pan_zoom_records[3].pan_y, 0);
580 EXPECT_EQ(pan_zoom_records[3].
scale, 1.1);
581 EXPECT_EQ(pan_zoom_records[3].rotation, 1.0);
583 EXPECT_EQ(pan_zoom_records.size(), 5u);
584 EXPECT_EQ(mouse_records.size(), 0u);
585 EXPECT_EQ(pan_zoom_records[4].
x, 0);
586 EXPECT_EQ(pan_zoom_records[4].
y, 0);
588 EXPECT_GE(pan_zoom_records[4].timestamp, pan_zoom_records[3].timestamp);
#define TEST(S, s, D, expected)
FlutterPointerPhase
The phase of the pointer event.
@ kPanZoomUpdate
The pan/zoom updated.
@ kPanZoomStart
A pan/zoom started on this pointer.
@ kPanZoomEnd
The pan/zoom ended.
FlutterPointerDeviceKind
The device type that created a pointer event.
@ kFlutterPointerDeviceKindMouse
G_DEFINE_TYPE_WITH_CODE(FlAccessibleNode, fl_accessible_node, ATK_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, fl_accessible_node_component_interface_init) G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, fl_accessible_node_action_interface_init)) static gboolean flag_is_changed(FlutterSemanticsFlag old_flags
G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(FlAccessibleTextField, fl_accessible_text_field, FL, ACCESSIBLE_TEXT_FIELD, FlAccessibleNode)
FlPixelBufferTexturePrivate * priv
Dart_NativeFunction function
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
DEF_SWITCHES_START aot vmservice shared library name