Remove FlScrollingViewDelegate (flutter/engine#56270)

We can just contact the engine directly and test that by overriding the
engine API.
This commit is contained in:
Robert Ancell 2024-11-06 10:16:49 +13:00 committed by GitHub
parent 8582bd3b7a
commit a98f1eb4e2
8 changed files with 367 additions and 712 deletions

View File

@ -45029,8 +45029,6 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_test.cc + ../../../flu
ORIGIN: ../../../flutter/shell/platform/linux/fl_scrolling_manager.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_scrolling_manager.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_scrolling_manager_test.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_scrolling_view_delegate.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_scrolling_view_delegate.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_settings.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_settings.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_settings_handler.cc + ../../../flutter/LICENSE
@ -47922,8 +47920,6 @@ FILE: ../../../flutter/shell/platform/linux/fl_renderer_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_scrolling_manager.cc
FILE: ../../../flutter/shell/platform/linux/fl_scrolling_manager.h
FILE: ../../../flutter/shell/platform/linux/fl_scrolling_manager_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_scrolling_view_delegate.cc
FILE: ../../../flutter/shell/platform/linux/fl_scrolling_view_delegate.h
FILE: ../../../flutter/shell/platform/linux/fl_settings.cc
FILE: ../../../flutter/shell/platform/linux/fl_settings.h
FILE: ../../../flutter/shell/platform/linux/fl_settings_handler.cc

View File

@ -135,7 +135,6 @@ source_set("flutter_linux_sources") {
"fl_renderer_gdk.cc",
"fl_renderer_headless.cc",
"fl_scrolling_manager.cc",
"fl_scrolling_view_delegate.cc",
"fl_settings.cc",
"fl_settings_handler.cc",
"fl_settings_portal.cc",

View File

@ -3,13 +3,17 @@
// found in the LICENSE file.
#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
static constexpr int kMicrosecondsPerMillisecond = 1000;
struct _FlScrollingManager {
GObject parent_instance;
GWeakRef view_delegate;
GWeakRef engine;
FlutterViewId view_id;
gdouble last_x;
gdouble last_y;
@ -29,7 +33,7 @@ G_DEFINE_TYPE(FlScrollingManager, fl_scrolling_manager, G_TYPE_OBJECT);
static void fl_scrolling_manager_dispose(GObject* object) {
FlScrollingManager* self = FL_SCROLLING_MANAGER(object);
g_weak_ref_clear(&self->view_delegate);
g_weak_ref_clear(&self->engine);
G_OBJECT_CLASS(fl_scrolling_manager_parent_class)->dispose(object);
}
@ -40,14 +44,15 @@ static void fl_scrolling_manager_class_init(FlScrollingManagerClass* klass) {
static void fl_scrolling_manager_init(FlScrollingManager* self) {}
FlScrollingManager* fl_scrolling_manager_new(
FlScrollingViewDelegate* view_delegate) {
g_return_val_if_fail(FL_IS_SCROLLING_VIEW_DELEGATE(view_delegate), nullptr);
FlScrollingManager* fl_scrolling_manager_new(FlEngine* engine,
FlutterViewId view_id) {
g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr);
FlScrollingManager* self = FL_SCROLLING_MANAGER(
g_object_new(fl_scrolling_manager_get_type(), nullptr));
g_weak_ref_init(&self->view_delegate, view_delegate);
g_weak_ref_init(&self->engine, engine);
self->view_id = view_id;
self->pan_started = FALSE;
self->zoom_started = FALSE;
self->rotate_started = FALSE;
@ -68,9 +73,8 @@ void fl_scrolling_manager_handle_scroll_event(FlScrollingManager* self,
gint scale_factor) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
@ -110,8 +114,8 @@ void fl_scrolling_manager_handle_scroll_event(FlScrollingManager* self,
scroll_delta_x *= -1;
scroll_delta_y *= -1;
if (gdk_event_is_scroll_stop_event(event)) {
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, event_time * kMicrosecondsPerMillisecond,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, event_time * kMicrosecondsPerMillisecond,
event_x * scale_factor, event_y * scale_factor, kPanZoomEnd,
self->pan_x, self->pan_y, 0, 0);
self->pan_started = FALSE;
@ -119,24 +123,24 @@ void fl_scrolling_manager_handle_scroll_event(FlScrollingManager* self,
if (!self->pan_started) {
self->pan_x = 0;
self->pan_y = 0;
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, event_time * kMicrosecondsPerMillisecond,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, event_time * kMicrosecondsPerMillisecond,
event_x * scale_factor, event_y * scale_factor, kPanZoomStart, 0, 0,
0, 0);
self->pan_started = TRUE;
}
self->pan_x += scroll_delta_x;
self->pan_y += scroll_delta_y;
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, event_time * kMicrosecondsPerMillisecond,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, event_time * kMicrosecondsPerMillisecond,
event_x * scale_factor, event_y * scale_factor, kPanZoomUpdate,
self->pan_x, self->pan_y, 1, 0);
}
} else {
self->last_x = event_x * scale_factor;
self->last_y = event_y * scale_factor;
fl_scrolling_view_delegate_send_mouse_pointer_event(
view_delegate,
fl_engine_send_mouse_pointer_event(
engine, self->view_id,
FlutterPointerPhase::kMove /* arbitrary value, phase will be ignored as
this is a discrete scroll event */
,
@ -149,9 +153,8 @@ void fl_scrolling_manager_handle_scroll_event(FlScrollingManager* self,
void fl_scrolling_manager_handle_rotation_begin(FlScrollingManager* self) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
@ -159,8 +162,8 @@ void fl_scrolling_manager_handle_rotation_begin(FlScrollingManager* self) {
if (!self->zoom_started) {
self->scale = 1;
self->rotation = 0;
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, g_get_real_time(), self->last_x, self->last_y,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, g_get_real_time(), self->last_x, self->last_y,
kPanZoomStart, 0, 0, 0, 0);
}
}
@ -169,31 +172,29 @@ void fl_scrolling_manager_handle_rotation_update(FlScrollingManager* self,
gdouble rotation) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
self->rotation = rotation;
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, g_get_real_time(), self->last_x, self->last_y,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, g_get_real_time(), self->last_x, self->last_y,
kPanZoomUpdate, 0, 0, self->scale, self->rotation);
}
void fl_scrolling_manager_handle_rotation_end(FlScrollingManager* self) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
self->rotate_started = FALSE;
if (!self->zoom_started) {
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, g_get_real_time(), self->last_x, self->last_y,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, g_get_real_time(), self->last_x, self->last_y,
kPanZoomEnd, 0, 0, 0, 0);
}
}
@ -201,9 +202,8 @@ void fl_scrolling_manager_handle_rotation_end(FlScrollingManager* self) {
void fl_scrolling_manager_handle_zoom_begin(FlScrollingManager* self) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
@ -211,8 +211,8 @@ void fl_scrolling_manager_handle_zoom_begin(FlScrollingManager* self) {
if (!self->rotate_started) {
self->scale = 1;
self->rotation = 0;
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, g_get_real_time(), self->last_x, self->last_y,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, g_get_real_time(), self->last_x, self->last_y,
kPanZoomStart, 0, 0, 0, 0);
}
}
@ -221,31 +221,29 @@ void fl_scrolling_manager_handle_zoom_update(FlScrollingManager* self,
gdouble scale) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
self->scale = scale;
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, g_get_real_time(), self->last_x, self->last_y,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, g_get_real_time(), self->last_x, self->last_y,
kPanZoomUpdate, 0, 0, self->scale, self->rotation);
}
void fl_scrolling_manager_handle_zoom_end(FlScrollingManager* self) {
g_return_if_fail(FL_IS_SCROLLING_MANAGER(self));
g_autoptr(FlScrollingViewDelegate) view_delegate =
FL_SCROLLING_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine == nullptr) {
return;
}
self->zoom_started = FALSE;
if (!self->rotate_started) {
fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
view_delegate, g_get_real_time(), self->last_x, self->last_y,
fl_engine_send_pointer_pan_zoom_event(
engine, self->view_id, g_get_real_time(), self->last_x, self->last_y,
kPanZoomEnd, 0, 0, 0, 0);
}
}

View File

@ -7,7 +7,8 @@
#include <gdk/gdk.h>
#include "flutter/shell/platform/linux/fl_scrolling_view_delegate.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
G_BEGIN_DECLS
@ -19,15 +20,15 @@ G_DECLARE_FINAL_TYPE(FlScrollingManager,
/**
* fl_scrolling_manager_new:
* @view_delegate: An interface that the manager requires to communicate with
* the platform. Usually implemented by FlView.
* @engine: an #FlEngine.
* @view_id: the view being managed.
*
* Create a new #FlScrollingManager.
*
* Returns: a new #FlScrollingManager.
*/
FlScrollingManager* fl_scrolling_manager_new(
FlScrollingViewDelegate* view_delegate);
FlScrollingManager* fl_scrolling_manager_new(FlEngine* engine,
FlutterViewId view_id);
/**
* fl_scrolling_manager_set_last_mouse_position:

View File

@ -3,247 +3,14 @@
// found in the LICENSE file.
#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
#include "flutter/shell/platform/linux/testing/fl_test.h"
#include <cstring>
#include <vector>
#include "gtest/gtest.h"
namespace {
typedef std::function<void(FlutterPointerPhase phase,
size_t timestamp,
double x,
double y,
FlutterPointerDeviceKind device_kind,
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;
FlutterPointerDeviceKind device_kind;
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;
};
struct FlMockScrollingViewDelegatePrivate {
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);
G_ADD_PRIVATE(FlMockScrollingViewDelegate))
#define FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(obj) \
static_cast<FlMockScrollingViewDelegatePrivate*>( \
fl_mock_scrolling_view_delegate_get_instance_private( \
FL_MOCK_SCROLLING_VIEW_DELEGATE(obj)))
static void fl_mock_scrolling_view_delegate_init(
FlMockScrollingViewDelegate* self) {
FlMockScrollingViewDelegatePrivate* priv =
FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(self);
new (priv) FlMockScrollingViewDelegatePrivate();
}
static void fl_mock_scrolling_view_delegate_dispose(GObject* object) {
FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(object)
->~FlMockScrollingViewDelegatePrivate();
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,
FlutterPointerDeviceKind device_kind,
double scroll_delta_x,
double scroll_delta_y,
int64_t buttons) {
FlMockScrollingViewDelegatePrivate* priv =
FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(delegate);
priv->mouse_handler(phase, timestamp, x, y, device_kind, 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) {
FlMockScrollingViewDelegatePrivate* priv =
FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(delegate);
priv->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) {
FlMockScrollingViewDelegatePrivate* priv =
FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(self);
priv->mouse_handler = std::move(handler);
}
static void fl_mock_scrolling_view_set_pan_zoom_handler(
FlMockScrollingViewDelegate* self,
PointerPanZoomCallHandler handler) {
FlMockScrollingViewDelegatePrivate* priv =
FL_MOCK_SCROLLING_VIEW_DELEGATE_GET_PRIVATE(self);
priv->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,
FlutterPointerDeviceKind device_kind, 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, FlutterPointerDeviceKind device_kind,
double scroll_delta_x, double scroll_delta_y,
int64_t buttons) {
storage.push_back(MousePointerEventRecord{
.phase = phase,
.timestamp = timestamp,
.x = x,
.y = y,
.device_kind = device_kind,
.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 {
@ -262,12 +29,23 @@ GdkDevice* makeFakeDevice(GdkInputSource source) {
return reinterpret_cast<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);
TEST(FlScrollingManagerTest, DiscreteDirectional) {
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
GdkDevice* mouse = makeFakeDevice(GDK_SOURCE_MOUSE);
GdkEventScroll* event =
reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
@ -276,57 +54,64 @@ TEST(FlScrollingManagerTest, DiscreteDirectionional) {
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].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(mouse_records[0].timestamp,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 1u);
EXPECT_EQ(pointer_events[0].x, 4.0);
EXPECT_EQ(pointer_events[0].y, 8.0);
EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(pointer_events[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);
EXPECT_EQ(pointer_events[0].scroll_delta_x, 0);
EXPECT_EQ(pointer_events[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].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(mouse_records[1].timestamp,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 2u);
EXPECT_EQ(pointer_events[1].x, 4.0);
EXPECT_EQ(pointer_events[1].y, 8.0);
EXPECT_EQ(pointer_events[1].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(pointer_events[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);
EXPECT_EQ(pointer_events[1].scroll_delta_x, 0);
EXPECT_EQ(pointer_events[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].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(mouse_records[2].timestamp,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 3u);
EXPECT_EQ(pointer_events[2].x, 4.0);
EXPECT_EQ(pointer_events[2].y, 8.0);
EXPECT_EQ(pointer_events[2].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(pointer_events[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);
EXPECT_EQ(pointer_events[2].scroll_delta_x, 53 * -1.0);
EXPECT_EQ(pointer_events[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].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(mouse_records[3].timestamp,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 4u);
EXPECT_EQ(pointer_events[3].x, 4.0);
EXPECT_EQ(pointer_events[3].y, 8.0);
EXPECT_EQ(pointer_events[3].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(pointer_events[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);
EXPECT_EQ(pointer_events[3].scroll_delta_x, 53 * 1.0);
EXPECT_EQ(pointer_events[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);
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
GdkDevice* mouse = makeFakeDevice(GDK_SOURCE_MOUSE);
GdkEventScroll* event =
reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
@ -337,24 +122,34 @@ TEST(FlScrollingManagerTest, DiscreteScrolling) {
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].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(mouse_records[0].timestamp,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 1u);
EXPECT_EQ(pointer_events[0].x, 4.0);
EXPECT_EQ(pointer_events[0].y, 8.0);
EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindMouse);
EXPECT_EQ(pointer_events[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);
EXPECT_EQ(pointer_events[0].scroll_delta_x, 53 * 1.0);
EXPECT_EQ(pointer_events[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);
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
GdkDevice* touchpad = makeFakeDevice(GDK_SOURCE_TOUCHPAD);
GdkEventScroll* event =
reinterpret_cast<GdkEventScroll*>(gdk_event_new(GDK_SCROLL));
@ -365,224 +160,248 @@ TEST(FlScrollingManagerTest, Panning) {
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,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 2u);
EXPECT_EQ(pointer_events[0].x, 4.0);
EXPECT_EQ(pointer_events[0].y, 8.0);
EXPECT_EQ(pointer_events[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,
EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
EXPECT_EQ(pointer_events[1].x, 4.0);
EXPECT_EQ(pointer_events[1].y, 8.0);
EXPECT_EQ(pointer_events[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,
EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
EXPECT_EQ(pointer_events[1].pan_x, 53 * -1.0); // directions get swapped
EXPECT_EQ(pointer_events[1].pan_y, 53 * -2.0);
EXPECT_EQ(pointer_events[1].scale, 1.0);
EXPECT_EQ(pointer_events[1].rotation, 0.0);
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 3u);
EXPECT_EQ(pointer_events[2].x, 4.0);
EXPECT_EQ(pointer_events[2].y, 8.0);
EXPECT_EQ(pointer_events[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);
EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
EXPECT_EQ(pointer_events[2].pan_x, 53 * -2.0); // directions get swapped
EXPECT_EQ(pointer_events[2].pan_y, 53 * -4.0);
EXPECT_EQ(pointer_events[2].scale, 1.0);
EXPECT_EQ(pointer_events[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,
fl_scrolling_manager_handle_scroll_event(manager, event, 1.0);
EXPECT_EQ(pointer_events.size(), 4u);
EXPECT_EQ(pointer_events[3].x, 4.0);
EXPECT_EQ(pointer_events[3].y, 8.0);
EXPECT_EQ(pointer_events[3].timestamp,
1000lu); // Milliseconds -> Microseconds
EXPECT_EQ(pan_zoom_records[3].phase, kPanZoomEnd);
EXPECT_EQ(pointer_events[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);
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
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);
fl_scrolling_manager_handle_zoom_begin(manager);
EXPECT_EQ(pointer_events.size(), 1u);
EXPECT_EQ(pointer_events[0].x, 0);
EXPECT_EQ(pointer_events[0].y, 0);
EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
EXPECT_GE(pointer_events[0].timestamp, time_start);
fl_scrolling_manager_handle_zoom_update(manager, 1.1);
EXPECT_EQ(pointer_events.size(), 2u);
EXPECT_EQ(pointer_events[1].x, 0);
EXPECT_EQ(pointer_events[1].y, 0);
EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
EXPECT_EQ(pointer_events[1].pan_x, 0);
EXPECT_EQ(pointer_events[1].pan_y, 0);
EXPECT_EQ(pointer_events[1].scale, 1.1);
EXPECT_EQ(pointer_events[1].rotation, 0);
fl_scrolling_manager_handle_zoom_end(manager);
EXPECT_EQ(pointer_events.size(), 3u);
EXPECT_EQ(pointer_events[2].x, 0);
EXPECT_EQ(pointer_events[2].y, 0);
EXPECT_EQ(pointer_events[2].phase, kPanZoomEnd);
EXPECT_GE(pointer_events[2].timestamp, pointer_events[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);
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
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);
fl_scrolling_manager_handle_rotation_begin(manager);
EXPECT_EQ(pointer_events.size(), 1u);
EXPECT_EQ(pointer_events[0].x, 0);
EXPECT_EQ(pointer_events[0].y, 0);
EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
EXPECT_GE(pointer_events[0].timestamp, time_start);
fl_scrolling_manager_handle_rotation_update(manager, 0.5);
EXPECT_EQ(pointer_events.size(), 2u);
EXPECT_EQ(pointer_events[1].x, 0);
EXPECT_EQ(pointer_events[1].y, 0);
EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
EXPECT_EQ(pointer_events[1].pan_x, 0);
EXPECT_EQ(pointer_events[1].pan_y, 0);
EXPECT_EQ(pointer_events[1].scale, 1.0);
EXPECT_EQ(pointer_events[1].rotation, 0.5);
fl_scrolling_manager_handle_rotation_end(manager);
EXPECT_EQ(pointer_events.size(), 3u);
EXPECT_EQ(pointer_events[2].x, 0);
EXPECT_EQ(pointer_events[2].y, 0);
EXPECT_EQ(pointer_events[2].phase, kPanZoomEnd);
EXPECT_GE(pointer_events[2].timestamp, pointer_events[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);
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
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());
fl_scrolling_manager_handle_zoom_begin(manager);
EXPECT_EQ(pointer_events.size(), 1u);
EXPECT_EQ(pointer_events[0].x, 0);
EXPECT_EQ(pointer_events[0].y, 0);
EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
EXPECT_GE(pointer_events[0].timestamp, time_start);
fl_scrolling_manager_handle_zoom_update(manager, 1.1);
EXPECT_EQ(pointer_events.size(), 2u);
EXPECT_EQ(pointer_events[1].x, 0);
EXPECT_EQ(pointer_events[1].y, 0);
EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
EXPECT_EQ(pointer_events[1].pan_x, 0);
EXPECT_EQ(pointer_events[1].pan_y, 0);
EXPECT_EQ(pointer_events[1].scale, 1.1);
EXPECT_EQ(pointer_events[1].rotation, 0);
fl_scrolling_manager_handle_rotation_begin(manager);
EXPECT_EQ(pointer_events.size(), 2u);
fl_scrolling_manager_handle_rotation_update(manager, 0.5);
EXPECT_EQ(pointer_events.size(), 3u);
EXPECT_EQ(pointer_events[2].x, 0);
EXPECT_EQ(pointer_events[2].y, 0);
EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
EXPECT_EQ(pointer_events[2].pan_x, 0);
EXPECT_EQ(pointer_events[2].pan_y, 0);
EXPECT_EQ(pointer_events[2].scale, 1.1);
EXPECT_EQ(pointer_events[2].rotation, 0.5);
fl_scrolling_manager_handle_zoom_end(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);
EXPECT_EQ(pointer_events.size(), 3u);
fl_scrolling_manager_handle_rotation_end(manager);
EXPECT_EQ(pointer_events.size(), 4u);
EXPECT_EQ(pointer_events[3].x, 0);
EXPECT_EQ(pointer_events[3].y, 0);
EXPECT_EQ(pointer_events[3].phase, kPanZoomEnd);
EXPECT_GE(pointer_events[3].timestamp, pointer_events[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);
}
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
std::vector<FlutterPointerEvent> pointer_events;
embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
SendPointerEvent,
([&pointer_events](auto engine, const FlutterPointerEvent* events,
size_t events_count) {
for (size_t i = 0; i < events_count; i++) {
pointer_events.push_back(events[i]);
}
} // namespace
return kSuccess;
}));
g_autoptr(FlScrollingManager) manager = fl_scrolling_manager_new(engine, 0);
size_t time_start = g_get_real_time();
fl_scrolling_manager_handle_zoom_begin(manager);
EXPECT_EQ(pointer_events.size(), 1u);
EXPECT_EQ(pointer_events[0].x, 0);
EXPECT_EQ(pointer_events[0].y, 0);
EXPECT_EQ(pointer_events[0].phase, kPanZoomStart);
EXPECT_GE(pointer_events[0].timestamp, time_start);
fl_scrolling_manager_handle_zoom_update(manager, 1.1);
EXPECT_EQ(pointer_events.size(), 2u);
EXPECT_EQ(pointer_events[1].x, 0);
EXPECT_EQ(pointer_events[1].y, 0);
EXPECT_EQ(pointer_events[1].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[1].timestamp, pointer_events[0].timestamp);
EXPECT_EQ(pointer_events[1].pan_x, 0);
EXPECT_EQ(pointer_events[1].pan_y, 0);
EXPECT_EQ(pointer_events[1].scale, 1.1);
EXPECT_EQ(pointer_events[1].rotation, 0);
fl_scrolling_manager_handle_rotation_begin(manager);
EXPECT_EQ(pointer_events.size(), 2u);
fl_scrolling_manager_handle_rotation_update(manager, 0.5);
EXPECT_EQ(pointer_events.size(), 3u);
EXPECT_EQ(pointer_events[2].x, 0);
EXPECT_EQ(pointer_events[2].y, 0);
EXPECT_EQ(pointer_events[2].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[2].timestamp, pointer_events[1].timestamp);
EXPECT_EQ(pointer_events[2].pan_x, 0);
EXPECT_EQ(pointer_events[2].pan_y, 0);
EXPECT_EQ(pointer_events[2].scale, 1.1);
EXPECT_EQ(pointer_events[2].rotation, 0.5);
fl_scrolling_manager_handle_zoom_end(manager);
EXPECT_EQ(pointer_events.size(), 3u);
fl_scrolling_manager_handle_rotation_update(manager, 1.0);
EXPECT_EQ(pointer_events.size(), 4u);
EXPECT_EQ(pointer_events[3].x, 0);
EXPECT_EQ(pointer_events[3].y, 0);
EXPECT_EQ(pointer_events[3].phase, kPanZoomUpdate);
EXPECT_GE(pointer_events[3].timestamp, pointer_events[2].timestamp);
EXPECT_EQ(pointer_events[3].pan_x, 0);
EXPECT_EQ(pointer_events[3].pan_y, 0);
EXPECT_EQ(pointer_events[3].scale, 1.1);
EXPECT_EQ(pointer_events[3].rotation, 1.0);
fl_scrolling_manager_handle_rotation_end(manager);
EXPECT_EQ(pointer_events.size(), 5u);
EXPECT_EQ(pointer_events[4].x, 0);
EXPECT_EQ(pointer_events[4].y, 0);
EXPECT_EQ(pointer_events[4].phase, kPanZoomEnd);
EXPECT_GE(pointer_events[4].timestamp, pointer_events[3].timestamp);
}

View File

@ -1,44 +0,0 @@
// 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_view_delegate.h"
G_DEFINE_INTERFACE(FlScrollingViewDelegate,
fl_scrolling_view_delegate,
G_TYPE_OBJECT)
static void fl_scrolling_view_delegate_default_init(
FlScrollingViewDelegateInterface* iface) {}
void fl_scrolling_view_delegate_send_mouse_pointer_event(
FlScrollingViewDelegate* self,
FlutterPointerPhase phase,
size_t timestamp,
double x,
double y,
FlutterPointerDeviceKind device_kind,
double scroll_delta_x,
double scroll_delta_y,
int64_t buttons) {
g_return_if_fail(FL_IS_SCROLLING_VIEW_DELEGATE(self));
FL_SCROLLING_VIEW_DELEGATE_GET_IFACE(self)->send_mouse_pointer_event(
self, phase, timestamp, x, y, device_kind, scroll_delta_x, scroll_delta_y,
buttons);
}
void fl_scrolling_view_delegate_send_pointer_pan_zoom_event(
FlScrollingViewDelegate* self,
size_t timestamp,
double x,
double y,
FlutterPointerPhase phase,
double pan_x,
double pan_y,
double scale,
double rotation) {
g_return_if_fail(FL_IS_SCROLLING_VIEW_DELEGATE(self));
FL_SCROLLING_VIEW_DELEGATE_GET_IFACE(self)->send_pointer_pan_zoom_event(
self, timestamp, x, y, phase, pan_x, pan_y, scale, rotation);
}

View File

@ -1,80 +0,0 @@
// 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.
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_SCROLLING_VIEW_DELEGATE_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_SCROLLING_VIEW_DELEGATE_H_
#include <gdk/gdk.h>
#include <cinttypes>
#include <memory>
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/fl_key_event.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
G_BEGIN_DECLS
G_DECLARE_INTERFACE(FlScrollingViewDelegate,
fl_scrolling_view_delegate,
FL,
SCROLLING_VIEW_DELEGATE,
GObject);
/**
* FlScrollingViewDelegate:
*
* An interface for a class that provides `FlScrollingManager` with
* platform-related features.
*
* This interface is typically implemented by `FlView`.
*/
struct _FlScrollingViewDelegateInterface {
GTypeInterface g_iface;
void (*send_mouse_pointer_event)(FlScrollingViewDelegate* delegate,
FlutterPointerPhase phase,
size_t timestamp,
double x,
double y,
FlutterPointerDeviceKind device_kind,
double scroll_delta_x,
double scroll_delta_y,
int64_t buttons);
void (*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);
};
void fl_scrolling_view_delegate_send_mouse_pointer_event(
FlScrollingViewDelegate* delegate,
FlutterPointerPhase phase,
size_t timestamp,
double x,
double y,
FlutterPointerDeviceKind device_kind,
double scroll_delta_x,
double scroll_delta_y,
int64_t buttons);
void fl_scrolling_view_delegate_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);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_SCROLLING_VIEW_DELEGATE_H_

View File

@ -20,7 +20,6 @@
#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
#include "flutter/shell/platform/linux/fl_renderer_gdk.h"
#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
#include "flutter/shell/platform/linux/fl_scrolling_view_delegate.h"
#include "flutter/shell/platform/linux/fl_socket_accessible.h"
#include "flutter/shell/platform/linux/fl_text_input_handler.h"
#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h"
@ -93,9 +92,6 @@ static void fl_view_plugin_registry_iface_init(
static void fl_view_keyboard_delegate_iface_init(
FlKeyboardViewDelegateInterface* iface);
static void fl_view_scrolling_delegate_iface_init(
FlScrollingViewDelegateInterface* iface);
static void fl_view_text_input_delegate_iface_init(
FlTextInputViewDelegateInterface* iface);
@ -108,10 +104,7 @@ G_DEFINE_TYPE_WITH_CODE(
fl_view_plugin_registry_iface_init)
G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(),
fl_view_keyboard_delegate_iface_init)
G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(),
fl_view_scrolling_delegate_iface_init)
G_IMPLEMENT_INTERFACE(
fl_text_input_view_delegate_get_type(),
G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(),
fl_view_text_input_delegate_iface_init))
// Emit the first frame signal in the main thread.
@ -154,7 +147,7 @@ static void init_keyboard(FlView* self) {
static void init_scrolling(FlView* self) {
g_clear_object(&self->scrolling_manager);
self->scrolling_manager =
fl_scrolling_manager_new(FL_SCROLLING_VIEW_DELEGATE(self));
fl_scrolling_manager_new(self->engine, self->view_id);
}
static FlutterPointerDeviceKind get_device_kind(GdkEvent* event) {
@ -369,33 +362,6 @@ static void fl_view_keyboard_delegate_iface_init(
};
}
static void fl_view_scrolling_delegate_iface_init(
FlScrollingViewDelegateInterface* iface) {
iface->send_mouse_pointer_event =
[](FlScrollingViewDelegate* view_delegate, FlutterPointerPhase phase,
size_t timestamp, double x, double y,
FlutterPointerDeviceKind device_kind, double scroll_delta_x,
double scroll_delta_y, int64_t buttons) {
FlView* self = FL_VIEW(view_delegate);
if (self->engine != nullptr) {
fl_engine_send_mouse_pointer_event(
self->engine, self->view_id, phase, timestamp, x, y, device_kind,
scroll_delta_x, scroll_delta_y, buttons);
}
};
iface->send_pointer_pan_zoom_event =
[](FlScrollingViewDelegate* view_delegate, size_t timestamp, double x,
double y, FlutterPointerPhase phase, double pan_x, double pan_y,
double scale, double rotation) {
FlView* self = FL_VIEW(view_delegate);
if (self->engine != nullptr) {
fl_engine_send_pointer_pan_zoom_event(self->engine, self->view_id,
timestamp, x, y, phase, pan_x,
pan_y, scale, rotation);
};
};
}
static void fl_view_text_input_delegate_iface_init(
FlTextInputViewDelegateInterface* iface) {
iface->translate_coordinates = [](FlTextInputViewDelegate* delegate,