| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/web_input_event_traits.h" | 5 #include "content/common/input/web_input_event_traits.h" |
| 6 | 6 |
| 7 #include <bitset> | |
| 8 #include <limits> | |
| 9 | |
| 10 #include "base/logging.h" | 7 #include "base/logging.h" |
| 11 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 12 | 9 |
| 13 using base::StringAppendF; | 10 using base::StringAppendF; |
| 14 using base::SStringPrintf; | 11 using base::SStringPrintf; |
| 15 using blink::WebGestureEvent; | 12 using blink::WebGestureEvent; |
| 16 using blink::WebInputEvent; | 13 using blink::WebInputEvent; |
| 17 using blink::WebKeyboardEvent; | 14 using blink::WebKeyboardEvent; |
| 18 using blink::WebMouseEvent; | 15 using blink::WebMouseEvent; |
| 19 using blink::WebMouseWheelEvent; | 16 using blink::WebMouseWheelEvent; |
| 20 using blink::WebTouchEvent; | 17 using blink::WebTouchEvent; |
| 21 using blink::WebTouchPoint; | 18 using blink::WebTouchPoint; |
| 22 using std::numeric_limits; | |
| 23 | 19 |
| 24 namespace content { | 20 namespace content { |
| 25 namespace { | 21 namespace { |
| 26 | 22 |
| 27 const int kInvalidTouchIndex = -1; | |
| 28 | |
| 29 void ApppendEventDetails(const WebKeyboardEvent& event, std::string* result) { | 23 void ApppendEventDetails(const WebKeyboardEvent& event, std::string* result) { |
| 30 StringAppendF(result, | 24 StringAppendF(result, |
| 31 "{\n WinCode: %d\n NativeCode: %d\n IsSystem: %d\n" | 25 "{\n WinCode: %d\n NativeCode: %d\n IsSystem: %d\n" |
| 32 " Text: %s\n UnmodifiedText: %s\n KeyIdentifier: %s\n}", | 26 " Text: %s\n UnmodifiedText: %s\n KeyIdentifier: %s\n}", |
| 33 event.windowsKeyCode, | 27 event.windowsKeyCode, |
| 34 event.nativeKeyCode, | 28 event.nativeKeyCode, |
| 35 event.isSystemKey, | 29 event.isSystemKey, |
| 36 reinterpret_cast<const char*>(event.text), | 30 reinterpret_cast<const char*>(event.text), |
| 37 reinterpret_cast<const char*>(event.unmodifiedText), | 31 reinterpret_cast<const char*>(event.unmodifiedText), |
| 38 reinterpret_cast<const char*>(event.keyIdentifier)); | 32 reinterpret_cast<const char*>(event.keyIdentifier)); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 StringAppendF(result, | 99 StringAppendF(result, |
| 106 "{\n Touches: %u, DispatchType: %d, CausesScrolling: %d," | 100 "{\n Touches: %u, DispatchType: %d, CausesScrolling: %d," |
| 107 " uniqueTouchEventId: %u\n[\n", | 101 " uniqueTouchEventId: %u\n[\n", |
| 108 event.touchesLength, event.dispatchType, | 102 event.touchesLength, event.dispatchType, |
| 109 event.movedBeyondSlopRegion, event.uniqueTouchEventId); | 103 event.movedBeyondSlopRegion, event.uniqueTouchEventId); |
| 110 for (unsigned i = 0; i < event.touchesLength; ++i) | 104 for (unsigned i = 0; i < event.touchesLength; ++i) |
| 111 ApppendTouchPointDetails(event.touches[i], result); | 105 ApppendTouchPointDetails(event.touches[i], result); |
| 112 result->append(" ]\n}"); | 106 result->append(" ]\n}"); |
| 113 } | 107 } |
| 114 | 108 |
| 115 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce, | |
| 116 const WebKeyboardEvent& event) { | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 void Coalesce(const WebKeyboardEvent& event_to_coalesce, | |
| 121 WebKeyboardEvent* event) { | |
| 122 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 123 } | |
| 124 | |
| 125 bool CanCoalesce(const WebMouseEvent& event_to_coalesce, | |
| 126 const WebMouseEvent& event) { | |
| 127 return event.type == event_to_coalesce.type && | |
| 128 event.type == WebInputEvent::MouseMove; | |
| 129 } | |
| 130 | |
| 131 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) { | |
| 132 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 133 // Accumulate movement deltas. | |
| 134 int x = event->movementX; | |
| 135 int y = event->movementY; | |
| 136 *event = event_to_coalesce; | |
| 137 event->movementX += x; | |
| 138 event->movementY += y; | |
| 139 } | |
| 140 | |
| 141 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce, | |
| 142 const WebMouseWheelEvent& event) { | |
| 143 return event.modifiers == event_to_coalesce.modifiers && | |
| 144 event.scrollByPage == event_to_coalesce.scrollByPage && | |
| 145 event.phase == event_to_coalesce.phase && | |
| 146 event.momentumPhase == event_to_coalesce.momentumPhase && | |
| 147 event.hasPreciseScrollingDeltas == | |
| 148 event_to_coalesce.hasPreciseScrollingDeltas; | |
| 149 } | |
| 150 | |
| 151 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) { | |
| 152 return accelerated_delta * acceleration_ratio; | |
| 153 } | |
| 154 | |
| 155 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { | |
| 156 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f) | |
| 157 return 1.f; | |
| 158 return unaccelerated_delta / accelerated_delta; | |
| 159 } | |
| 160 | |
| 161 void Coalesce(const WebMouseWheelEvent& event_to_coalesce, | |
| 162 WebMouseWheelEvent* event) { | |
| 163 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 164 float unaccelerated_x = | |
| 165 GetUnacceleratedDelta(event->deltaX, | |
| 166 event->accelerationRatioX) + | |
| 167 GetUnacceleratedDelta(event_to_coalesce.deltaX, | |
| 168 event_to_coalesce.accelerationRatioX); | |
| 169 float unaccelerated_y = | |
| 170 GetUnacceleratedDelta(event->deltaY, | |
| 171 event->accelerationRatioY) + | |
| 172 GetUnacceleratedDelta(event_to_coalesce.deltaY, | |
| 173 event_to_coalesce.accelerationRatioY); | |
| 174 event->deltaX += event_to_coalesce.deltaX; | |
| 175 event->deltaY += event_to_coalesce.deltaY; | |
| 176 event->wheelTicksX += event_to_coalesce.wheelTicksX; | |
| 177 event->wheelTicksY += event_to_coalesce.wheelTicksY; | |
| 178 event->accelerationRatioX = | |
| 179 GetAccelerationRatio(event->deltaX, unaccelerated_x); | |
| 180 event->accelerationRatioY = | |
| 181 GetAccelerationRatio(event->deltaY, unaccelerated_y); | |
| 182 } | |
| 183 | |
| 184 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|. | |
| 185 int GetIndexOfTouchID(const WebTouchEvent& event, int id) { | |
| 186 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
| 187 if (event.touches[i].id == id) | |
| 188 return i; | |
| 189 } | |
| 190 return kInvalidTouchIndex; | |
| 191 } | |
| 192 | |
| 193 WebInputEvent::DispatchType MergeDispatchTypes( | |
| 194 WebInputEvent::DispatchType type_1, | |
| 195 WebInputEvent::DispatchType type_2) { | |
| 196 static_assert(WebInputEvent::DispatchType::Blocking < | |
| 197 WebInputEvent::DispatchType::EventNonBlocking, | |
| 198 "Enum not ordered correctly"); | |
| 199 static_assert(WebInputEvent::DispatchType::EventNonBlocking < | |
| 200 WebInputEvent::DispatchType::ListenersNonBlockingPassive, | |
| 201 "Enum not ordered correctly"); | |
| 202 static_assert( | |
| 203 WebInputEvent::DispatchType::ListenersNonBlockingPassive < | |
| 204 WebInputEvent::DispatchType::ListenersForcedNonBlockingPassive, | |
| 205 "Enum not ordered correctly"); | |
| 206 return static_cast<WebInputEvent::DispatchType>( | |
| 207 std::min(static_cast<int>(type_1), static_cast<int>(type_2))); | |
| 208 } | |
| 209 | |
| 210 bool CanCoalesce(const WebTouchEvent& event_to_coalesce, | |
| 211 const WebTouchEvent& event) { | |
| 212 if (event.type != event_to_coalesce.type || | |
| 213 event.type != WebInputEvent::TouchMove || | |
| 214 event.modifiers != event_to_coalesce.modifiers || | |
| 215 event.touchesLength != event_to_coalesce.touchesLength || | |
| 216 event.touchesLength > WebTouchEvent::touchesLengthCap) | |
| 217 return false; | |
| 218 | |
| 219 static_assert(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U, | |
| 220 "suboptimal touchesLengthCap size"); | |
| 221 // Ensure that we have a 1-to-1 mapping of pointer ids between touches. | |
| 222 std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches( | |
| 223 (1 << event.touchesLength) - 1); | |
| 224 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) { | |
| 225 int event_touch_index = | |
| 226 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id); | |
| 227 if (event_touch_index == kInvalidTouchIndex) | |
| 228 return false; | |
| 229 if (!unmatched_event_touches[event_touch_index]) | |
| 230 return false; | |
| 231 unmatched_event_touches[event_touch_index] = false; | |
| 232 } | |
| 233 return unmatched_event_touches.none(); | |
| 234 } | |
| 235 | |
| 236 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) { | |
| 237 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 238 // The WebTouchPoints include absolute position information. So it is | |
| 239 // sufficient to simply replace the previous event with the new event-> | |
| 240 // However, it is necessary to make sure that all the points have the | |
| 241 // correct state, i.e. the touch-points that moved in the last event, but | |
| 242 // didn't change in the current event, will have Stationary state. It is | |
| 243 // necessary to change them back to Moved state. | |
| 244 WebTouchEvent old_event = *event; | |
| 245 *event = event_to_coalesce; | |
| 246 for (unsigned i = 0; i < event->touchesLength; ++i) { | |
| 247 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id); | |
| 248 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved) | |
| 249 event->touches[i].state = blink::WebTouchPoint::StateMoved; | |
| 250 } | |
| 251 event->movedBeyondSlopRegion |= old_event.movedBeyondSlopRegion; | |
| 252 event->dispatchType = MergeDispatchTypes(old_event.dispatchType, | |
| 253 event_to_coalesce.dispatchType); | |
| 254 } | |
| 255 | |
| 256 bool CanCoalesce(const WebGestureEvent& event_to_coalesce, | |
| 257 const WebGestureEvent& event) { | |
| 258 if (event.type != event_to_coalesce.type || | |
| 259 event.sourceDevice != event_to_coalesce.sourceDevice || | |
| 260 event.modifiers != event_to_coalesce.modifiers) | |
| 261 return false; | |
| 262 | |
| 263 if (event.type == WebInputEvent::GestureScrollUpdate) | |
| 264 return true; | |
| 265 | |
| 266 // GesturePinchUpdate scales can be combined only if they share a focal point, | |
| 267 // e.g., with double-tap drag zoom. | |
| 268 if (event.type == WebInputEvent::GesturePinchUpdate && | |
| 269 event.x == event_to_coalesce.x && | |
| 270 event.y == event_to_coalesce.y) | |
| 271 return true; | |
| 272 | |
| 273 return false; | |
| 274 } | |
| 275 | |
| 276 void Coalesce(const WebGestureEvent& event_to_coalesce, | |
| 277 WebGestureEvent* event) { | |
| 278 DCHECK(CanCoalesce(event_to_coalesce, *event)); | |
| 279 if (event->type == WebInputEvent::GestureScrollUpdate) { | |
| 280 event->data.scrollUpdate.deltaX += | |
| 281 event_to_coalesce.data.scrollUpdate.deltaX; | |
| 282 event->data.scrollUpdate.deltaY += | |
| 283 event_to_coalesce.data.scrollUpdate.deltaY; | |
| 284 DCHECK_EQ( | |
| 285 event->data.scrollUpdate.previousUpdateInSequencePrevented, | |
| 286 event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented); | |
| 287 } else if (event->type == WebInputEvent::GesturePinchUpdate) { | |
| 288 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale; | |
| 289 // Ensure the scale remains bounded above 0 and below Infinity so that | |
| 290 // we can reliably perform operations like log on the values. | |
| 291 if (event->data.pinchUpdate.scale < numeric_limits<float>::min()) | |
| 292 event->data.pinchUpdate.scale = numeric_limits<float>::min(); | |
| 293 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max()) | |
| 294 event->data.pinchUpdate.scale = numeric_limits<float>::max(); | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 struct WebInputEventToString { | 109 struct WebInputEventToString { |
| 299 template <class EventType> | 110 template <class EventType> |
| 300 bool Execute(const WebInputEvent& event, std::string* result) const { | 111 bool Execute(const WebInputEvent& event, std::string* result) const { |
| 301 SStringPrintf(result, "%s (Time: %lf, Modifiers: %d)\n", | 112 SStringPrintf(result, "%s (Time: %lf, Modifiers: %d)\n", |
| 302 WebInputEventTraits::GetName(event.type), | 113 WebInputEventTraits::GetName(event.type), |
| 303 event.timeStampSeconds, | 114 event.timeStampSeconds, |
| 304 event.modifiers); | 115 event.modifiers); |
| 305 const EventType& typed_event = static_cast<const EventType&>(event); | 116 const EventType& typed_event = static_cast<const EventType&>(event); |
| 306 ApppendEventDetails(typed_event, result); | 117 ApppendEventDetails(typed_event, result); |
| 307 return true; | 118 return true; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 331 template <class EventType> | 142 template <class EventType> |
| 332 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const { | 143 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const { |
| 333 if (!event) | 144 if (!event) |
| 334 return false; | 145 return false; |
| 335 DCHECK_EQ(sizeof(EventType), event->size); | 146 DCHECK_EQ(sizeof(EventType), event->size); |
| 336 delete static_cast<EventType*>(event); | 147 delete static_cast<EventType*>(event); |
| 337 return true; | 148 return true; |
| 338 } | 149 } |
| 339 }; | 150 }; |
| 340 | 151 |
| 341 struct WebInputEventCanCoalesce { | |
| 342 template <class EventType> | |
| 343 bool Execute(const WebInputEvent& event_to_coalesce, | |
| 344 const WebInputEvent* event) const { | |
| 345 if (event_to_coalesce.type != event->type) | |
| 346 return false; | |
| 347 DCHECK_EQ(sizeof(EventType), event->size); | |
| 348 DCHECK_EQ(sizeof(EventType), event_to_coalesce.size); | |
| 349 return CanCoalesce(static_cast<const EventType&>(event_to_coalesce), | |
| 350 *static_cast<const EventType*>(event)); | |
| 351 } | |
| 352 }; | |
| 353 | |
| 354 struct WebInputEventCoalesce { | |
| 355 template <class EventType> | |
| 356 bool Execute(const WebInputEvent& event_to_coalesce, | |
| 357 WebInputEvent* event) const { | |
| 358 // New events get coalesced into older events, and the newer timestamp | |
| 359 // should always be preserved. | |
| 360 const double time_stamp_seconds = event_to_coalesce.timeStampSeconds; | |
| 361 Coalesce(static_cast<const EventType&>(event_to_coalesce), | |
| 362 static_cast<EventType*>(event)); | |
| 363 event->timeStampSeconds = time_stamp_seconds; | |
| 364 return true; | |
| 365 } | |
| 366 }; | |
| 367 | |
| 368 template <typename Operator, typename ArgIn, typename ArgOut> | 152 template <typename Operator, typename ArgIn, typename ArgOut> |
| 369 bool Apply(Operator op, | 153 bool Apply(Operator op, |
| 370 WebInputEvent::Type type, | 154 WebInputEvent::Type type, |
| 371 const ArgIn& arg_in, | 155 const ArgIn& arg_in, |
| 372 ArgOut* arg_out) { | 156 ArgOut* arg_out) { |
| 373 if (WebInputEvent::isMouseEventType(type)) | 157 if (WebInputEvent::isMouseEventType(type)) |
| 374 return op.template Execute<WebMouseEvent>(arg_in, arg_out); | 158 return op.template Execute<WebMouseEvent>(arg_in, arg_out); |
| 375 else if (type == WebInputEvent::MouseWheel) | 159 else if (type == WebInputEvent::MouseWheel) |
| 376 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out); | 160 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out); |
| 377 else if (WebInputEvent::isKeyboardEventType(type)) | 161 else if (WebInputEvent::isKeyboardEventType(type)) |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 return scoped_event; | 237 return scoped_event; |
| 454 } | 238 } |
| 455 | 239 |
| 456 void WebInputEventTraits::Delete(WebInputEvent* event) { | 240 void WebInputEventTraits::Delete(WebInputEvent* event) { |
| 457 if (!event) | 241 if (!event) |
| 458 return; | 242 return; |
| 459 bool dummy_var = false; | 243 bool dummy_var = false; |
| 460 Apply(WebInputEventDelete(), event->type, event, &dummy_var); | 244 Apply(WebInputEventDelete(), event->type, event, &dummy_var); |
| 461 } | 245 } |
| 462 | 246 |
| 463 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce, | |
| 464 const WebInputEvent& event) { | |
| 465 // Early out before casting. | |
| 466 if (event_to_coalesce.type != event.type) | |
| 467 return false; | |
| 468 return Apply(WebInputEventCanCoalesce(), | |
| 469 event.type, | |
| 470 event_to_coalesce, | |
| 471 &event); | |
| 472 } | |
| 473 | |
| 474 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce, | |
| 475 WebInputEvent* event) { | |
| 476 DCHECK(event); | |
| 477 Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event); | |
| 478 } | |
| 479 | |
| 480 bool WebInputEventTraits::ShouldBlockEventStream(const WebInputEvent& event) { | 247 bool WebInputEventTraits::ShouldBlockEventStream(const WebInputEvent& event) { |
| 481 switch (event.type) { | 248 switch (event.type) { |
| 482 case WebInputEvent::MouseDown: | 249 case WebInputEvent::MouseDown: |
| 483 case WebInputEvent::MouseUp: | 250 case WebInputEvent::MouseUp: |
| 484 case WebInputEvent::MouseEnter: | 251 case WebInputEvent::MouseEnter: |
| 485 case WebInputEvent::MouseLeave: | 252 case WebInputEvent::MouseLeave: |
| 486 case WebInputEvent::ContextMenu: | 253 case WebInputEvent::ContextMenu: |
| 487 case WebInputEvent::GestureScrollBegin: | 254 case WebInputEvent::GestureScrollBegin: |
| 488 case WebInputEvent::GestureScrollEnd: | 255 case WebInputEvent::GestureScrollEnd: |
| 489 case WebInputEvent::GestureShowPress: | 256 case WebInputEvent::GestureShowPress: |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 | 297 |
| 531 uint32_t WebInputEventTraits::GetUniqueTouchEventId( | 298 uint32_t WebInputEventTraits::GetUniqueTouchEventId( |
| 532 const WebInputEvent& event) { | 299 const WebInputEvent& event) { |
| 533 if (WebInputEvent::isTouchEventType(event.type)) { | 300 if (WebInputEvent::isTouchEventType(event.type)) { |
| 534 return static_cast<const WebTouchEvent&>(event).uniqueTouchEventId; | 301 return static_cast<const WebTouchEvent&>(event).uniqueTouchEventId; |
| 535 } | 302 } |
| 536 return 0U; | 303 return 0U; |
| 537 } | 304 } |
| 538 | 305 |
| 539 } // namespace content | 306 } // namespace content |
| OLD | NEW |