| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 // MSVC++ requires this to be set before any other includes to get M_PI. | 5 // MSVC++ requires this to be set before any other includes to get M_PI. |
| 6 #define _USE_MATH_DEFINES | 6 #define _USE_MATH_DEFINES |
| 7 | 7 |
| 8 #include "ui/events/blink/blink_event_util.h" | 8 #include "ui/events/blink/blink_event_util.h" |
| 9 | 9 |
| 10 #include <stddef.h> | 10 #include <stddef.h> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <bitset> |
| 13 #include <cmath> | 14 #include <cmath> |
| 15 #include <limits> |
| 14 | 16 |
| 15 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 16 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 17 #include "third_party/WebKit/public/platform/WebGestureEvent.h" | 19 #include "third_party/WebKit/public/platform/WebGestureEvent.h" |
| 18 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 20 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
| 19 #include "ui/events/base_event_utils.h" | 21 #include "ui/events/base_event_utils.h" |
| 20 #include "ui/events/event_constants.h" | 22 #include "ui/events/event_constants.h" |
| 21 #include "ui/events/gesture_detection/gesture_event_data.h" | 23 #include "ui/events/gesture_detection/gesture_event_data.h" |
| 22 #include "ui/events/gesture_detection/motion_event.h" | 24 #include "ui/events/gesture_detection/motion_event.h" |
| 23 #include "ui/events/gesture_event_details.h" | 25 #include "ui/events/gesture_event_details.h" |
| 24 #include "ui/events/keycodes/dom/keycode_converter.h" | 26 #include "ui/events/keycodes/dom/keycode_converter.h" |
| 25 #include "ui/gfx/geometry/safe_integer_conversions.h" | 27 #include "ui/gfx/geometry/safe_integer_conversions.h" |
| 26 #include "ui/gfx/geometry/vector2d.h" | 28 #include "ui/gfx/geometry/vector2d.h" |
| 27 | 29 |
| 28 using blink::WebGestureEvent; | 30 using blink::WebGestureEvent; |
| 29 using blink::WebInputEvent; | 31 using blink::WebInputEvent; |
| 32 using blink::WebMouseEvent; |
| 33 using blink::WebMouseWheelEvent; |
| 30 using blink::WebPointerProperties; | 34 using blink::WebPointerProperties; |
| 31 using blink::WebTouchEvent; | 35 using blink::WebTouchEvent; |
| 32 using blink::WebTouchPoint; | 36 using blink::WebTouchPoint; |
| 37 using std::numeric_limits; |
| 33 | 38 |
| 34 namespace ui { | 39 namespace ui { |
| 35 namespace { | 40 namespace { |
| 36 | 41 |
| 42 const int kInvalidTouchIndex = -1; |
| 43 |
| 37 WebInputEvent::Type ToWebTouchEventType(MotionEvent::Action action) { | 44 WebInputEvent::Type ToWebTouchEventType(MotionEvent::Action action) { |
| 38 switch (action) { | 45 switch (action) { |
| 39 case MotionEvent::ACTION_DOWN: | 46 case MotionEvent::ACTION_DOWN: |
| 40 return WebInputEvent::TouchStart; | 47 return WebInputEvent::TouchStart; |
| 41 case MotionEvent::ACTION_MOVE: | 48 case MotionEvent::ACTION_MOVE: |
| 42 return WebInputEvent::TouchMove; | 49 return WebInputEvent::TouchMove; |
| 43 case MotionEvent::ACTION_UP: | 50 case MotionEvent::ACTION_UP: |
| 44 return WebInputEvent::TouchEnd; | 51 return WebInputEvent::TouchEnd; |
| 45 case MotionEvent::ACTION_CANCEL: | 52 case MotionEvent::ACTION_CANCEL: |
| 46 return WebInputEvent::TouchCancel; | 53 return WebInputEvent::TouchCancel; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 touch.rotationAngle = orientation_deg; | 195 touch.rotationAngle = orientation_deg; |
| 189 } else { | 196 } else { |
| 190 touch.radiusX = major_radius; | 197 touch.radiusX = major_radius; |
| 191 touch.radiusY = minor_radius; | 198 touch.radiusY = minor_radius; |
| 192 touch.rotationAngle = orientation_deg + 90; | 199 touch.rotationAngle = orientation_deg + 90; |
| 193 } | 200 } |
| 194 | 201 |
| 195 return touch; | 202 return touch; |
| 196 } | 203 } |
| 197 | 204 |
| 205 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) { |
| 206 return accelerated_delta * acceleration_ratio; |
| 207 } |
| 208 |
| 209 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { |
| 210 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f) |
| 211 return 1.f; |
| 212 return unaccelerated_delta / accelerated_delta; |
| 213 } |
| 214 |
| 215 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|. |
| 216 int GetIndexOfTouchID(const WebTouchEvent& event, int id) { |
| 217 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 218 if (event.touches[i].id == id) |
| 219 return i; |
| 220 } |
| 221 return kInvalidTouchIndex; |
| 222 } |
| 223 |
| 224 WebInputEvent::DispatchType MergeDispatchTypes( |
| 225 WebInputEvent::DispatchType type_1, |
| 226 WebInputEvent::DispatchType type_2) { |
| 227 static_assert(WebInputEvent::DispatchType::Blocking < |
| 228 WebInputEvent::DispatchType::EventNonBlocking, |
| 229 "Enum not ordered correctly"); |
| 230 static_assert(WebInputEvent::DispatchType::EventNonBlocking < |
| 231 WebInputEvent::DispatchType::ListenersNonBlockingPassive, |
| 232 "Enum not ordered correctly"); |
| 233 static_assert( |
| 234 WebInputEvent::DispatchType::ListenersNonBlockingPassive < |
| 235 WebInputEvent::DispatchType::ListenersForcedNonBlockingDueToFling, |
| 236 "Enum not ordered correctly"); |
| 237 return static_cast<WebInputEvent::DispatchType>( |
| 238 std::min(static_cast<int>(type_1), static_cast<int>(type_2))); |
| 239 } |
| 240 |
| 241 bool CanCoalesce(const WebMouseEvent& event_to_coalesce, |
| 242 const WebMouseEvent& event) { |
| 243 return event.type == event_to_coalesce.type && |
| 244 event.type == WebInputEvent::MouseMove; |
| 245 } |
| 246 |
| 247 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) { |
| 248 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 249 // Accumulate movement deltas. |
| 250 int x = event->movementX; |
| 251 int y = event->movementY; |
| 252 *event = event_to_coalesce; |
| 253 event->movementX += x; |
| 254 event->movementY += y; |
| 255 } |
| 256 |
| 257 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce, |
| 258 const WebMouseWheelEvent& event) { |
| 259 return event.modifiers == event_to_coalesce.modifiers && |
| 260 event.scrollByPage == event_to_coalesce.scrollByPage && |
| 261 event.phase == event_to_coalesce.phase && |
| 262 event.momentumPhase == event_to_coalesce.momentumPhase && |
| 263 event.hasPreciseScrollingDeltas == |
| 264 event_to_coalesce.hasPreciseScrollingDeltas; |
| 265 } |
| 266 |
| 267 void Coalesce(const WebMouseWheelEvent& event_to_coalesce, |
| 268 WebMouseWheelEvent* event) { |
| 269 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 270 float unaccelerated_x = |
| 271 GetUnacceleratedDelta(event->deltaX, event->accelerationRatioX) + |
| 272 GetUnacceleratedDelta(event_to_coalesce.deltaX, |
| 273 event_to_coalesce.accelerationRatioX); |
| 274 float unaccelerated_y = |
| 275 GetUnacceleratedDelta(event->deltaY, event->accelerationRatioY) + |
| 276 GetUnacceleratedDelta(event_to_coalesce.deltaY, |
| 277 event_to_coalesce.accelerationRatioY); |
| 278 float old_deltaX = event->deltaX; |
| 279 float old_deltaY = event->deltaY; |
| 280 float old_wheelTicksX = event->wheelTicksX; |
| 281 float old_wheelTicksY = event->wheelTicksY; |
| 282 float old_movementX = event->movementX; |
| 283 float old_movementY = event->movementY; |
| 284 *event = event_to_coalesce; |
| 285 event->deltaX += old_deltaX; |
| 286 event->deltaY += old_deltaY; |
| 287 event->wheelTicksX += old_wheelTicksX; |
| 288 event->wheelTicksY += old_wheelTicksY; |
| 289 event->movementX += old_movementX; |
| 290 event->movementY += old_movementY; |
| 291 event->accelerationRatioX = |
| 292 GetAccelerationRatio(event->deltaX, unaccelerated_x); |
| 293 event->accelerationRatioY = |
| 294 GetAccelerationRatio(event->deltaY, unaccelerated_y); |
| 295 } |
| 296 |
| 297 bool CanCoalesce(const WebTouchEvent& event_to_coalesce, |
| 298 const WebTouchEvent& event) { |
| 299 if (event.type != event_to_coalesce.type || |
| 300 event.type != WebInputEvent::TouchMove || |
| 301 event.modifiers != event_to_coalesce.modifiers || |
| 302 event.touchesLength != event_to_coalesce.touchesLength || |
| 303 event.touchesLength > WebTouchEvent::kTouchesLengthCap) |
| 304 return false; |
| 305 |
| 306 static_assert(WebTouchEvent::kTouchesLengthCap <= sizeof(int32_t) * 8U, |
| 307 "suboptimal kTouchesLengthCap size"); |
| 308 // Ensure that we have a 1-to-1 mapping of pointer ids between touches. |
| 309 std::bitset<WebTouchEvent::kTouchesLengthCap> unmatched_event_touches( |
| 310 (1 << event.touchesLength) - 1); |
| 311 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) { |
| 312 int event_touch_index = |
| 313 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id); |
| 314 if (event_touch_index == kInvalidTouchIndex) |
| 315 return false; |
| 316 if (!unmatched_event_touches[event_touch_index]) |
| 317 return false; |
| 318 unmatched_event_touches[event_touch_index] = false; |
| 319 } |
| 320 return unmatched_event_touches.none(); |
| 321 } |
| 322 |
| 323 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) { |
| 324 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 325 // The WebTouchPoints include absolute position information. So it is |
| 326 // sufficient to simply replace the previous event with the new event-> |
| 327 // However, it is necessary to make sure that all the points have the |
| 328 // correct state, i.e. the touch-points that moved in the last event, but |
| 329 // didn't change in the current event, will have Stationary state. It is |
| 330 // necessary to change them back to Moved state. |
| 331 WebTouchEvent old_event = *event; |
| 332 *event = event_to_coalesce; |
| 333 for (unsigned i = 0; i < event->touchesLength; ++i) { |
| 334 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id); |
| 335 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved) |
| 336 event->touches[i].state = blink::WebTouchPoint::StateMoved; |
| 337 } |
| 338 event->movedBeyondSlopRegion |= old_event.movedBeyondSlopRegion; |
| 339 event->dispatchType = MergeDispatchTypes(old_event.dispatchType, |
| 340 event_to_coalesce.dispatchType); |
| 341 } |
| 342 |
| 343 bool CanCoalesce(const WebGestureEvent& event_to_coalesce, |
| 344 const WebGestureEvent& event) { |
| 345 if (event.type != event_to_coalesce.type || |
| 346 event.sourceDevice != event_to_coalesce.sourceDevice || |
| 347 event.modifiers != event_to_coalesce.modifiers) |
| 348 return false; |
| 349 |
| 350 if (event.type == WebInputEvent::GestureScrollUpdate) |
| 351 return true; |
| 352 |
| 353 // GesturePinchUpdate scales can be combined only if they share a focal point, |
| 354 // e.g., with double-tap drag zoom. |
| 355 if (event.type == WebInputEvent::GesturePinchUpdate && |
| 356 event.x == event_to_coalesce.x && event.y == event_to_coalesce.y) |
| 357 return true; |
| 358 |
| 359 return false; |
| 360 } |
| 361 |
| 362 void Coalesce(const WebGestureEvent& event_to_coalesce, |
| 363 WebGestureEvent* event) { |
| 364 DCHECK(CanCoalesce(event_to_coalesce, *event)); |
| 365 if (event->type == WebInputEvent::GestureScrollUpdate) { |
| 366 event->data.scrollUpdate.deltaX += |
| 367 event_to_coalesce.data.scrollUpdate.deltaX; |
| 368 event->data.scrollUpdate.deltaY += |
| 369 event_to_coalesce.data.scrollUpdate.deltaY; |
| 370 DCHECK_EQ( |
| 371 event->data.scrollUpdate.previousUpdateInSequencePrevented, |
| 372 event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented); |
| 373 } else if (event->type == WebInputEvent::GesturePinchUpdate) { |
| 374 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale; |
| 375 // Ensure the scale remains bounded above 0 and below Infinity so that |
| 376 // we can reliably perform operations like log on the values. |
| 377 if (event->data.pinchUpdate.scale < numeric_limits<float>::min()) |
| 378 event->data.pinchUpdate.scale = numeric_limits<float>::min(); |
| 379 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max()) |
| 380 event->data.pinchUpdate.scale = numeric_limits<float>::max(); |
| 381 } |
| 382 } |
| 383 |
| 198 } // namespace | 384 } // namespace |
| 199 | 385 |
| 386 bool CanCoalesce(const blink::WebInputEvent& event_to_coalesce, |
| 387 const blink::WebInputEvent& event) { |
| 388 if (blink::WebInputEvent::isGestureEventType(event_to_coalesce.type) && |
| 389 blink::WebInputEvent::isGestureEventType(event.type)) { |
| 390 return CanCoalesce( |
| 391 static_cast<const blink::WebGestureEvent&>(event_to_coalesce), |
| 392 static_cast<const blink::WebGestureEvent&>(event)); |
| 393 } |
| 394 if (blink::WebInputEvent::isMouseEventType(event_to_coalesce.type) && |
| 395 blink::WebInputEvent::isMouseEventType(event.type)) { |
| 396 return CanCoalesce( |
| 397 static_cast<const blink::WebMouseEvent&>(event_to_coalesce), |
| 398 static_cast<const blink::WebMouseEvent&>(event)); |
| 399 } |
| 400 if (blink::WebInputEvent::isTouchEventType(event_to_coalesce.type) && |
| 401 blink::WebInputEvent::isTouchEventType(event.type)) { |
| 402 return CanCoalesce( |
| 403 static_cast<const blink::WebTouchEvent&>(event_to_coalesce), |
| 404 static_cast<const blink::WebTouchEvent&>(event)); |
| 405 } |
| 406 if (event_to_coalesce.type == blink::WebInputEvent::MouseWheel && |
| 407 event.type == blink::WebInputEvent::MouseWheel) { |
| 408 return CanCoalesce( |
| 409 static_cast<const blink::WebMouseWheelEvent&>(event_to_coalesce), |
| 410 static_cast<const blink::WebMouseWheelEvent&>(event)); |
| 411 } |
| 412 return false; |
| 413 } |
| 414 |
| 415 void Coalesce(const blink::WebInputEvent& event_to_coalesce, |
| 416 blink::WebInputEvent* event) { |
| 417 if (blink::WebInputEvent::isGestureEventType(event_to_coalesce.type) && |
| 418 blink::WebInputEvent::isGestureEventType(event->type)) { |
| 419 Coalesce(static_cast<const blink::WebGestureEvent&>(event_to_coalesce), |
| 420 static_cast<blink::WebGestureEvent*>(event)); |
| 421 return; |
| 422 } |
| 423 if (blink::WebInputEvent::isMouseEventType(event_to_coalesce.type) && |
| 424 blink::WebInputEvent::isMouseEventType(event->type)) { |
| 425 Coalesce(static_cast<const blink::WebMouseEvent&>(event_to_coalesce), |
| 426 static_cast<blink::WebMouseEvent*>(event)); |
| 427 return; |
| 428 } |
| 429 if (blink::WebInputEvent::isTouchEventType(event_to_coalesce.type) && |
| 430 blink::WebInputEvent::isTouchEventType(event->type)) { |
| 431 Coalesce(static_cast<const blink::WebTouchEvent&>(event_to_coalesce), |
| 432 static_cast<blink::WebTouchEvent*>(event)); |
| 433 return; |
| 434 } |
| 435 if (event_to_coalesce.type == blink::WebInputEvent::MouseWheel && |
| 436 event->type == blink::WebInputEvent::MouseWheel) { |
| 437 Coalesce(static_cast<const blink::WebMouseWheelEvent&>(event_to_coalesce), |
| 438 static_cast<blink::WebMouseWheelEvent*>(event)); |
| 439 } |
| 440 } |
| 441 |
| 200 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent( | 442 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent( |
| 201 const MotionEvent& event, | 443 const MotionEvent& event, |
| 202 bool moved_beyond_slop_region) { | 444 bool moved_beyond_slop_region) { |
| 203 static_assert(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) == | 445 static_assert(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) == |
| 204 static_cast<int>(blink::WebTouchEvent::kTouchesLengthCap), | 446 static_cast<int>(blink::WebTouchEvent::kTouchesLengthCap), |
| 205 "inconsistent maximum number of active touch points"); | 447 "inconsistent maximum number of active touch points"); |
| 206 | 448 |
| 207 blink::WebTouchEvent result; | 449 blink::WebTouchEvent result; |
| 208 | 450 |
| 209 result.type = ToWebTouchEventType(event.GetAction()); | 451 result.type = ToWebTouchEventType(event.GetAction()); |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 case DomKeyLocation::RIGHT: | 851 case DomKeyLocation::RIGHT: |
| 610 return blink::WebInputEvent::IsRight; | 852 return blink::WebInputEvent::IsRight; |
| 611 case DomKeyLocation::NUMPAD: | 853 case DomKeyLocation::NUMPAD: |
| 612 return blink::WebInputEvent::IsKeyPad; | 854 return blink::WebInputEvent::IsKeyPad; |
| 613 case DomKeyLocation::STANDARD: | 855 case DomKeyLocation::STANDARD: |
| 614 break; | 856 break; |
| 615 } | 857 } |
| 616 return static_cast<blink::WebInputEvent::Modifiers>(0); | 858 return static_cast<blink::WebInputEvent::Modifiers>(0); |
| 617 } | 859 } |
| 618 | 860 |
| 861 bool IsGestureScollOrPinch(WebInputEvent::Type type) { |
| 862 switch (type) { |
| 863 case blink::WebGestureEvent::GestureScrollBegin: |
| 864 case blink::WebGestureEvent::GestureScrollUpdate: |
| 865 case blink::WebGestureEvent::GestureScrollEnd: |
| 866 case blink::WebGestureEvent::GesturePinchBegin: |
| 867 case blink::WebGestureEvent::GesturePinchUpdate: |
| 868 case blink::WebGestureEvent::GesturePinchEnd: |
| 869 return true; |
| 870 default: |
| 871 return false; |
| 872 } |
| 873 } |
| 874 |
| 875 bool IsContinuousGestureEvent(WebInputEvent::Type type) { |
| 876 switch (type) { |
| 877 case blink::WebGestureEvent::GestureScrollUpdate: |
| 878 case blink::WebGestureEvent::GesturePinchUpdate: |
| 879 return true; |
| 880 default: |
| 881 return false; |
| 882 } |
| 883 } |
| 884 |
| 619 } // namespace ui | 885 } // namespace ui |
| OLD | NEW |