mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Fuchsia] Support scroll_*_physical_pixel fields (flutter/engine#34325)
* [WIP][Fuchsia] Support scroll_physical_pixel fields * add test * update * update * update * update * update * update * update * update * use scroll_delta instead of pan * use kMouse * use kMouse * Update shell/platform/fuchsia/flutter/pointer_delegate.cc Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com> * Update shell/platform/fuchsia/flutter/pointer_delegate.cc Co-authored-by: Callum Moffat <smartercallum@gmail.com> * format Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com> Co-authored-by: Callum Moffat <smartercallum@gmail.com>
This commit is contained in:
parent
271b59d7a6
commit
4b0da8fac2
@ -287,22 +287,40 @@ flutter::PointerData CreateMouseDraft(const fup_MouseEvent& event,
|
||||
ptr.buttons = flutter_buttons;
|
||||
}
|
||||
|
||||
// Fuchsia currently provides scroll data in "ticks", not physical pixels.
|
||||
// However, Flutter expects scroll data in physical pixels. To compensate for
|
||||
// lack of guidance, we make up a "reasonable amount".
|
||||
// TODO(fxbug.dev/85388): Replace with physical pixel scroll.
|
||||
// Fuchsia previously only provided scroll data in "ticks", not physical
|
||||
// pixels. On legacy platforms, since Flutter expects scroll data in physical
|
||||
// pixels, to compensate for lack of guidance, we make up a "reasonable
|
||||
// amount".
|
||||
// TODO(fxbug.dev/103443): Remove the tick based scrolling after the
|
||||
// transition.
|
||||
const int kScrollOffsetMultiplier = 20;
|
||||
|
||||
if (sample.has_scroll_v()) {
|
||||
ptr.signal_kind = flutter::PointerData::SignalKind::kScroll;
|
||||
double dy = -sample.scroll_v() * kScrollOffsetMultiplier; // logical amount
|
||||
ptr.scroll_delta_y = dy; // Not yet physical; adjusted in Platform View.
|
||||
double dy = 0;
|
||||
double dx = 0;
|
||||
bool is_scroll = false;
|
||||
|
||||
if (sample.has_scroll_v_physical_pixel()) {
|
||||
dy = -sample.scroll_v_physical_pixel();
|
||||
is_scroll = true;
|
||||
} else if (sample.has_scroll_v()) {
|
||||
dy = -sample.scroll_v() *
|
||||
kScrollOffsetMultiplier; // logical amount, not yet physical; adjusted
|
||||
// in Platform View.
|
||||
is_scroll = true;
|
||||
}
|
||||
|
||||
if (sample.has_scroll_h()) {
|
||||
if (sample.has_scroll_h_physical_pixel()) {
|
||||
dx = sample.scroll_h_physical_pixel();
|
||||
is_scroll = true;
|
||||
} else if (sample.has_scroll_h()) {
|
||||
dx = sample.scroll_h() * kScrollOffsetMultiplier; // logical amount
|
||||
is_scroll = true;
|
||||
}
|
||||
|
||||
if (is_scroll) {
|
||||
ptr.signal_kind = flutter::PointerData::SignalKind::kScroll;
|
||||
double dx = sample.scroll_h() * kScrollOffsetMultiplier; // logical amount
|
||||
ptr.scroll_delta_x = dx; // Not yet physical; adjusted in Platform View.
|
||||
ptr.scroll_delta_y = dy;
|
||||
ptr.scroll_delta_x = dx;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
|
||||
@ -30,6 +30,7 @@ using fup_TouchPointerSample = fuchsia::ui::pointer::TouchPointerSample;
|
||||
using fup_TouchResponse = fuchsia::ui::pointer::TouchResponse;
|
||||
using fup_TouchResponseType = fuchsia::ui::pointer::TouchResponseType;
|
||||
using fup_ViewParameters = fuchsia::ui::pointer::ViewParameters;
|
||||
using fup_MouseEvent = fuchsia::ui::pointer::MouseEvent;
|
||||
|
||||
constexpr std::array<std::array<float, 2>, 2> kRect = {{{0, 0}, {20, 20}}};
|
||||
constexpr std::array<float, 9> kIdentity = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
@ -37,6 +38,11 @@ constexpr fup_TouchIxnId kIxnOne = {.device_id = 1u,
|
||||
.pointer_id = 1u,
|
||||
.interaction_id = 2u};
|
||||
|
||||
constexpr uint32_t kMouseDeviceId = 123;
|
||||
constexpr std::array<int64_t, 2> kNoScrollInPhysicalPixelDelta = {0, 0};
|
||||
const bool kNotPrecisionScroll = false;
|
||||
const bool kPrecisionScroll = true;
|
||||
|
||||
// Fixture to exercise Flutter runner's implementation for
|
||||
// fuchsia.ui.pointer.TouchSource.
|
||||
class PointerDelegateTest : public ::testing::Test {
|
||||
@ -676,4 +682,163 @@ TEST_F(PointerDelegateTest, Protocol_PointersAreIndependent) {
|
||||
pointers = {};
|
||||
}
|
||||
|
||||
TEST_F(PointerDelegateTest, MouseWheel_TickBased) {
|
||||
std::optional<std::vector<flutter::PointerData>> pointers;
|
||||
pointer_delegate_->WatchLoop(
|
||||
[&pointers](std::vector<flutter::PointerData> events) {
|
||||
pointers = std::move(events);
|
||||
});
|
||||
RunLoopUntilIdle(); // Server gets watch call.
|
||||
|
||||
std::vector<fup_MouseEvent> events =
|
||||
MouseEventBuilder()
|
||||
.AddTime(1111789u)
|
||||
.AddViewParameters(kRect, kRect, kIdentity)
|
||||
.AddSample(kMouseDeviceId, {10.f, 10.f}, {}, {0, 1},
|
||||
kNoScrollInPhysicalPixelDelta, kNotPrecisionScroll)
|
||||
.AddMouseDeviceInfo(kMouseDeviceId, {0, 1, 2})
|
||||
.BuildAsVector();
|
||||
mouse_source_->ScheduleCallback(std::move(events));
|
||||
RunLoopUntilIdle();
|
||||
|
||||
ASSERT_TRUE(pointers.has_value());
|
||||
ASSERT_EQ(pointers.value().size(), 1u);
|
||||
EXPECT_EQ(pointers.value()[0].change, flutter::PointerData::Change::kHover);
|
||||
EXPECT_EQ(pointers.value()[0].signal_kind,
|
||||
flutter::PointerData::SignalKind::kScroll);
|
||||
EXPECT_EQ(pointers.value()[0].kind, flutter::PointerData::DeviceKind::kMouse);
|
||||
EXPECT_EQ(pointers.value()[0].buttons, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_x, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_y, -20);
|
||||
pointers = {};
|
||||
|
||||
// receive a horizontal scroll
|
||||
events = MouseEventBuilder()
|
||||
.AddTime(1111789u)
|
||||
.AddViewParameters(kRect, kRect, kIdentity)
|
||||
.AddSample(kMouseDeviceId, {10.f, 10.f}, {}, {1, 0},
|
||||
kNoScrollInPhysicalPixelDelta, kNotPrecisionScroll)
|
||||
.AddMouseDeviceInfo(kMouseDeviceId, {0, 1, 2})
|
||||
.BuildAsVector();
|
||||
mouse_source_->ScheduleCallback(std::move(events));
|
||||
RunLoopUntilIdle();
|
||||
|
||||
ASSERT_TRUE(pointers.has_value());
|
||||
ASSERT_EQ(pointers.value().size(), 1u);
|
||||
EXPECT_EQ(pointers.value()[0].change, flutter::PointerData::Change::kHover);
|
||||
EXPECT_EQ(pointers.value()[0].signal_kind,
|
||||
flutter::PointerData::SignalKind::kScroll);
|
||||
EXPECT_EQ(pointers.value()[0].kind, flutter::PointerData::DeviceKind::kMouse);
|
||||
EXPECT_EQ(pointers.value()[0].buttons, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_x, 20);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_y, 0);
|
||||
pointers = {};
|
||||
}
|
||||
|
||||
TEST_F(PointerDelegateTest, MouseWheel_PixelBased) {
|
||||
std::optional<std::vector<flutter::PointerData>> pointers;
|
||||
pointer_delegate_->WatchLoop(
|
||||
[&pointers](std::vector<flutter::PointerData> events) {
|
||||
pointers = std::move(events);
|
||||
});
|
||||
RunLoopUntilIdle(); // Server gets watch call.
|
||||
|
||||
std::vector<fup_MouseEvent> events =
|
||||
MouseEventBuilder()
|
||||
.AddTime(1111789u)
|
||||
.AddViewParameters(kRect, kRect, kIdentity)
|
||||
.AddSample(kMouseDeviceId, {10.f, 10.f}, {}, {0, 1}, {0, 120},
|
||||
kNotPrecisionScroll)
|
||||
.AddMouseDeviceInfo(kMouseDeviceId, {0, 1, 2})
|
||||
.BuildAsVector();
|
||||
mouse_source_->ScheduleCallback(std::move(events));
|
||||
RunLoopUntilIdle();
|
||||
|
||||
ASSERT_TRUE(pointers.has_value());
|
||||
ASSERT_EQ(pointers.value().size(), 1u);
|
||||
EXPECT_EQ(pointers.value()[0].change, flutter::PointerData::Change::kHover);
|
||||
EXPECT_EQ(pointers.value()[0].signal_kind,
|
||||
flutter::PointerData::SignalKind::kScroll);
|
||||
EXPECT_EQ(pointers.value()[0].kind, flutter::PointerData::DeviceKind::kMouse);
|
||||
EXPECT_EQ(pointers.value()[0].buttons, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_x, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_y, -120);
|
||||
pointers = {};
|
||||
|
||||
// receive a horizontal scroll
|
||||
events = MouseEventBuilder()
|
||||
.AddTime(1111789u)
|
||||
.AddViewParameters(kRect, kRect, kIdentity)
|
||||
.AddSample(kMouseDeviceId, {10.f, 10.f}, {}, {1, 0}, {120, 0},
|
||||
kNotPrecisionScroll)
|
||||
.AddMouseDeviceInfo(kMouseDeviceId, {0, 1, 2})
|
||||
.BuildAsVector();
|
||||
mouse_source_->ScheduleCallback(std::move(events));
|
||||
RunLoopUntilIdle();
|
||||
|
||||
ASSERT_TRUE(pointers.has_value());
|
||||
ASSERT_EQ(pointers.value().size(), 1u);
|
||||
EXPECT_EQ(pointers.value()[0].change, flutter::PointerData::Change::kHover);
|
||||
EXPECT_EQ(pointers.value()[0].signal_kind,
|
||||
flutter::PointerData::SignalKind::kScroll);
|
||||
EXPECT_EQ(pointers.value()[0].kind, flutter::PointerData::DeviceKind::kMouse);
|
||||
EXPECT_EQ(pointers.value()[0].buttons, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_x, 120);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_y, 0);
|
||||
pointers = {};
|
||||
}
|
||||
|
||||
TEST_F(PointerDelegateTest, MouseWheel_TouchpadPixelBased) {
|
||||
std::optional<std::vector<flutter::PointerData>> pointers;
|
||||
pointer_delegate_->WatchLoop(
|
||||
[&pointers](std::vector<flutter::PointerData> events) {
|
||||
pointers = std::move(events);
|
||||
});
|
||||
RunLoopUntilIdle(); // Server gets watch call.
|
||||
|
||||
std::vector<fup_MouseEvent> events =
|
||||
MouseEventBuilder()
|
||||
.AddTime(1111789u)
|
||||
.AddViewParameters(kRect, kRect, kIdentity)
|
||||
.AddSample(kMouseDeviceId, {10.f, 10.f}, {}, {0, 1}, {0, 120},
|
||||
kPrecisionScroll)
|
||||
.AddMouseDeviceInfo(kMouseDeviceId, {0, 1, 2})
|
||||
.BuildAsVector();
|
||||
mouse_source_->ScheduleCallback(std::move(events));
|
||||
RunLoopUntilIdle();
|
||||
|
||||
ASSERT_TRUE(pointers.has_value());
|
||||
ASSERT_EQ(pointers.value().size(), 1u);
|
||||
EXPECT_EQ(pointers.value()[0].change, flutter::PointerData::Change::kHover);
|
||||
EXPECT_EQ(pointers.value()[0].signal_kind,
|
||||
flutter::PointerData::SignalKind::kScroll);
|
||||
EXPECT_EQ(pointers.value()[0].kind, flutter::PointerData::DeviceKind::kMouse);
|
||||
EXPECT_EQ(pointers.value()[0].buttons, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_x, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_y, -120);
|
||||
pointers = {};
|
||||
|
||||
// receive a horizontal scroll
|
||||
events = MouseEventBuilder()
|
||||
.AddTime(1111789u)
|
||||
.AddViewParameters(kRect, kRect, kIdentity)
|
||||
.AddSample(kMouseDeviceId, {10.f, 10.f}, {}, {1, 0}, {120, 0},
|
||||
kPrecisionScroll)
|
||||
.AddMouseDeviceInfo(kMouseDeviceId, {0, 1, 2})
|
||||
.BuildAsVector();
|
||||
mouse_source_->ScheduleCallback(std::move(events));
|
||||
RunLoopUntilIdle();
|
||||
|
||||
ASSERT_TRUE(pointers.has_value());
|
||||
ASSERT_EQ(pointers.value().size(), 1u);
|
||||
EXPECT_EQ(pointers.value()[0].change, flutter::PointerData::Change::kHover);
|
||||
EXPECT_EQ(pointers.value()[0].signal_kind,
|
||||
flutter::PointerData::SignalKind::kScroll);
|
||||
EXPECT_EQ(pointers.value()[0].kind, flutter::PointerData::DeviceKind::kMouse);
|
||||
EXPECT_EQ(pointers.value()[0].buttons, 0);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_x, 120);
|
||||
EXPECT_EQ(pointers.value()[0].scroll_delta_y, 0);
|
||||
pointers = {};
|
||||
}
|
||||
|
||||
} // namespace flutter_runner::testing
|
||||
|
||||
@ -12,6 +12,30 @@ using fup_TouchIxnId = fuchsia::ui::pointer::TouchInteractionId;
|
||||
using fup_TouchIxnResult = fuchsia::ui::pointer::TouchInteractionResult;
|
||||
using fup_TouchPointerSample = fuchsia::ui::pointer::TouchPointerSample;
|
||||
using fup_ViewParameters = fuchsia::ui::pointer::ViewParameters;
|
||||
using fup_MouseEvent = fuchsia::ui::pointer::MouseEvent;
|
||||
using fup_MousePointerSample = fuchsia::ui::pointer::MousePointerSample;
|
||||
using fup_MouseDeviceInfo = fuchsia::ui::pointer::MouseDeviceInfo;
|
||||
|
||||
namespace {
|
||||
|
||||
fup_ViewParameters CreateViewParameters(
|
||||
std::array<std::array<float, 2>, 2> view,
|
||||
std::array<std::array<float, 2>, 2> viewport,
|
||||
std::array<float, 9> transform) {
|
||||
fup_ViewParameters params;
|
||||
fuchsia::ui::pointer::Rectangle view_rect;
|
||||
view_rect.min = view[0];
|
||||
view_rect.max = view[1];
|
||||
params.view = view_rect;
|
||||
fuchsia::ui::pointer::Rectangle viewport_rect;
|
||||
viewport_rect.min = viewport[0];
|
||||
viewport_rect.max = viewport[1];
|
||||
params.viewport = viewport_rect;
|
||||
params.viewport_to_view_transform = transform;
|
||||
return params;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TouchEventBuilder TouchEventBuilder::New() {
|
||||
return TouchEventBuilder();
|
||||
@ -36,16 +60,8 @@ TouchEventBuilder& TouchEventBuilder::AddViewParameters(
|
||||
std::array<std::array<float, 2>, 2> view,
|
||||
std::array<std::array<float, 2>, 2> viewport,
|
||||
std::array<float, 9> transform) {
|
||||
params_ = std::make_optional<fup_ViewParameters>();
|
||||
fuchsia::ui::pointer::Rectangle view_rect;
|
||||
view_rect.min = view[0];
|
||||
view_rect.max = view[1];
|
||||
params_->view = view_rect;
|
||||
fuchsia::ui::pointer::Rectangle viewport_rect;
|
||||
viewport_rect.min = viewport[0];
|
||||
viewport_rect.max = viewport[1];
|
||||
params_->viewport = viewport_rect;
|
||||
params_->viewport_to_view_transform = transform;
|
||||
params_ = CreateViewParameters(std::move(view), std::move(viewport),
|
||||
std::move(transform));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -77,4 +93,84 @@ std::vector<fup_TouchEvent> TouchEventBuilder::BuildAsVector() {
|
||||
return events;
|
||||
}
|
||||
|
||||
MouseEventBuilder MouseEventBuilder::New() {
|
||||
return MouseEventBuilder();
|
||||
}
|
||||
|
||||
MouseEventBuilder& MouseEventBuilder::AddTime(zx_time_t time) {
|
||||
time_ = time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MouseEventBuilder& MouseEventBuilder::AddSample(
|
||||
uint32_t id,
|
||||
std::array<float, 2> position,
|
||||
std::vector<uint8_t> pressed_buttons,
|
||||
std::array<int64_t, 2> scroll,
|
||||
std::array<int64_t, 2> scroll_in_physical_pixel,
|
||||
bool is_precision_scroll) {
|
||||
sample_ = std::make_optional<fup_MousePointerSample>();
|
||||
sample_->set_device_id(id);
|
||||
if (!pressed_buttons.empty()) {
|
||||
sample_->set_pressed_buttons(pressed_buttons);
|
||||
}
|
||||
sample_->set_position_in_viewport(position);
|
||||
if (scroll[0] != 0) {
|
||||
sample_->set_scroll_h(scroll[0]);
|
||||
}
|
||||
if (scroll[1] != 0) {
|
||||
sample_->set_scroll_v(scroll[1]);
|
||||
}
|
||||
if (scroll_in_physical_pixel[0] != 0) {
|
||||
sample_->set_scroll_h_physical_pixel(scroll_in_physical_pixel[0]);
|
||||
}
|
||||
if (scroll_in_physical_pixel[1] != 0) {
|
||||
sample_->set_scroll_v_physical_pixel(scroll_in_physical_pixel[1]);
|
||||
}
|
||||
sample_->set_is_precision_scroll(is_precision_scroll);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MouseEventBuilder& MouseEventBuilder::AddViewParameters(
|
||||
std::array<std::array<float, 2>, 2> view,
|
||||
std::array<std::array<float, 2>, 2> viewport,
|
||||
std::array<float, 9> transform) {
|
||||
params_ = CreateViewParameters(std::move(view), std::move(viewport),
|
||||
std::move(transform));
|
||||
return *this;
|
||||
}
|
||||
|
||||
MouseEventBuilder& MouseEventBuilder::AddMouseDeviceInfo(
|
||||
uint32_t id,
|
||||
std::vector<uint8_t> buttons) {
|
||||
device_info_ = std::make_optional<fup_MouseDeviceInfo>();
|
||||
device_info_->set_id(id);
|
||||
device_info_->set_buttons(buttons);
|
||||
return *this;
|
||||
}
|
||||
|
||||
fup_MouseEvent MouseEventBuilder::Build() {
|
||||
fup_MouseEvent event;
|
||||
if (time_) {
|
||||
event.set_timestamp(time_.value());
|
||||
}
|
||||
if (params_) {
|
||||
event.set_view_parameters(std::move(params_.value()));
|
||||
}
|
||||
if (sample_) {
|
||||
event.set_pointer_sample(std::move(sample_.value()));
|
||||
}
|
||||
if (device_info_) {
|
||||
event.set_device_info(std::move(device_info_.value()));
|
||||
}
|
||||
event.set_trace_flow_id(123);
|
||||
return event;
|
||||
}
|
||||
|
||||
std::vector<fup_MouseEvent> MouseEventBuilder::BuildAsVector() {
|
||||
std::vector<fup_MouseEvent> events;
|
||||
events.emplace_back(Build());
|
||||
return events;
|
||||
}
|
||||
|
||||
} // namespace flutter_runner::testing
|
||||
|
||||
@ -40,6 +40,34 @@ class TouchEventBuilder {
|
||||
std::optional<fuchsia::ui::pointer::TouchInteractionResult> result_;
|
||||
};
|
||||
|
||||
// A helper class for crafting a fuchsia.ui.pointer.MouseEventBuilder table.
|
||||
class MouseEventBuilder {
|
||||
public:
|
||||
static MouseEventBuilder New();
|
||||
|
||||
MouseEventBuilder& AddTime(zx_time_t time);
|
||||
MouseEventBuilder& AddSample(uint32_t id,
|
||||
std::array<float, 2> position,
|
||||
std::vector<uint8_t> pressed_buttons,
|
||||
std::array<int64_t, 2> scroll,
|
||||
std::array<int64_t, 2> scroll_in_physical_pixel,
|
||||
bool is_precision_scroll);
|
||||
MouseEventBuilder& AddViewParameters(
|
||||
std::array<std::array<float, 2>, 2> view,
|
||||
std::array<std::array<float, 2>, 2> viewport,
|
||||
std::array<float, 9> transform);
|
||||
MouseEventBuilder& AddMouseDeviceInfo(uint32_t id,
|
||||
std::vector<uint8_t> buttons);
|
||||
fuchsia::ui::pointer::MouseEvent Build();
|
||||
std::vector<fuchsia::ui::pointer::MouseEvent> BuildAsVector();
|
||||
|
||||
private:
|
||||
std::optional<zx_time_t> time_;
|
||||
std::optional<fuchsia::ui::pointer::MousePointerSample> sample_;
|
||||
std::optional<fuchsia::ui::pointer::ViewParameters> params_;
|
||||
std::optional<fuchsia::ui::pointer::MouseDeviceInfo> device_info_;
|
||||
};
|
||||
|
||||
} // namespace flutter_runner::testing
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_TESTS_POINTER_EVENT_UTILITY_H_
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user