Commit cbe60510 authored by Mike Wasserman's avatar Mike Wasserman Committed by Commit Bot

mus: Support scroll event transport and dispatch

Add ScrollData and EventMomentumPhase mojo struct, enum, and traits.
Remove lossy ScrollEvent conversion code from PlatformDisplayDefault.
Generalize some EventDispatcher code to support non-pointer events.
Add a basic StructTraitsTest.ScrollEvent unit test.

Bug: 602859, b/73663094
Test: onemilescroll.com, Arc++ scrolls/flings with --enable-features=Mus
Change-Id: Ib6ba95fdd79aa67d5ad1b6b7c4ff9f4b38b3e45b
Reviewed-on: https://chromium-review.googlesource.com/940607Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Commit-Queue: Michael Wasserman <msw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#540367}
parent 6a272677
......@@ -41,13 +41,21 @@ bool IsOnlyOneMouseButtonDown(int flags) {
// This is meant to mirror when implicit capture stops. Specifically non-mouse
// pointer up, or mouse and no more buttons down.
bool IsPointerGoingUp(const PointerEvent& event) {
return (event.type() == ui::ET_POINTER_UP ||
bool IsPointerGoingUp(const Event& event) {
return event.IsPointerEvent() &&
(event.type() == ui::ET_POINTER_UP ||
event.type() == ui::ET_POINTER_CANCELLED) &&
(!event.IsMousePointerEvent() ||
IsOnlyOneMouseButtonDown(event.flags()));
}
// Get the pointer id from an event, only supports PointerEvents for now.
int32_t GetPointerId(const Event& event) {
if (event.IsPointerEvent())
return event.AsPointerEvent()->pointer_details().id;
return PointerDetails::kUnknownPointerId;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
......@@ -311,21 +319,21 @@ void EventDispatcher::ProcessEvent(const ui::Event& event,
return;
}
DCHECK(event.IsPointerEvent());
DCHECK(event.IsPointerEvent() || event.IsScrollEvent());
DCHECK(event_location.location == event.AsLocatedEvent()->root_location_f());
DCHECK(event_location.location == event.AsLocatedEvent()->location_f());
DCHECK(!waiting_on_event_targeter_);
const EventSource event_source =
event.IsMousePointerEvent() ? EventSource::MOUSE : EventSource::TOUCH;
DCHECK(event_location.location == event.AsPointerEvent()->root_location_f());
DCHECK(event_location.location == event.AsPointerEvent()->location_f());
if (ShouldUseEventTargeter(*event.AsPointerEvent())) {
if (ShouldUseEventTargeter(event)) {
waiting_on_event_targeter_ = true;
const EventSource event_source =
event.IsMousePointerEvent() ? EventSource::MOUSE : EventSource::TOUCH;
event_targeter_->FindTargetForLocation(
event_source, event_location,
base::BindOnce(&EventDispatcher::ProcessPointerEventOnFoundTarget,
base::Unretained(this), *event.AsPointerEvent()));
base::BindOnce(&EventDispatcher::ProcessEventOnFoundTarget,
base::Unretained(this), ui::Event::Clone(event)));
} else {
ProcessPointerEventOnFoundTargetImpl(*event.AsPointerEvent(),
event_location, nullptr);
ProcessEventOnFoundTargetImpl(ui::Event::Clone(event), event_location,
nullptr);
}
}
......@@ -438,15 +446,14 @@ void EventDispatcher::HideCursorOnMatchedKeyEvent(const ui::KeyEvent& event) {
delegate_->OnEventChangesCursorVisibility(event, false);
}
bool EventDispatcher::ShouldUseEventTargeter(const PointerEvent& event) const {
const int32_t pointer_id = event.pointer_details().id;
bool EventDispatcher::ShouldUseEventTargeter(const Event& event) const {
if (drag_controller_)
return true;
if (capture_window_)
return false;
auto iter = pointer_targets_.find(pointer_id);
auto iter = pointer_targets_.find(GetPointerId(event));
if (iter == pointer_targets_.end() || !iter->second.is_pointer_down)
return true;
......@@ -454,40 +461,39 @@ bool EventDispatcher::ShouldUseEventTargeter(const PointerEvent& event) const {
event.type() == ET_POINTER_DOWN;
}
void EventDispatcher::ProcessPointerEventOnFoundTarget(
const ui::PointerEvent& event,
void EventDispatcher::ProcessEventOnFoundTarget(
std::unique_ptr<ui::Event> event,
const EventLocation& event_location,
const DeepestWindow& target) {
DCHECK(waiting_on_event_targeter_);
waiting_on_event_targeter_ = false;
ProcessPointerEventOnFoundTargetImpl(event, event_location, &target);
ProcessEventOnFoundTargetImpl(std::move(event), event_location, &target);
}
void EventDispatcher::ProcessPointerEventOnFoundTargetImpl(
const ui::PointerEvent& event,
void EventDispatcher::ProcessEventOnFoundTargetImpl(
std::unique_ptr<ui::Event> event,
const EventLocation& event_location,
const DeepestWindow* found_target) {
DCHECK(!waiting_on_event_targeter_);
// WARNING: |found_target| may be null!
std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event);
DCHECK(!waiting_on_event_targeter_);
UpdateCursorRelatedProperties(event, event_location);
UpdateCursorRelatedProperties(*event, event_location);
const bool is_mouse_event = event.IsMousePointerEvent();
const bool is_pointer_going_up = IsPointerGoingUp(event);
const bool is_mouse_event = event->IsMousePointerEvent();
const bool is_pointer_going_up = IsPointerGoingUp(*event);
// Update mouse down state upon events which change it.
if (is_mouse_event) {
if (event.type() == ui::ET_POINTER_DOWN)
if (event->type() == ui::ET_POINTER_DOWN)
mouse_button_down_ = true;
else if (is_pointer_going_up)
mouse_button_down_ = false;
}
if (drag_controller_) {
if (drag_controller_ && event->IsPointerEvent()) {
DCHECK(found_target);
if (drag_controller_->DispatchPointerEvent(
*cloned_event->AsPointerEvent(),
*event->AsPointerEvent(),
AdjustTargetForModal(*found_target).window)) {
return;
}
......@@ -496,7 +502,7 @@ void EventDispatcher::ProcessPointerEventOnFoundTargetImpl(
if (capture_window_) {
SetMouseCursorSourceWindow(capture_window_);
DispatchToClient(capture_window_, capture_window_client_id_,
*cloned_event->AsPointerEvent(), event_location);
*event->AsLocatedEvent(), event_location);
return;
}
......@@ -509,17 +515,16 @@ void EventDispatcher::ProcessPointerEventOnFoundTargetImpl(
result->pointer_target.in_nonclient_area =
result->deepest_window.in_non_client_area;
result->pointer_target.is_pointer_down =
event.type() == ui::ET_POINTER_DOWN;
event->type() == ui::ET_POINTER_DOWN;
result->pointer_target.display_id = event_location.display_id;
}
const int32_t pointer_id = event.pointer_details().id;
const int32_t pointer_id = GetPointerId(*event);
if (!IsTrackingPointer(pointer_id) ||
!pointer_targets_[pointer_id].is_pointer_down) {
DCHECK(result);
const bool any_pointers_down = AreAnyPointersDown();
UpdateTargetForPointer(pointer_id, *cloned_event->AsPointerEvent(),
UpdateTargetForPointer(pointer_id, *event->AsLocatedEvent(),
result->pointer_target, event_location);
if (is_mouse_event)
SetMouseCursorSourceWindow(pointer_targets_[pointer_id].window);
......@@ -550,7 +555,7 @@ void EventDispatcher::ProcessPointerEventOnFoundTargetImpl(
}
DispatchToPointerTarget(pointer_targets_[pointer_id],
*cloned_event->AsPointerEvent(), event_location);
*event->AsLocatedEvent(), event_location);
if (is_pointer_going_up) {
if (is_mouse_event)
......@@ -561,7 +566,7 @@ void EventDispatcher::ProcessPointerEventOnFoundTargetImpl(
delegate_->ReleaseNativeCapture();
}
if (event.type() == ET_POINTER_DOWN) {
if (event->type() == ET_POINTER_DOWN) {
// Use |found_target| as |result| has already been adjusted for the
// modal window.
DCHECK(found_target);
......@@ -571,7 +576,7 @@ void EventDispatcher::ProcessPointerEventOnFoundTargetImpl(
}
void EventDispatcher::UpdateCursorRelatedProperties(
const ui::PointerEvent& event,
const ui::Event& event,
const EventLocation& event_location) {
if (event.IsMousePointerEvent()) {
// This corresponds to the code in CompoundEventFilter which updates
......@@ -585,7 +590,7 @@ void EventDispatcher::UpdateCursorRelatedProperties(
event_location.display_id);
delegate_->OnMouseCursorLocationChanged(event_location.raw_location,
event_location.display_id);
} else {
} else if (event.IsPointerEvent()) {
// When we have a non-touch event that wasn't synthesized, hide the mouse
// cursor until the next non-synthesized mouse event.
delegate_->OnEventChangesCursorTouchVisibility(event, false);
......@@ -663,7 +668,7 @@ void EventDispatcher::StopTrackingPointer(int32_t pointer_id) {
void EventDispatcher::UpdateTargetForPointer(
int32_t pointer_id,
const ui::PointerEvent& event,
const ui::LocatedEvent& event,
const PointerTarget& pointer_target,
const EventLocation& event_location) {
if (!IsTrackingPointer(pointer_id)) {
......
......@@ -33,7 +33,6 @@ namespace ui {
class Event;
class KeyEvent;
class LocatedEvent;
class PointerEvent;
namespace ws {
......@@ -241,16 +240,16 @@ class EventDispatcher : public ServerWindowDrawnTrackerObserver,
return pointer_targets_.count(pointer_id) > 0;
}
// Returns true if EventTargeter needs to queried for the specified event.
bool ShouldUseEventTargeter(const PointerEvent& event) const;
// Returns true if EventTargeter needs to be queried for the specified event.
bool ShouldUseEventTargeter(const Event& event) const;
// Callback from EventTargeter once the target has been found. Calls
// ProcessPointerEventOnFoundTargetImpl().
void ProcessPointerEventOnFoundTarget(const ui::PointerEvent& event,
const EventLocation& event_location,
const DeepestWindow& target);
// ProcessEventOnFoundTargetImpl().
void ProcessEventOnFoundTarget(std::unique_ptr<ui::Event> event,
const EventLocation& event_location,
const DeepestWindow& target);
// EventDispatcher provides the following logic for pointer events:
// EventDispatcher provides the following logic for events:
// . wheel events go to the current target of the associated pointer. If
// there is no target, they go to the deepest window.
// . move (not drag) events go to the deepest window.
......@@ -264,13 +263,12 @@ class EventDispatcher : public ServerWindowDrawnTrackerObserver,
// If ShouldUseEventTargeter() returned false it means this function should
// not need |found_target| and has enough information to process the event
// without a DeepestWindow.
void ProcessPointerEventOnFoundTargetImpl(const ui::PointerEvent& event,
const EventLocation& event_location,
const DeepestWindow* found_target);
void ProcessEventOnFoundTargetImpl(std::unique_ptr<ui::Event> event,
const EventLocation& event_location,
const DeepestWindow* found_target);
// Called when processing a pointer event to updated cursor related
// properties.
void UpdateCursorRelatedProperties(const ui::PointerEvent& event,
// Called when processing a event to updated cursor related properties.
void UpdateCursorRelatedProperties(const ui::Event& event,
const EventLocation& event_location);
void UpdateNonClientAreaForCurrentWindowOnFoundWindow(
......@@ -301,7 +299,7 @@ class EventDispatcher : public ServerWindowDrawnTrackerObserver,
// pointer sends the appropriate event to the delegate and updates the
// currently tracked PointerTarget appropriately.
void UpdateTargetForPointer(int32_t pointer_id,
const ui::PointerEvent& event,
const ui::LocatedEvent& event,
const PointerTarget& pointer_target,
const EventLocation& event_location);
......
......@@ -203,16 +203,8 @@ void PlatformDisplayDefault::OnDamageRect(const gfx::Rect& damaged_region) {
}
void PlatformDisplayDefault::DispatchEvent(ui::Event* event) {
// Event location and event root location are the same, and both in pixels
// and display coordinates.
if (event->IsScrollEvent()) {
// TODO(moshayedi): crbug.com/602859. Dispatch scroll events as
// they are once we have proper support for scroll events.
ui::PointerEvent pointer_event(
ui::MouseWheelEvent(*event->AsScrollEvent()));
SendEventToSink(&pointer_event);
} else if (event->IsMouseEvent()) {
// Mojo requires conversion of mouse and touch events to pointer events.
if (event->IsMouseEvent()) {
ui::PointerEvent pointer_event(*event->AsMouseEvent());
SendEventToSink(&pointer_event);
} else if (event->IsTouchEvent()) {
......
......@@ -122,6 +122,24 @@ struct GestureData {
LocationData location;
};
// Data to support scroll events.
struct ScrollData {
LocationData location;
// Potential accelerated offsets.
float x_offset;
float y_offset;
// Unaccelerated offsets.
float x_offset_ordinal;
float y_offset_ordinal;
// Number of fingers on the pad.
int32 finger_count;
// For non-fling events, provides momentum information (e.g. for the case
// where the device provides continuous event updates during a fling).
EventMomentumPhase momentum_phase;
};
struct Event {
// TODO(sky): rename to type.
EventType action;
......@@ -138,4 +156,5 @@ struct Event {
KeyData? key_data;
PointerData? pointer_data;
GestureData? gesture_data;
ScrollData? scroll_data;
};
......@@ -21,4 +21,7 @@ sources = [
]
# TODO(moshayedi): crbug.com/617167. Map mojom.Event directly to ui::Event.
type_mappings = [ "ui.mojom.Event=std::unique_ptr<ui::Event>[move_only]" ]
type_mappings = [
"ui.mojom.Event=std::unique_ptr<ui::Event>[move_only]",
"ui.mojom.EventMomentumPhase=ui::EventMomentumPhase",
]
......@@ -23,6 +23,9 @@ enum EventType {
POINTER_WHEEL_CHANGED,
MOUSE_EXIT,
GESTURE_TAP,
SCROLL,
SCROLL_FLING_START,
SCROLL_FLING_CANCEL,
};
// This mirrors ui::EventFlags
......@@ -63,3 +66,12 @@ enum WheelMode {
PAGE,
SCALING,
};
// Momentum phase information used for a ScrollEvent.
// These values match ui::EventMomentumPhase in ui/events/event_constants.h
enum EventMomentumPhase {
NONE,
MAY_BEGIN,
INERTIAL_UPDATE,
END,
};
\ No newline at end of file
......@@ -43,6 +43,15 @@ ui::mojom::EventType UIEventTypeToMojo(ui::EventType type) {
case ui::ET_GESTURE_TAP:
return ui::mojom::EventType::GESTURE_TAP;
case ui::ET_SCROLL:
return ui::mojom::EventType::SCROLL;
case ui::ET_SCROLL_FLING_START:
return ui::mojom::EventType::SCROLL_FLING_START;
case ui::ET_SCROLL_FLING_CANCEL:
return ui::mojom::EventType::SCROLL_FLING_CANCEL;
default:
NOTREACHED() << "This unsupported event type will close the connection";
break;
......@@ -70,6 +79,15 @@ ui::EventType MojoPointerEventTypeToUIEvent(ui::mojom::EventType action) {
case ui::mojom::EventType::POINTER_WHEEL_CHANGED:
return ui::ET_POINTER_WHEEL_CHANGED;
case ui::mojom::EventType::SCROLL:
return ui::ET_SCROLL;
case ui::mojom::EventType::SCROLL_FLING_START:
return ui::ET_SCROLL_FLING_START;
case ui::mojom::EventType::SCROLL_FLING_CANCEL:
return ui::ET_SCROLL_FLING_CANCEL;
default:
NOTREACHED();
}
......@@ -77,7 +95,7 @@ ui::EventType MojoPointerEventTypeToUIEvent(ui::mojom::EventType action) {
return ui::ET_UNKNOWN;
}
ui::mojom::LocationDataPtr GetLocationData(ui::LocatedEvent* event) {
ui::mojom::LocationDataPtr GetLocationData(const ui::LocatedEvent* event) {
ui::mojom::LocationDataPtr location_data(ui::mojom::LocationData::New());
location_data->x = event->location_f().x();
location_data->y = event->location_f().y();
......@@ -319,6 +337,24 @@ StructTraits<ui::mojom::EventDataView, EventUniquePtr>::gesture_data(
return gesture_data;
}
ui::mojom::ScrollDataPtr
StructTraits<ui::mojom::EventDataView, EventUniquePtr>::scroll_data(
const EventUniquePtr& event) {
if (!event->IsScrollEvent())
return nullptr;
ui::mojom::ScrollDataPtr scroll_data(ui::mojom::ScrollData::New());
scroll_data->location = GetLocationData(event->AsLocatedEvent());
const ui::ScrollEvent* scroll_event = event->AsScrollEvent();
scroll_data->x_offset = scroll_event->x_offset();
scroll_data->y_offset = scroll_event->y_offset();
scroll_data->x_offset_ordinal = scroll_event->x_offset_ordinal();
scroll_data->y_offset_ordinal = scroll_event->y_offset_ordinal();
scroll_data->finger_count = scroll_event->finger_count();
scroll_data->momentum_phase = scroll_event->momentum_phase();
return scroll_data;
}
bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read(
ui::mojom::EventDataView event,
EventUniquePtr* out) {
......@@ -386,6 +422,22 @@ bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read(
time_stamp, ui::GestureEventDetails(ui::ET_GESTURE_TAP));
break;
}
case ui::mojom::EventType::SCROLL:
case ui::mojom::EventType::SCROLL_FLING_START:
case ui::mojom::EventType::SCROLL_FLING_CANCEL: {
ui::mojom::ScrollDataPtr scroll_data;
if (!event.ReadScrollData<ui::mojom::ScrollDataPtr>(&scroll_data))
return false;
*out = std::make_unique<ui::ScrollEvent>(
MojoPointerEventTypeToUIEvent(event.action()),
gfx::Point(scroll_data->location->x, scroll_data->location->y),
time_stamp, event.flags(), scroll_data->x_offset,
scroll_data->y_offset, scroll_data->x_offset_ordinal,
scroll_data->y_offset_ordinal, scroll_data->finger_count,
scroll_data->momentum_phase);
break;
}
case ui::mojom::EventType::UNKNOWN:
NOTREACHED() << "This unsupported event type will close the connection";
return false;
......
......@@ -5,7 +5,9 @@
#ifndef UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
#define UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
#include "ui/events/event_constants.h"
#include "ui/events/mojo/event.mojom.h"
#include "ui/events/mojo/event_constants.mojom.h"
namespace ui {
class Event;
......@@ -25,9 +27,48 @@ struct StructTraits<ui::mojom::EventDataView, EventUniquePtr> {
static ui::mojom::KeyDataPtr key_data(const EventUniquePtr& event);
static ui::mojom::PointerDataPtr pointer_data(const EventUniquePtr& event);
static ui::mojom::GestureDataPtr gesture_data(const EventUniquePtr& event);
static ui::mojom::ScrollDataPtr scroll_data(const EventUniquePtr& event);
static bool Read(ui::mojom::EventDataView r, EventUniquePtr* out);
};
template <>
struct EnumTraits<ui::mojom::EventMomentumPhase, ui::EventMomentumPhase> {
static ui::mojom::EventMomentumPhase ToMojom(ui::EventMomentumPhase input) {
switch (input) {
case ui::EventMomentumPhase::NONE:
return ui::mojom::EventMomentumPhase::NONE;
case ui::EventMomentumPhase::MAY_BEGIN:
return ui::mojom::EventMomentumPhase::MAY_BEGIN;
case ui::EventMomentumPhase::INERTIAL_UPDATE:
return ui::mojom::EventMomentumPhase::INERTIAL_UPDATE;
case ui::EventMomentumPhase::END:
return ui::mojom::EventMomentumPhase::END;
}
NOTREACHED();
return ui::mojom::EventMomentumPhase::NONE;
}
static bool FromMojom(ui::mojom::EventMomentumPhase input,
ui::EventMomentumPhase* out) {
switch (input) {
case ui::mojom::EventMomentumPhase::NONE:
*out = ui::EventMomentumPhase::NONE;
return true;
case ui::mojom::EventMomentumPhase::MAY_BEGIN:
*out = ui::EventMomentumPhase::MAY_BEGIN;
return true;
case ui::mojom::EventMomentumPhase::INERTIAL_UPDATE:
*out = ui::EventMomentumPhase::INERTIAL_UPDATE;
return true;
case ui::mojom::EventMomentumPhase::END:
*out = ui::EventMomentumPhase::END;
return true;
}
NOTREACHED();
return false;
}
};
} // namespace mojo
#endif // UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
......@@ -250,4 +250,40 @@ TEST_F(StructTraitsTest, GestureEvent) {
}
}
TEST_F(StructTraitsTest, ScrollEvent) {
ScrollEvent kTestData[] = {
{ET_SCROLL, gfx::Point(10, 20),
base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
2, 3, 4, 5, EventMomentumPhase::NONE},
{ET_SCROLL_FLING_START, gfx::Point(10, 20),
base::TimeTicks() + base::TimeDelta::FromMicroseconds(502), EF_NONE, 1,
2, 3, 4, 5, EventMomentumPhase::MAY_BEGIN},
{ET_SCROLL_FLING_CANCEL, gfx::Point(10, 20),
base::TimeTicks() + base::TimeDelta::FromMicroseconds(502), EF_NONE, 1,
2, 3, 4, 5, EventMomentumPhase::END},
};
mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
for (size_t i = 0; i < arraysize(kTestData); i++) {
std::unique_ptr<Event> output;
proxy->EchoEvent(Event::Clone(kTestData[i]), &output);
EXPECT_TRUE(output->IsScrollEvent());
const ScrollEvent* output_ptr_event = output->AsScrollEvent();
EXPECT_EQ(kTestData[i].type(), output_ptr_event->type());
EXPECT_EQ(kTestData[i].location(), output_ptr_event->location());
EXPECT_EQ(kTestData[i].time_stamp(), output_ptr_event->time_stamp());
EXPECT_EQ(kTestData[i].flags(), output_ptr_event->flags());
EXPECT_EQ(kTestData[i].x_offset(), output_ptr_event->x_offset());
EXPECT_EQ(kTestData[i].y_offset(), output_ptr_event->y_offset());
EXPECT_EQ(kTestData[i].x_offset_ordinal(),
output_ptr_event->x_offset_ordinal());
EXPECT_EQ(kTestData[i].y_offset_ordinal(),
output_ptr_event->y_offset_ordinal());
EXPECT_EQ(kTestData[i].finger_count(), output_ptr_event->finger_count());
EXPECT_EQ(kTestData[i].momentum_phase(),
output_ptr_event->momentum_phase());
}
}
} // namespace ui
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment