[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:
巢鹏 2022-07-15 17:51:59 -04:00 committed by GitHub
parent 271b59d7a6
commit 4b0da8fac2
4 changed files with 328 additions and 21 deletions

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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_