| Index: ui/events/blink/blink_event_util.cc
|
| diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc
|
| index 360ca65c17de6a56d83d1568845873cb11930205..5148bf1600513a3e43c5be21b0fc44c54f5e3cd7 100644
|
| --- a/ui/events/blink/blink_event_util.cc
|
| +++ b/ui/events/blink/blink_event_util.cc
|
| @@ -10,7 +10,9 @@
|
| #include <stddef.h>
|
|
|
| #include <algorithm>
|
| +#include <bitset>
|
| #include <cmath>
|
| +#include <limits>
|
|
|
| #include "base/time/time.h"
|
| #include "build/build_config.h"
|
| @@ -27,13 +29,18 @@
|
|
|
| using blink::WebGestureEvent;
|
| using blink::WebInputEvent;
|
| +using blink::WebMouseEvent;
|
| +using blink::WebMouseWheelEvent;
|
| using blink::WebPointerProperties;
|
| using blink::WebTouchEvent;
|
| using blink::WebTouchPoint;
|
| +using std::numeric_limits;
|
|
|
| namespace ui {
|
| namespace {
|
|
|
| +const int kInvalidTouchIndex = -1;
|
| +
|
| WebInputEvent::Type ToWebTouchEventType(MotionEvent::Action action) {
|
| switch (action) {
|
| case MotionEvent::ACTION_DOWN:
|
| @@ -195,8 +202,243 @@ WebTouchPoint CreateWebTouchPoint(const MotionEvent& event,
|
| return touch;
|
| }
|
|
|
| +float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
|
| + return accelerated_delta * acceleration_ratio;
|
| +}
|
| +
|
| +float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
|
| + if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
|
| + return 1.f;
|
| + return unaccelerated_delta / accelerated_delta;
|
| +}
|
| +
|
| +// Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|.
|
| +int GetIndexOfTouchID(const WebTouchEvent& event, int id) {
|
| + for (unsigned i = 0; i < event.touchesLength; ++i) {
|
| + if (event.touches[i].id == id)
|
| + return i;
|
| + }
|
| + return kInvalidTouchIndex;
|
| +}
|
| +
|
| +WebInputEvent::DispatchType MergeDispatchTypes(
|
| + WebInputEvent::DispatchType type_1,
|
| + WebInputEvent::DispatchType type_2) {
|
| + static_assert(WebInputEvent::DispatchType::Blocking <
|
| + WebInputEvent::DispatchType::EventNonBlocking,
|
| + "Enum not ordered correctly");
|
| + static_assert(WebInputEvent::DispatchType::EventNonBlocking <
|
| + WebInputEvent::DispatchType::ListenersNonBlockingPassive,
|
| + "Enum not ordered correctly");
|
| + static_assert(
|
| + WebInputEvent::DispatchType::ListenersNonBlockingPassive <
|
| + WebInputEvent::DispatchType::ListenersForcedNonBlockingDueToFling,
|
| + "Enum not ordered correctly");
|
| + return static_cast<WebInputEvent::DispatchType>(
|
| + std::min(static_cast<int>(type_1), static_cast<int>(type_2)));
|
| +}
|
| +
|
| +bool CanCoalesce(const WebMouseEvent& event_to_coalesce,
|
| + const WebMouseEvent& event) {
|
| + return event.type == event_to_coalesce.type &&
|
| + event.type == WebInputEvent::MouseMove;
|
| +}
|
| +
|
| +void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) {
|
| + DCHECK(CanCoalesce(event_to_coalesce, *event));
|
| + // Accumulate movement deltas.
|
| + int x = event->movementX;
|
| + int y = event->movementY;
|
| + *event = event_to_coalesce;
|
| + event->movementX += x;
|
| + event->movementY += y;
|
| +}
|
| +
|
| +bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
|
| + const WebMouseWheelEvent& event) {
|
| + return event.modifiers == event_to_coalesce.modifiers &&
|
| + event.scrollByPage == event_to_coalesce.scrollByPage &&
|
| + event.phase == event_to_coalesce.phase &&
|
| + event.momentumPhase == event_to_coalesce.momentumPhase &&
|
| + event.hasPreciseScrollingDeltas ==
|
| + event_to_coalesce.hasPreciseScrollingDeltas;
|
| +}
|
| +
|
| +void Coalesce(const WebMouseWheelEvent& event_to_coalesce,
|
| + WebMouseWheelEvent* event) {
|
| + DCHECK(CanCoalesce(event_to_coalesce, *event));
|
| + float unaccelerated_x =
|
| + GetUnacceleratedDelta(event->deltaX, event->accelerationRatioX) +
|
| + GetUnacceleratedDelta(event_to_coalesce.deltaX,
|
| + event_to_coalesce.accelerationRatioX);
|
| + float unaccelerated_y =
|
| + GetUnacceleratedDelta(event->deltaY, event->accelerationRatioY) +
|
| + GetUnacceleratedDelta(event_to_coalesce.deltaY,
|
| + event_to_coalesce.accelerationRatioY);
|
| + float old_deltaX = event->deltaX;
|
| + float old_deltaY = event->deltaY;
|
| + float old_wheelTicksX = event->wheelTicksX;
|
| + float old_wheelTicksY = event->wheelTicksY;
|
| + float old_movementX = event->movementX;
|
| + float old_movementY = event->movementY;
|
| + *event = event_to_coalesce;
|
| + event->deltaX += old_deltaX;
|
| + event->deltaY += old_deltaY;
|
| + event->wheelTicksX += old_wheelTicksX;
|
| + event->wheelTicksY += old_wheelTicksY;
|
| + event->movementX += old_movementX;
|
| + event->movementY += old_movementY;
|
| + event->accelerationRatioX =
|
| + GetAccelerationRatio(event->deltaX, unaccelerated_x);
|
| + event->accelerationRatioY =
|
| + GetAccelerationRatio(event->deltaY, unaccelerated_y);
|
| +}
|
| +
|
| +bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
|
| + const WebTouchEvent& event) {
|
| + if (event.type != event_to_coalesce.type ||
|
| + event.type != WebInputEvent::TouchMove ||
|
| + event.modifiers != event_to_coalesce.modifiers ||
|
| + event.touchesLength != event_to_coalesce.touchesLength ||
|
| + event.touchesLength > WebTouchEvent::kTouchesLengthCap)
|
| + return false;
|
| +
|
| + static_assert(WebTouchEvent::kTouchesLengthCap <= sizeof(int32_t) * 8U,
|
| + "suboptimal kTouchesLengthCap size");
|
| + // Ensure that we have a 1-to-1 mapping of pointer ids between touches.
|
| + std::bitset<WebTouchEvent::kTouchesLengthCap> unmatched_event_touches(
|
| + (1 << event.touchesLength) - 1);
|
| + for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) {
|
| + int event_touch_index =
|
| + GetIndexOfTouchID(event, event_to_coalesce.touches[i].id);
|
| + if (event_touch_index == kInvalidTouchIndex)
|
| + return false;
|
| + if (!unmatched_event_touches[event_touch_index])
|
| + return false;
|
| + unmatched_event_touches[event_touch_index] = false;
|
| + }
|
| + return unmatched_event_touches.none();
|
| +}
|
| +
|
| +void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
|
| + DCHECK(CanCoalesce(event_to_coalesce, *event));
|
| + // The WebTouchPoints include absolute position information. So it is
|
| + // sufficient to simply replace the previous event with the new event->
|
| + // However, it is necessary to make sure that all the points have the
|
| + // correct state, i.e. the touch-points that moved in the last event, but
|
| + // didn't change in the current event, will have Stationary state. It is
|
| + // necessary to change them back to Moved state.
|
| + WebTouchEvent old_event = *event;
|
| + *event = event_to_coalesce;
|
| + for (unsigned i = 0; i < event->touchesLength; ++i) {
|
| + int i_old = GetIndexOfTouchID(old_event, event->touches[i].id);
|
| + if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved)
|
| + event->touches[i].state = blink::WebTouchPoint::StateMoved;
|
| + }
|
| + event->movedBeyondSlopRegion |= old_event.movedBeyondSlopRegion;
|
| + event->dispatchType = MergeDispatchTypes(old_event.dispatchType,
|
| + event_to_coalesce.dispatchType);
|
| +}
|
| +
|
| +bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
|
| + const WebGestureEvent& event) {
|
| + if (event.type != event_to_coalesce.type ||
|
| + event.sourceDevice != event_to_coalesce.sourceDevice ||
|
| + event.modifiers != event_to_coalesce.modifiers)
|
| + return false;
|
| +
|
| + if (event.type == WebInputEvent::GestureScrollUpdate)
|
| + return true;
|
| +
|
| + // GesturePinchUpdate scales can be combined only if they share a focal point,
|
| + // e.g., with double-tap drag zoom.
|
| + if (event.type == WebInputEvent::GesturePinchUpdate &&
|
| + event.x == event_to_coalesce.x && event.y == event_to_coalesce.y)
|
| + return true;
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void Coalesce(const WebGestureEvent& event_to_coalesce,
|
| + WebGestureEvent* event) {
|
| + DCHECK(CanCoalesce(event_to_coalesce, *event));
|
| + if (event->type == WebInputEvent::GestureScrollUpdate) {
|
| + event->data.scrollUpdate.deltaX +=
|
| + event_to_coalesce.data.scrollUpdate.deltaX;
|
| + event->data.scrollUpdate.deltaY +=
|
| + event_to_coalesce.data.scrollUpdate.deltaY;
|
| + DCHECK_EQ(
|
| + event->data.scrollUpdate.previousUpdateInSequencePrevented,
|
| + event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented);
|
| + } else if (event->type == WebInputEvent::GesturePinchUpdate) {
|
| + event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale;
|
| + // Ensure the scale remains bounded above 0 and below Infinity so that
|
| + // we can reliably perform operations like log on the values.
|
| + if (event->data.pinchUpdate.scale < numeric_limits<float>::min())
|
| + event->data.pinchUpdate.scale = numeric_limits<float>::min();
|
| + else if (event->data.pinchUpdate.scale > numeric_limits<float>::max())
|
| + event->data.pinchUpdate.scale = numeric_limits<float>::max();
|
| + }
|
| +}
|
| +
|
| } // namespace
|
|
|
| +bool CanCoalesce(const blink::WebInputEvent& event_to_coalesce,
|
| + const blink::WebInputEvent& event) {
|
| + if (blink::WebInputEvent::isGestureEventType(event_to_coalesce.type) &&
|
| + blink::WebInputEvent::isGestureEventType(event.type)) {
|
| + return CanCoalesce(
|
| + static_cast<const blink::WebGestureEvent&>(event_to_coalesce),
|
| + static_cast<const blink::WebGestureEvent&>(event));
|
| + }
|
| + if (blink::WebInputEvent::isMouseEventType(event_to_coalesce.type) &&
|
| + blink::WebInputEvent::isMouseEventType(event.type)) {
|
| + return CanCoalesce(
|
| + static_cast<const blink::WebMouseEvent&>(event_to_coalesce),
|
| + static_cast<const blink::WebMouseEvent&>(event));
|
| + }
|
| + if (blink::WebInputEvent::isTouchEventType(event_to_coalesce.type) &&
|
| + blink::WebInputEvent::isTouchEventType(event.type)) {
|
| + return CanCoalesce(
|
| + static_cast<const blink::WebTouchEvent&>(event_to_coalesce),
|
| + static_cast<const blink::WebTouchEvent&>(event));
|
| + }
|
| + if (event_to_coalesce.type == blink::WebInputEvent::MouseWheel &&
|
| + event.type == blink::WebInputEvent::MouseWheel) {
|
| + return CanCoalesce(
|
| + static_cast<const blink::WebMouseWheelEvent&>(event_to_coalesce),
|
| + static_cast<const blink::WebMouseWheelEvent&>(event));
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void Coalesce(const blink::WebInputEvent& event_to_coalesce,
|
| + blink::WebInputEvent* event) {
|
| + if (blink::WebInputEvent::isGestureEventType(event_to_coalesce.type) &&
|
| + blink::WebInputEvent::isGestureEventType(event->type)) {
|
| + Coalesce(static_cast<const blink::WebGestureEvent&>(event_to_coalesce),
|
| + static_cast<blink::WebGestureEvent*>(event));
|
| + return;
|
| + }
|
| + if (blink::WebInputEvent::isMouseEventType(event_to_coalesce.type) &&
|
| + blink::WebInputEvent::isMouseEventType(event->type)) {
|
| + Coalesce(static_cast<const blink::WebMouseEvent&>(event_to_coalesce),
|
| + static_cast<blink::WebMouseEvent*>(event));
|
| + return;
|
| + }
|
| + if (blink::WebInputEvent::isTouchEventType(event_to_coalesce.type) &&
|
| + blink::WebInputEvent::isTouchEventType(event->type)) {
|
| + Coalesce(static_cast<const blink::WebTouchEvent&>(event_to_coalesce),
|
| + static_cast<blink::WebTouchEvent*>(event));
|
| + return;
|
| + }
|
| + if (event_to_coalesce.type == blink::WebInputEvent::MouseWheel &&
|
| + event->type == blink::WebInputEvent::MouseWheel) {
|
| + Coalesce(static_cast<const blink::WebMouseWheelEvent&>(event_to_coalesce),
|
| + static_cast<blink::WebMouseWheelEvent*>(event));
|
| + }
|
| +}
|
| +
|
| blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
|
| const MotionEvent& event,
|
| bool moved_beyond_slop_region) {
|
| @@ -616,4 +858,28 @@ blink::WebInputEvent::Modifiers DomCodeToWebInputEventModifiers(DomCode code) {
|
| return static_cast<blink::WebInputEvent::Modifiers>(0);
|
| }
|
|
|
| +bool IsGestureScollOrPinch(WebInputEvent::Type type) {
|
| + switch (type) {
|
| + case blink::WebGestureEvent::GestureScrollBegin:
|
| + case blink::WebGestureEvent::GestureScrollUpdate:
|
| + case blink::WebGestureEvent::GestureScrollEnd:
|
| + case blink::WebGestureEvent::GesturePinchBegin:
|
| + case blink::WebGestureEvent::GesturePinchUpdate:
|
| + case blink::WebGestureEvent::GesturePinchEnd:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +bool IsContinuousGestureEvent(WebInputEvent::Type type) {
|
| + switch (type) {
|
| + case blink::WebGestureEvent::GestureScrollUpdate:
|
| + case blink::WebGestureEvent::GesturePinchUpdate:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| } // namespace ui
|
|
|