OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/common/input/event_with_latency_info.h" |
| 6 |
| 7 #include <bitset> |
| 8 #include <limits> |
| 9 |
| 10 using blink::WebGestureEvent; |
| 11 using blink::WebInputEvent; |
| 12 using blink::WebKeyboardEvent; |
| 13 using blink::WebMouseEvent; |
| 14 using blink::WebMouseWheelEvent; |
| 15 using blink::WebTouchEvent; |
| 16 using std::numeric_limits; |
| 17 |
| 18 namespace content { |
| 19 namespace { |
| 20 |
| 21 const int kInvalidTouchIndex = -1; |
| 22 |
| 23 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) { |
| 24 return accelerated_delta * acceleration_ratio; |
| 25 } |
| 26 |
| 27 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { |
| 28 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f) |
| 29 return 1.f; |
| 30 return unaccelerated_delta / accelerated_delta; |
| 31 } |
| 32 |
| 33 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|. |
| 34 int GetIndexOfTouchID(const WebTouchEvent& event, int id) { |
| 35 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 36 if (event.touches[i].id == id) |
| 37 return i; |
| 38 } |
| 39 return kInvalidTouchIndex; |
| 40 } |
| 41 |
| 42 WebInputEvent::DispatchType MergeDispatchTypes( |
| 43 WebInputEvent::DispatchType type_1, |
| 44 WebInputEvent::DispatchType type_2) { |
| 45 static_assert(WebInputEvent::DispatchType::Blocking < |
| 46 WebInputEvent::DispatchType::EventNonBlocking, |
| 47 "Enum not ordered correctly"); |
| 48 static_assert(WebInputEvent::DispatchType::EventNonBlocking < |
| 49 WebInputEvent::DispatchType::ListenersNonBlockingPassive, |
| 50 "Enum not ordered correctly"); |
| 51 static_assert( |
| 52 WebInputEvent::DispatchType::ListenersNonBlockingPassive < |
| 53 WebInputEvent::DispatchType::ListenersForcedNonBlockingPassive, |
| 54 "Enum not ordered correctly"); |
| 55 return static_cast<WebInputEvent::DispatchType>( |
| 56 std::min(static_cast<int>(type_1), static_cast<int>(type_2))); |
| 57 } |
| 58 |
| 59 } // namespace |
| 60 |
| 61 namespace internal { |
| 62 |
| 63 bool CanCoalesce(const WebMouseEvent& event_to_coalesce, |
| 64 const WebMouseEvent& event) { |
| 65 return event.type == event_to_coalesce.type && |
| 66 event.type == WebInputEvent::MouseMove; |
| 67 } |
| 68 |
| 69 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) { |
| 70 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 71 // Accumulate movement deltas. |
| 72 int x = event->movementX; |
| 73 int y = event->movementY; |
| 74 *event = event_to_coalesce; |
| 75 event->movementX += x; |
| 76 event->movementY += y; |
| 77 } |
| 78 |
| 79 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce, |
| 80 const WebMouseWheelEvent& event) { |
| 81 return event.modifiers == event_to_coalesce.modifiers && |
| 82 event.scrollByPage == event_to_coalesce.scrollByPage && |
| 83 event.phase == event_to_coalesce.phase && |
| 84 event.momentumPhase == event_to_coalesce.momentumPhase && |
| 85 event.hasPreciseScrollingDeltas == |
| 86 event_to_coalesce.hasPreciseScrollingDeltas; |
| 87 } |
| 88 |
| 89 void Coalesce(const WebMouseWheelEvent& event_to_coalesce, |
| 90 WebMouseWheelEvent* event) { |
| 91 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 92 float unaccelerated_x = |
| 93 GetUnacceleratedDelta(event->deltaX, event->accelerationRatioX) + |
| 94 GetUnacceleratedDelta(event_to_coalesce.deltaX, |
| 95 event_to_coalesce.accelerationRatioX); |
| 96 float unaccelerated_y = |
| 97 GetUnacceleratedDelta(event->deltaY, event->accelerationRatioY) + |
| 98 GetUnacceleratedDelta(event_to_coalesce.deltaY, |
| 99 event_to_coalesce.accelerationRatioY); |
| 100 event->deltaX += event_to_coalesce.deltaX; |
| 101 event->deltaY += event_to_coalesce.deltaY; |
| 102 event->wheelTicksX += event_to_coalesce.wheelTicksX; |
| 103 event->wheelTicksY += event_to_coalesce.wheelTicksY; |
| 104 event->accelerationRatioX = |
| 105 GetAccelerationRatio(event->deltaX, unaccelerated_x); |
| 106 event->accelerationRatioY = |
| 107 GetAccelerationRatio(event->deltaY, unaccelerated_y); |
| 108 } |
| 109 |
| 110 bool CanCoalesce(const WebTouchEvent& event_to_coalesce, |
| 111 const WebTouchEvent& event) { |
| 112 if (event.type != event_to_coalesce.type || |
| 113 event.type != WebInputEvent::TouchMove || |
| 114 event.modifiers != event_to_coalesce.modifiers || |
| 115 event.touchesLength != event_to_coalesce.touchesLength || |
| 116 event.touchesLength > WebTouchEvent::touchesLengthCap) |
| 117 return false; |
| 118 |
| 119 static_assert(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U, |
| 120 "suboptimal touchesLengthCap size"); |
| 121 // Ensure that we have a 1-to-1 mapping of pointer ids between touches. |
| 122 std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches( |
| 123 (1 << event.touchesLength) - 1); |
| 124 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) { |
| 125 int event_touch_index = |
| 126 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id); |
| 127 if (event_touch_index == kInvalidTouchIndex) |
| 128 return false; |
| 129 if (!unmatched_event_touches[event_touch_index]) |
| 130 return false; |
| 131 unmatched_event_touches[event_touch_index] = false; |
| 132 } |
| 133 return unmatched_event_touches.none(); |
| 134 } |
| 135 |
| 136 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) { |
| 137 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 138 // The WebTouchPoints include absolute position information. So it is |
| 139 // sufficient to simply replace the previous event with the new event-> |
| 140 // However, it is necessary to make sure that all the points have the |
| 141 // correct state, i.e. the touch-points that moved in the last event, but |
| 142 // didn't change in the current event, will have Stationary state. It is |
| 143 // necessary to change them back to Moved state. |
| 144 WebTouchEvent old_event = *event; |
| 145 *event = event_to_coalesce; |
| 146 for (unsigned i = 0; i < event->touchesLength; ++i) { |
| 147 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id); |
| 148 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved) |
| 149 event->touches[i].state = blink::WebTouchPoint::StateMoved; |
| 150 } |
| 151 event->movedBeyondSlopRegion |= old_event.movedBeyondSlopRegion; |
| 152 event->dispatchType = MergeDispatchTypes(old_event.dispatchType, |
| 153 event_to_coalesce.dispatchType); |
| 154 } |
| 155 |
| 156 bool CanCoalesce(const WebGestureEvent& event_to_coalesce, |
| 157 const WebGestureEvent& event) { |
| 158 if (event.type != event_to_coalesce.type || |
| 159 event.sourceDevice != event_to_coalesce.sourceDevice || |
| 160 event.modifiers != event_to_coalesce.modifiers) |
| 161 return false; |
| 162 |
| 163 if (event.type == WebInputEvent::GestureScrollUpdate) |
| 164 return true; |
| 165 |
| 166 // GesturePinchUpdate scales can be combined only if they share a focal point, |
| 167 // e.g., with double-tap drag zoom. |
| 168 if (event.type == WebInputEvent::GesturePinchUpdate && |
| 169 event.x == event_to_coalesce.x && event.y == event_to_coalesce.y) |
| 170 return true; |
| 171 |
| 172 return false; |
| 173 } |
| 174 |
| 175 void Coalesce(const WebGestureEvent& event_to_coalesce, |
| 176 WebGestureEvent* event) { |
| 177 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 178 if (event->type == WebInputEvent::GestureScrollUpdate) { |
| 179 event->data.scrollUpdate.deltaX += |
| 180 event_to_coalesce.data.scrollUpdate.deltaX; |
| 181 event->data.scrollUpdate.deltaY += |
| 182 event_to_coalesce.data.scrollUpdate.deltaY; |
| 183 DCHECK_EQ( |
| 184 event->data.scrollUpdate.previousUpdateInSequencePrevented, |
| 185 event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented); |
| 186 } else if (event->type == WebInputEvent::GesturePinchUpdate) { |
| 187 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale; |
| 188 // Ensure the scale remains bounded above 0 and below Infinity so that |
| 189 // we can reliably perform operations like log on the values. |
| 190 if (event->data.pinchUpdate.scale < numeric_limits<float>::min()) |
| 191 event->data.pinchUpdate.scale = numeric_limits<float>::min(); |
| 192 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max()) |
| 193 event->data.pinchUpdate.scale = numeric_limits<float>::max(); |
| 194 } |
| 195 } |
| 196 |
| 197 } // namespace internal |
| 198 } // namespace content |
OLD | NEW |