| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/common/input/event_with_latency_info.h" | 5 #include "content/common/input/event_with_latency_info.h" |
| 6 | 6 |
| 7 #include <bitset> | |
| 8 #include <limits> | |
| 9 | |
| 10 using blink::WebGestureEvent; | |
| 11 using blink::WebInputEvent; | 7 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 | 8 |
| 18 namespace content { | 9 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::ListenersForcedNonBlockingDueToFling, | |
| 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 float old_deltaX = event->deltaX; | |
| 101 float old_deltaY = event->deltaY; | |
| 102 float old_wheelTicksX = event->wheelTicksX; | |
| 103 float old_wheelTicksY = event->wheelTicksY; | |
| 104 float old_movementX = event->movementX; | |
| 105 float old_movementY = event->movementY; | |
| 106 *event = event_to_coalesce; | |
| 107 event->deltaX += old_deltaX; | |
| 108 event->deltaY += old_deltaY; | |
| 109 event->wheelTicksX += old_wheelTicksX; | |
| 110 event->wheelTicksY += old_wheelTicksY; | |
| 111 event->movementX += old_movementX; | |
| 112 event->movementY += old_movementY; | |
| 113 event->accelerationRatioX = | |
| 114 GetAccelerationRatio(event->deltaX, unaccelerated_x); | |
| 115 event->accelerationRatioY = | |
| 116 GetAccelerationRatio(event->deltaY, unaccelerated_y); | |
| 117 } | |
| 118 | |
| 119 bool CanCoalesce(const WebTouchEvent& event_to_coalesce, | |
| 120 const WebTouchEvent& event) { | |
| 121 if (event.type != event_to_coalesce.type || | |
| 122 event.type != WebInputEvent::TouchMove || | |
| 123 event.modifiers != event_to_coalesce.modifiers || | |
| 124 event.touchesLength != event_to_coalesce.touchesLength || | |
| 125 event.touchesLength > WebTouchEvent::kTouchesLengthCap) | |
| 126 return false; | |
| 127 | |
| 128 static_assert(WebTouchEvent::kTouchesLengthCap <= sizeof(int32_t) * 8U, | |
| 129 "suboptimal kTouchesLengthCap size"); | |
| 130 // Ensure that we have a 1-to-1 mapping of pointer ids between touches. | |
| 131 std::bitset<WebTouchEvent::kTouchesLengthCap> unmatched_event_touches( | |
| 132 (1 << event.touchesLength) - 1); | |
| 133 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) { | |
| 134 int event_touch_index = | |
| 135 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id); | |
| 136 if (event_touch_index == kInvalidTouchIndex) | |
| 137 return false; | |
| 138 if (!unmatched_event_touches[event_touch_index]) | |
| 139 return false; | |
| 140 unmatched_event_touches[event_touch_index] = false; | |
| 141 } | |
| 142 return unmatched_event_touches.none(); | |
| 143 } | |
| 144 | |
| 145 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) { | |
| 146 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 147 // The WebTouchPoints include absolute position information. So it is | |
| 148 // sufficient to simply replace the previous event with the new event-> | |
| 149 // However, it is necessary to make sure that all the points have the | |
| 150 // correct state, i.e. the touch-points that moved in the last event, but | |
| 151 // didn't change in the current event, will have Stationary state. It is | |
| 152 // necessary to change them back to Moved state. | |
| 153 WebTouchEvent old_event = *event; | |
| 154 *event = event_to_coalesce; | |
| 155 for (unsigned i = 0; i < event->touchesLength; ++i) { | |
| 156 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id); | |
| 157 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved) | |
| 158 event->touches[i].state = blink::WebTouchPoint::StateMoved; | |
| 159 } | |
| 160 event->movedBeyondSlopRegion |= old_event.movedBeyondSlopRegion; | |
| 161 event->dispatchType = MergeDispatchTypes(old_event.dispatchType, | |
| 162 event_to_coalesce.dispatchType); | |
| 163 } | |
| 164 | |
| 165 bool CanCoalesce(const WebGestureEvent& event_to_coalesce, | |
| 166 const WebGestureEvent& event) { | |
| 167 if (event.type != event_to_coalesce.type || | |
| 168 event.sourceDevice != event_to_coalesce.sourceDevice || | |
| 169 event.modifiers != event_to_coalesce.modifiers) | |
| 170 return false; | |
| 171 | |
| 172 if (event.type == WebInputEvent::GestureScrollUpdate) | |
| 173 return true; | |
| 174 | |
| 175 // GesturePinchUpdate scales can be combined only if they share a focal point, | |
| 176 // e.g., with double-tap drag zoom. | |
| 177 if (event.type == WebInputEvent::GesturePinchUpdate && | |
| 178 event.x == event_to_coalesce.x && event.y == event_to_coalesce.y) | |
| 179 return true; | |
| 180 | |
| 181 return false; | |
| 182 } | |
| 183 | |
| 184 void Coalesce(const WebGestureEvent& event_to_coalesce, | |
| 185 WebGestureEvent* event) { | |
| 186 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 187 if (event->type == WebInputEvent::GestureScrollUpdate) { | |
| 188 event->data.scrollUpdate.deltaX += | |
| 189 event_to_coalesce.data.scrollUpdate.deltaX; | |
| 190 event->data.scrollUpdate.deltaY += | |
| 191 event_to_coalesce.data.scrollUpdate.deltaY; | |
| 192 DCHECK_EQ( | |
| 193 event->data.scrollUpdate.previousUpdateInSequencePrevented, | |
| 194 event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented); | |
| 195 } else if (event->type == WebInputEvent::GesturePinchUpdate) { | |
| 196 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale; | |
| 197 // Ensure the scale remains bounded above 0 and below Infinity so that | |
| 198 // we can reliably perform operations like log on the values. | |
| 199 if (event->data.pinchUpdate.scale < numeric_limits<float>::min()) | |
| 200 event->data.pinchUpdate.scale = numeric_limits<float>::min(); | |
| 201 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max()) | |
| 202 event->data.pinchUpdate.scale = numeric_limits<float>::max(); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 bool CanCoalesce(const blink::WebInputEvent& event_to_coalesce, | |
| 207 const blink::WebInputEvent& event) { | |
| 208 if (blink::WebInputEvent::isGestureEventType(event_to_coalesce.type) && | |
| 209 blink::WebInputEvent::isGestureEventType(event.type)) { | |
| 210 return CanCoalesce( | |
| 211 static_cast<const blink::WebGestureEvent&>(event_to_coalesce), | |
| 212 static_cast<const blink::WebGestureEvent&>(event)); | |
| 213 } | |
| 214 if (blink::WebInputEvent::isMouseEventType(event_to_coalesce.type) && | |
| 215 blink::WebInputEvent::isMouseEventType(event.type)) { | |
| 216 return CanCoalesce( | |
| 217 static_cast<const blink::WebMouseEvent&>(event_to_coalesce), | |
| 218 static_cast<const blink::WebMouseEvent&>(event)); | |
| 219 } | |
| 220 if (blink::WebInputEvent::isTouchEventType(event_to_coalesce.type) && | |
| 221 blink::WebInputEvent::isTouchEventType(event.type)) { | |
| 222 return CanCoalesce( | |
| 223 static_cast<const blink::WebTouchEvent&>(event_to_coalesce), | |
| 224 static_cast<const blink::WebTouchEvent&>(event)); | |
| 225 } | |
| 226 if (event_to_coalesce.type == blink::WebInputEvent::MouseWheel && | |
| 227 event.type == blink::WebInputEvent::MouseWheel) { | |
| 228 return CanCoalesce( | |
| 229 static_cast<const blink::WebMouseWheelEvent&>(event_to_coalesce), | |
| 230 static_cast<const blink::WebMouseWheelEvent&>(event)); | |
| 231 } | |
| 232 return false; | |
| 233 } | |
| 234 | |
| 235 void Coalesce(const blink::WebInputEvent& event_to_coalesce, | |
| 236 blink::WebInputEvent* event) { | |
| 237 if (blink::WebInputEvent::isGestureEventType(event_to_coalesce.type) && | |
| 238 blink::WebInputEvent::isGestureEventType(event->type)) { | |
| 239 Coalesce(static_cast<const blink::WebGestureEvent&>(event_to_coalesce), | |
| 240 static_cast<blink::WebGestureEvent*>(event)); | |
| 241 return; | |
| 242 } | |
| 243 if (blink::WebInputEvent::isMouseEventType(event_to_coalesce.type) && | |
| 244 blink::WebInputEvent::isMouseEventType(event->type)) { | |
| 245 Coalesce(static_cast<const blink::WebMouseEvent&>(event_to_coalesce), | |
| 246 static_cast<blink::WebMouseEvent*>(event)); | |
| 247 return; | |
| 248 } | |
| 249 if (blink::WebInputEvent::isTouchEventType(event_to_coalesce.type) && | |
| 250 blink::WebInputEvent::isTouchEventType(event->type)) { | |
| 251 Coalesce(static_cast<const blink::WebTouchEvent&>(event_to_coalesce), | |
| 252 static_cast<blink::WebTouchEvent*>(event)); | |
| 253 return; | |
| 254 } | |
| 255 if (event_to_coalesce.type == blink::WebInputEvent::MouseWheel && | |
| 256 event->type == blink::WebInputEvent::MouseWheel) { | |
| 257 Coalesce(static_cast<const blink::WebMouseWheelEvent&>(event_to_coalesce), | |
| 258 static_cast<blink::WebMouseWheelEvent*>(event)); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 } // namespace internal | |
| 263 | 10 |
| 264 ScopedWebInputEventWithLatencyInfo::ScopedWebInputEventWithLatencyInfo( | 11 ScopedWebInputEventWithLatencyInfo::ScopedWebInputEventWithLatencyInfo( |
| 265 ui::ScopedWebInputEvent event, | 12 ui::ScopedWebInputEvent event, |
| 266 const ui::LatencyInfo& latency_info) | 13 const ui::LatencyInfo& latency_info) |
| 267 : event_(std::move(event)), latency_(latency_info) { | 14 : event_(std::move(event)), latency_(latency_info) { |
| 268 } | 15 } |
| 269 | 16 |
| 270 ScopedWebInputEventWithLatencyInfo::~ScopedWebInputEventWithLatencyInfo() {} | 17 ScopedWebInputEventWithLatencyInfo::~ScopedWebInputEventWithLatencyInfo() {} |
| 271 | 18 |
| 272 bool ScopedWebInputEventWithLatencyInfo::CanCoalesceWith( | 19 bool ScopedWebInputEventWithLatencyInfo::CanCoalesceWith( |
| 273 const ScopedWebInputEventWithLatencyInfo& other) const { | 20 const ScopedWebInputEventWithLatencyInfo& other) const { |
| 274 return internal::CanCoalesce(other.event(), event()); | 21 return ui::CanCoalesce(other.event(), event()); |
| 275 } | 22 } |
| 276 | 23 |
| 277 void ScopedWebInputEventWithLatencyInfo::CoalesceWith( | 24 void ScopedWebInputEventWithLatencyInfo::CoalesceWith( |
| 278 const ScopedWebInputEventWithLatencyInfo& other) { | 25 const ScopedWebInputEventWithLatencyInfo& other) { |
| 279 // |other| should be a newer event than |this|. | 26 // |other| should be a newer event than |this|. |
| 280 if (other.latency_.trace_id() >= 0 && latency_.trace_id() >= 0) | 27 if (other.latency_.trace_id() >= 0 && latency_.trace_id() >= 0) |
| 281 DCHECK_GT(other.latency_.trace_id(), latency_.trace_id()); | 28 DCHECK_GT(other.latency_.trace_id(), latency_.trace_id()); |
| 282 | 29 |
| 283 // New events get coalesced into older events, and the newer timestamp | 30 // New events get coalesced into older events, and the newer timestamp |
| 284 // should always be preserved. | 31 // should always be preserved. |
| 285 const double time_stamp_seconds = other.event().timeStampSeconds; | 32 const double time_stamp_seconds = other.event().timeStampSeconds; |
| 286 internal::Coalesce(other.event(), event_.get()); | 33 ui::Coalesce(other.event(), event_.get()); |
| 287 event_->timeStampSeconds = time_stamp_seconds; | 34 event_->timeStampSeconds = time_stamp_seconds; |
| 288 | 35 |
| 289 // When coalescing two input events, we keep the oldest LatencyInfo | 36 // When coalescing two input events, we keep the oldest LatencyInfo |
| 290 // since it will represent the longest latency. | 37 // since it will represent the longest latency. |
| 291 other.latency_ = latency_; | 38 other.latency_ = latency_; |
| 292 other.latency_.set_coalesced(); | 39 other.latency_.set_coalesced(); |
| 293 } | 40 } |
| 294 | 41 |
| 295 const blink::WebInputEvent& ScopedWebInputEventWithLatencyInfo::event() const { | 42 const blink::WebInputEvent& ScopedWebInputEventWithLatencyInfo::event() const { |
| 296 return *event_; | 43 return *event_; |
| 297 } | 44 } |
| 298 | 45 |
| 299 blink::WebInputEvent& ScopedWebInputEventWithLatencyInfo::event() { | 46 blink::WebInputEvent& ScopedWebInputEventWithLatencyInfo::event() { |
| 300 return *event_; | 47 return *event_; |
| 301 } | 48 } |
| 302 | 49 |
| 303 } // namespace content | 50 } // namespace content |
| OLD | NEW |