blob: b4fe739b88b8e4bfe6e778b18fbc4d5b78c303e3 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "third_party/blink/public/common/input/web_coalesced_input_event_mojom_traits.h"
#include <memory>
#include "base/i18n/char_iterator.h"
#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "third_party/blink/public/common/input/web_gesture_event.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "ui/latency/mojom/latency_info_mojom_traits.h"
namespace mojo {
namespace {
void CopyString(char16_t* dst, const std::u16string& text) {
size_t pos = 0;
for (base::i18n::UTF16CharIterator iter(text);
!iter.end() && pos < blink::WebKeyboardEvent::kTextLengthCap - 1;
iter.Advance()) {
dst[pos++] = iter.get();
}
dst[pos] = '\0';
}
blink::mojom::PointerDataPtr PointerDataFromPointerProperties(
const blink::WebPointerProperties& pointer,
blink::mojom::MouseDataPtr mouse_data) {
return blink::mojom::PointerData::New(
pointer.id, pointer.force, pointer.tilt_x, pointer.tilt_y,
pointer.tangential_pressure, pointer.twist, pointer.button,
pointer.pointer_type, pointer.movement_x, pointer.movement_y,
pointer.is_raw_movement_event, pointer.PositionInWidget(),
pointer.PositionInScreen(), std::move(mouse_data));
}
void PointerPropertiesFromPointerData(
const blink::mojom::PointerDataPtr& pointer_data,
blink::WebPointerProperties* pointer_properties) {
pointer_properties->id = pointer_data->pointer_id;
pointer_properties->force = pointer_data->force;
pointer_properties->tilt_x = pointer_data->tilt_x;
pointer_properties->tilt_y = pointer_data->tilt_y;
pointer_properties->tangential_pressure = pointer_data->tangential_pressure;
pointer_properties->twist = pointer_data->twist;
pointer_properties->button = pointer_data->button;
pointer_properties->pointer_type = pointer_data->pointer_type;
pointer_properties->movement_x = pointer_data->movement_x;
pointer_properties->movement_y = pointer_data->movement_y;
pointer_properties->is_raw_movement_event =
pointer_data->is_raw_movement_event;
}
void TouchPointPropertiesFromPointerData(
const blink::mojom::TouchPointPtr& mojo_touch_point,
blink::WebTouchPoint* touch_point) {
PointerPropertiesFromPointerData(mojo_touch_point->pointer_data, touch_point);
touch_point->state = mojo_touch_point->state;
touch_point->radius_x = mojo_touch_point->radius_x;
touch_point->radius_y = mojo_touch_point->radius_y;
touch_point->rotation_angle = mojo_touch_point->rotation_angle;
touch_point->SetPositionInWidget(
mojo_touch_point->pointer_data->widget_position.x(),
mojo_touch_point->pointer_data->widget_position.y());
touch_point->SetPositionInScreen(
mojo_touch_point->pointer_data->screen_position.x(),
mojo_touch_point->pointer_data->screen_position.y());
}
// TODO(dtapuska): Remove once SetPositionInXXX moves to WebPointerProperties.
void MouseEventPropertiesFromPointerData(
const blink::mojom::PointerDataPtr& pointer_data,
blink::WebMouseEvent* mouse_event) {
PointerPropertiesFromPointerData(pointer_data, mouse_event);
mouse_event->SetPositionInWidget(pointer_data->widget_position.x(),
pointer_data->widget_position.y());
mouse_event->SetPositionInScreen(pointer_data->screen_position.x(),
pointer_data->screen_position.y());
}
} // namespace
bool StructTraits<blink::mojom::EventDataView,
std::unique_ptr<blink::WebCoalescedInputEvent>>::
Read(blink::mojom::EventDataView event,
std::unique_ptr<blink::WebCoalescedInputEvent>* out) {
DCHECK(!out->get());
blink::WebInputEvent::Type type;
if (!event.ReadType(&type))
return false;
base::TimeTicks timestamp;
if (!event.ReadTimestamp(&timestamp))
return false;
std::unique_ptr<blink::WebInputEvent> input_event;
if (blink::WebInputEvent::IsKeyboardEventType(type)) {
blink::mojom::KeyDataPtr key_data;
if (!event.ReadKeyData<blink::mojom::KeyDataPtr>(&key_data))
return false;
input_event = std::make_unique<blink::WebKeyboardEvent>(
type, event.modifiers(), timestamp);
blink::WebKeyboardEvent* key_event =
static_cast<blink::WebKeyboardEvent*>(input_event.get());
key_event->windows_key_code = key_data->windows_key_code;
key_event->native_key_code = key_data->native_key_code;
key_event->dom_code = key_data->dom_code;
key_event->dom_key = key_data->dom_key;
key_event->is_system_key = key_data->is_system_key;
key_event->is_browser_shortcut = key_data->is_browser_shortcut;
CopyString(key_event->text, key_data->text);
CopyString(key_event->unmodified_text, key_data->unmodified_text);
} else if (blink::WebInputEvent::IsGestureEventType(type)) {
blink::mojom::GestureDataPtr gesture_data;
if (!event.ReadGestureData<blink::mojom::GestureDataPtr>(&gesture_data))
return false;
input_event = std::make_unique<blink::WebGestureEvent>(
type, event.modifiers(), timestamp, gesture_data->source_device);
blink::WebGestureEvent* gesture_event =
static_cast<blink::WebGestureEvent*>(input_event.get());
gesture_event->SetPositionInWidget(gesture_data->widget_position);
gesture_event->SetPositionInScreen(gesture_data->screen_position);
gesture_event->is_source_touch_event_set_blocking =
gesture_data->is_source_touch_event_set_blocking;
gesture_event->primary_pointer_type = gesture_data->primary_pointer_type;
gesture_event->SetSourceDevice(gesture_data->source_device);
gesture_event->unique_touch_event_id = gesture_data->unique_touch_event_id;
if (gesture_data->contact_size) {
switch (type) {
default:
break;
case blink::WebInputEvent::Type::kGestureTapDown:
gesture_event->data.tap_down.width =
gesture_data->contact_size->width();
gesture_event->data.tap_down.height =
gesture_data->contact_size->height();
break;
case blink::WebInputEvent::Type::kGestureShowPress:
gesture_event->data.show_press.width =
gesture_data->contact_size->width();
gesture_event->data.show_press.height =
gesture_data->contact_size->height();
break;
case blink::WebInputEvent::Type::kGestureTap:
case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
case blink::WebInputEvent::Type::kGestureDoubleTap:
gesture_event->data.tap.width = gesture_data->contact_size->width();
gesture_event->data.tap.height = gesture_data->contact_size->height();
break;
case blink::WebInputEvent::Type::kGestureLongPress:
case blink::WebInputEvent::Type::kGestureLongTap:
gesture_event->data.long_press.width =
gesture_data->contact_size->width();
gesture_event->data.long_press.height =
gesture_data->contact_size->height();
break;
case blink::WebInputEvent::Type::kGestureTwoFingerTap:
gesture_event->data.two_finger_tap.first_finger_width =
gesture_data->contact_size->width();
gesture_event->data.two_finger_tap.first_finger_height =
gesture_data->contact_size->height();
break;
}
}
if (gesture_data->scroll_data) {
switch (type) {
default:
break;
case blink::WebInputEvent::Type::kGestureScrollBegin:
gesture_event->data.scroll_begin.delta_x_hint =
gesture_data->scroll_data->delta_x;
gesture_event->data.scroll_begin.delta_y_hint =
gesture_data->scroll_data->delta_y;
gesture_event->data.scroll_begin.delta_hint_units =
gesture_data->scroll_data->delta_units;
gesture_event->data.scroll_begin.target_viewport =
gesture_data->scroll_data->target_viewport;
gesture_event->data.scroll_begin.inertial_phase =
gesture_data->scroll_data->inertial_phase;
gesture_event->data.scroll_begin.synthetic =
gesture_data->scroll_data->synthetic;
gesture_event->data.scroll_begin.pointer_count =
gesture_data->scroll_data->pointer_count;
gesture_event->data.scroll_begin.cursor_control =
gesture_data->scroll_data->cursor_control;
break;
case blink::WebInputEvent::Type::kGestureScrollEnd:
gesture_event->data.scroll_end.delta_units =
gesture_data->scroll_data->delta_units;
gesture_event->data.scroll_end.inertial_phase =
gesture_data->scroll_data->inertial_phase;
gesture_event->data.scroll_end.synthetic =
gesture_data->scroll_data->synthetic;
break;
case blink::WebInputEvent::Type::kGestureScrollUpdate:
gesture_event->data.scroll_update.delta_x =
gesture_data->scroll_data->delta_x;
gesture_event->data.scroll_update.delta_y =
gesture_data->scroll_data->delta_y;
gesture_event->data.scroll_update.delta_units =
gesture_data->scroll_data->delta_units;
gesture_event->data.scroll_update.inertial_phase =
gesture_data->scroll_data->inertial_phase;
if (gesture_data->scroll_data->update_details) {
gesture_event->data.scroll_update.velocity_x =
gesture_data->scroll_data->update_details->velocity_x;
gesture_event->data.scroll_update.velocity_y =
gesture_data->scroll_data->update_details->velocity_y;
}
break;
}
}
if (gesture_data->pinch_begin_data &&
type == blink::WebInputEvent::Type::kGesturePinchBegin) {
gesture_event->data.pinch_begin.needs_wheel_event =
gesture_data->pinch_begin_data->needs_wheel_event;
}
if (gesture_data->pinch_update_data &&
type == blink::WebInputEvent::Type::kGesturePinchUpdate) {
gesture_event->data.pinch_update.zoom_disabled =
gesture_data->pinch_update_data->zoom_disabled;
gesture_event->data.pinch_update.scale =
gesture_data->pinch_update_data->scale;
gesture_event->data.pinch_update.needs_wheel_event =
gesture_data->pinch_update_data->needs_wheel_event;
}
if (gesture_data->pinch_end_data &&
type == blink::WebInputEvent::Type::kGesturePinchEnd) {
gesture_event->data.pinch_end.needs_wheel_event =
gesture_data->pinch_end_data->needs_wheel_event;
}
if (gesture_data->tap_data) {
switch (type) {
default:
break;
case blink::WebInputEvent::Type::kGestureTap:
case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
case blink::WebInputEvent::Type::kGestureDoubleTap:
gesture_event->data.tap.tap_count = gesture_data->tap_data->tap_count;
gesture_event->data.tap.needs_wheel_event =
gesture_data->tap_data->needs_wheel_event;
break;
}
}
if (gesture_data->fling_data) {
switch (type) {
default:
break;
case blink::WebInputEvent::Type::kGestureFlingStart:
gesture_event->data.fling_start.velocity_x =
gesture_data->fling_data->velocity_x;
gesture_event->data.fling_start.velocity_y =
gesture_data->fling_data->velocity_y;
gesture_event->data.fling_start.target_viewport =
gesture_data->fling_data->target_viewport;
break;
case blink::WebInputEvent::Type::kGestureFlingCancel:
gesture_event->data.fling_cancel.target_viewport =
gesture_data->fling_data->target_viewport;
gesture_event->data.fling_cancel.prevent_boosting =
gesture_data->fling_data->prevent_boosting;
break;
}
}
} else if (blink::WebInputEvent::IsTouchEventType(type)) {
blink::mojom::TouchDataPtr touch_data;
if (!event.ReadTouchData<blink::mojom::TouchDataPtr>(&touch_data))
return false;
input_event = std::make_unique<blink::WebTouchEvent>(
type, event.modifiers(), timestamp);
blink::WebTouchEvent* touch_event =
static_cast<blink::WebTouchEvent*>(input_event.get());
std::vector<blink::mojom::TouchPointPtr> touches;
unsigned i;
for (i = 0; i < touch_data->touches.size() &&
i < blink::WebTouchEvent::kTouchesLengthCap;
++i) {
blink::WebTouchPoint& touch_point = touch_event->touches[i];
TouchPointPropertiesFromPointerData(touch_data->touches[i], &touch_point);
}
touch_event->touches_length = i;
touch_event->dispatch_type = touch_data->cancelable;
touch_event->moved_beyond_slop_region =
touch_data->moved_beyond_slop_region;
touch_event->hovering = touch_data->hovering;
touch_event->touch_start_or_first_touch_move =
touch_data->touch_start_or_first_move;
touch_event->unique_touch_event_id = touch_data->unique_touch_event_id;
} else if (blink::WebInputEvent::IsMouseEventType(type) ||
type == blink::WebInputEvent::Type::kMouseWheel) {
blink::mojom::PointerDataPtr pointer_data;
if (!event.ReadPointerData<blink::mojom::PointerDataPtr>(&pointer_data))
return false;
if (blink::WebInputEvent::IsMouseEventType(type)) {
input_event = std::make_unique<blink::WebMouseEvent>(
type, event.modifiers(), timestamp);
} else {
input_event = std::make_unique<blink::WebMouseWheelEvent>(
type, event.modifiers(), timestamp);
}
blink::WebMouseEvent* mouse_event =
static_cast<blink::WebMouseEvent*>(input_event.get());
MouseEventPropertiesFromPointerData(pointer_data, mouse_event);
if (pointer_data->mouse_data) {
mouse_event->click_count = pointer_data->mouse_data->click_count;
if (type == blink::WebInputEvent::Type::kMouseWheel &&
pointer_data->mouse_data->wheel_data) {
blink::WebMouseWheelEvent* wheel_event =
static_cast<blink::WebMouseWheelEvent*>(mouse_event);
blink::mojom::WheelDataPtr& wheel_data =
pointer_data->mouse_data->wheel_data;
wheel_event->delta_x = wheel_data->delta_x;
wheel_event->delta_y = wheel_data->delta_y;
wheel_event->wheel_ticks_x = wheel_data->wheel_ticks_x;
wheel_event->wheel_ticks_y = wheel_data->wheel_ticks_y;
wheel_event->acceleration_ratio_x = wheel_data->acceleration_ratio_x;
wheel_event->acceleration_ratio_y = wheel_data->acceleration_ratio_y;
wheel_event->phase =
static_cast<blink::WebMouseWheelEvent::Phase>(wheel_data->phase);
wheel_event->momentum_phase =
static_cast<blink::WebMouseWheelEvent::Phase>(
wheel_data->momentum_phase);
wheel_event->dispatch_type = wheel_data->cancelable;
wheel_event->event_action =
static_cast<blink::WebMouseWheelEvent::EventAction>(
wheel_data->event_action);
wheel_event->delta_units =
static_cast<ui::ScrollGranularity>(wheel_data->delta_units);
}
}
} else {
return false;
}
ui::LatencyInfo latency_info;
if (!event.ReadLatency(&latency_info))
return false;
*out = std::make_unique<blink::WebCoalescedInputEvent>(std::move(input_event),
latency_info);
return true;
}
// static
blink::mojom::KeyDataPtr
StructTraits<blink::mojom::EventDataView,
std::unique_ptr<blink::WebCoalescedInputEvent>>::
key_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
if (!blink::WebInputEvent::IsKeyboardEventType(event->Event().GetType()))
return nullptr;
const blink::WebKeyboardEvent* key_event =
static_cast<const blink::WebKeyboardEvent*>(event->EventPointer());
return blink::mojom::KeyData::New(
key_event->dom_key, key_event->dom_code, key_event->windows_key_code,
key_event->native_key_code, key_event->is_system_key,
key_event->is_browser_shortcut, key_event->text,
key_event->unmodified_text);
}
// static
blink::mojom::PointerDataPtr
StructTraits<blink::mojom::EventDataView,
std::unique_ptr<blink::WebCoalescedInputEvent>>::
pointer_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
bool is_wheel_event =
event->Event().GetType() == blink::WebInputEvent::Type::kMouseWheel;
if (!blink::WebInputEvent::IsMouseEventType(event->Event().GetType()) &&
!is_wheel_event) {
return nullptr;
}
const blink::WebMouseEvent* mouse_event =
static_cast<const blink::WebMouseEvent*>(event->EventPointer());
blink::mojom::WheelDataPtr wheel_data;
if (is_wheel_event) {
const blink::WebMouseWheelEvent* wheel_event =
static_cast<const blink::WebMouseWheelEvent*>(mouse_event);
wheel_data = blink::mojom::WheelData::New(
wheel_event->delta_x, wheel_event->delta_y, wheel_event->wheel_ticks_x,
wheel_event->wheel_ticks_y, wheel_event->acceleration_ratio_x,
wheel_event->acceleration_ratio_y, wheel_event->phase,
wheel_event->momentum_phase, wheel_event->dispatch_type,
static_cast<uint8_t>(wheel_event->event_action),
static_cast<uint8_t>(wheel_event->delta_units));
}
return PointerDataFromPointerProperties(
*mouse_event, blink::mojom::MouseData::New(mouse_event->click_count,
std::move(wheel_data)));
}
// static
blink::mojom::GestureDataPtr
StructTraits<blink::mojom::EventDataView,
std::unique_ptr<blink::WebCoalescedInputEvent>>::
gesture_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
if (!blink::WebInputEvent::IsGestureEventType(event->Event().GetType()))
return nullptr;
const blink::WebGestureEvent* gesture_event =
static_cast<const blink::WebGestureEvent*>(event->EventPointer());
auto gesture_data = blink::mojom::GestureData::New();
gesture_data->screen_position = gesture_event->PositionInScreen();
gesture_data->widget_position = gesture_event->PositionInWidget();
gesture_data->source_device = gesture_event->SourceDevice();
gesture_data->is_source_touch_event_set_blocking =
gesture_event->is_source_touch_event_set_blocking;
gesture_data->primary_pointer_type = gesture_event->primary_pointer_type;
gesture_data->unique_touch_event_id = gesture_event->unique_touch_event_id;
switch (gesture_event->GetType()) {
default:
break;
case blink::WebInputEvent::Type::kGestureTapDown:
gesture_data->contact_size =
gfx::Size(gesture_event->data.tap_down.width,
gesture_event->data.tap_down.height);
break;
case blink::WebInputEvent::Type::kGestureShowPress:
gesture_data->contact_size =
gfx::Size(gesture_event->data.show_press.width,
gesture_event->data.show_press.height);
break;
case blink::WebInputEvent::Type::kGestureTap:
case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
case blink::WebInputEvent::Type::kGestureDoubleTap:
gesture_data->contact_size = gfx::Size(gesture_event->data.tap.width,
gesture_event->data.tap.height);
gesture_data->tap_data =
blink::mojom::TapData::New(gesture_event->data.tap.tap_count,
gesture_event->data.tap.needs_wheel_event);
break;
case blink::WebInputEvent::Type::kGestureLongPress:
case blink::WebInputEvent::Type::kGestureLongTap:
gesture_data->contact_size =
gfx::Size(gesture_event->data.long_press.width,
gesture_event->data.long_press.height);
break;
case blink::WebInputEvent::Type::kGestureTwoFingerTap:
gesture_data->contact_size =
gfx::Size(gesture_event->data.two_finger_tap.first_finger_width,
gesture_event->data.two_finger_tap.first_finger_height);
break;
case blink::WebInputEvent::Type::kGestureScrollBegin:
gesture_data->scroll_data = blink::mojom::ScrollData::New(
gesture_event->data.scroll_begin.delta_x_hint,
gesture_event->data.scroll_begin.delta_y_hint,
gesture_event->data.scroll_begin.delta_hint_units,
gesture_event->data.scroll_begin.target_viewport,
gesture_event->data.scroll_begin.inertial_phase,
gesture_event->data.scroll_begin.synthetic,
gesture_event->data.scroll_begin.pointer_count,
gesture_event->data.scroll_begin.cursor_control, nullptr);
break;
case blink::WebInputEvent::Type::kGestureScrollEnd:
gesture_data->scroll_data = blink::mojom::ScrollData::New(
0, 0, gesture_event->data.scroll_end.delta_units, false,
gesture_event->data.scroll_end.inertial_phase,
gesture_event->data.scroll_end.synthetic, 0, false, nullptr);
break;
case blink::WebInputEvent::Type::kGestureScrollUpdate:
gesture_data->scroll_data = blink::mojom::ScrollData::New(
gesture_event->data.scroll_update.delta_x,
gesture_event->data.scroll_update.delta_y,
gesture_event->data.scroll_update.delta_units, false,
gesture_event->data.scroll_update.inertial_phase, false, 0, false,
blink::mojom::ScrollUpdate::New(
gesture_event->data.scroll_update.velocity_x,
gesture_event->data.scroll_update.velocity_y));
break;
case blink::WebInputEvent::Type::kGestureFlingStart:
gesture_data->fling_data = blink::mojom::FlingData::New(
gesture_event->data.fling_start.velocity_x,
gesture_event->data.fling_start.velocity_y,
gesture_event->data.fling_start.target_viewport, false);
break;
case blink::WebInputEvent::Type::kGestureFlingCancel:
gesture_data->fling_data = blink::mojom::FlingData::New(
0, 0, gesture_event->data.fling_cancel.target_viewport,
gesture_event->data.fling_cancel.prevent_boosting);
break;
case blink::WebInputEvent::Type::kGesturePinchBegin:
gesture_data->pinch_begin_data = blink::mojom::PinchBeginData::New(
gesture_event->data.pinch_begin.needs_wheel_event);
break;
case blink::WebInputEvent::Type::kGesturePinchUpdate:
gesture_data->pinch_update_data = blink::mojom::PinchUpdateData::New(
gesture_event->data.pinch_update.scale,
gesture_event->data.pinch_update.zoom_disabled,
gesture_event->data.pinch_update.needs_wheel_event);
break;
case blink::WebInputEvent::Type::kGesturePinchEnd:
gesture_data->pinch_end_data = blink::mojom::PinchEndData::New(
gesture_event->data.pinch_end.needs_wheel_event);
break;
}
return gesture_data;
}
// static
blink::mojom::TouchDataPtr
StructTraits<blink::mojom::EventDataView,
std::unique_ptr<blink::WebCoalescedInputEvent>>::
touch_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
if (!blink::WebInputEvent::IsTouchEventType(event->Event().GetType()))
return nullptr;
const blink::WebTouchEvent* touch_event =
static_cast<const blink::WebTouchEvent*>(event->EventPointer());
auto touch_data = blink::mojom::TouchData::New(
touch_event->dispatch_type, touch_event->moved_beyond_slop_region,
touch_event->touch_start_or_first_touch_move, touch_event->hovering,
touch_event->unique_touch_event_id,
std::vector<blink::mojom::TouchPointPtr>());
for (unsigned i = 0; i < touch_event->touches_length; ++i) {
blink::mojom::PointerDataPtr pointer_data =
PointerDataFromPointerProperties(touch_event->touches[i], nullptr);
touch_data->touches.emplace_back(blink::mojom::TouchPoint::New(
touch_event->touches[i].state, touch_event->touches[i].radius_x,
touch_event->touches[i].radius_y,
touch_event->touches[i].rotation_angle, std::move(pointer_data)));
}
return touch_data;
}
} // namespace mojo