1 // Copyright (c) 2012 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 "ui/events/gestures/gesture_sequence.h" 6 7 #include <stdlib.h> 8 #include <cmath> 9 10 #include "base/command_line.h" 11 #include "base/logging.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/time/time.h" 15 #include "ui/events/event.h" 16 #include "ui/events/event_constants.h" 17 #include "ui/events/event_switches.h" 18 #include "ui/events/gestures/gesture_configuration.h" 19 #include "ui/events/gestures/gesture_util.h" 20 #include "ui/gfx/rect.h" 21 22 namespace ui { 23 24 namespace { 25 26 // ui::EventType is mapped to TouchState so it can fit into 3 bits of 27 // Signature. 28 enum TouchState { 29 TS_RELEASED, 30 TS_PRESSED, 31 TS_MOVED, 32 TS_STATIONARY, 33 TS_CANCELLED, 34 TS_UNKNOWN, 35 }; 36 37 // ui::EventResult is mapped to TouchStatusInternal to simply indicate whether a 38 // processed touch-event should affect gesture-recognition or not. 39 enum TouchStatusInternal { 40 TSI_NOT_PROCESSED, // The touch-event should take-part into 41 // gesture-recognition only if the touch-event has not 42 // been processed. 43 44 TSI_PROCESSED, // The touch-event should affect gesture-recognition only 45 // if the touch-event has been processed. For example,, 46 // this means that a JavaScript touch handler called 47 // |preventDefault| on the associated touch event 48 // or was processed by an aura-window or views-view. 49 50 TSI_ALWAYS // The touch-event should always affect gesture 51 // recognition. 52 }; 53 54 // Get equivalent TouchState from EventType |type|. 55 TouchState TouchEventTypeToTouchState(ui::EventType type) { 56 switch (type) { 57 case ui::ET_TOUCH_RELEASED: 58 return TS_RELEASED; 59 case ui::ET_TOUCH_PRESSED: 60 return TS_PRESSED; 61 case ui::ET_TOUCH_MOVED: 62 return TS_MOVED; 63 case ui::ET_TOUCH_STATIONARY: 64 return TS_STATIONARY; 65 case ui::ET_TOUCH_CANCELLED: 66 return TS_CANCELLED; 67 default: 68 DVLOG(1) << "Unknown Touch Event type"; 69 } 70 return TS_UNKNOWN; 71 } 72 73 // Gesture signature types for different values of combination (GestureState, 74 // touch_id, ui::EventType, touch_handled), see Signature for more info. 75 // 76 // Note: New addition of types should be placed as per their Signature value. 77 #define G(gesture_state, id, touch_state, handled) 1 + ( \ 78 (((touch_state) & 0x7) << 1) | \ 79 ((handled & 0x3) << 4) | \ 80 (((id) & 0xfff) << 6) | \ 81 ((gesture_state) << 18)) 82 83 enum EdgeStateSignatureType { 84 GST_INVALID = -1, 85 86 GST_NO_GESTURE_FIRST_PRESSED = 87 G(GS_NO_GESTURE, 0, TS_PRESSED, TSI_NOT_PROCESSED), 88 89 GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED = 90 G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_RELEASED, TSI_NOT_PROCESSED), 91 92 GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED_HANDLED = 93 G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_RELEASED, TSI_PROCESSED), 94 95 // Ignore processed touch-move events until gesture-scroll starts. 96 GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED = 97 G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_MOVED, TSI_NOT_PROCESSED), 98 99 GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED_PROCESSED = 100 G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_MOVED, TSI_PROCESSED), 101 102 GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY = 103 G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_STATIONARY, TSI_NOT_PROCESSED), 104 105 GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED = 106 G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_CANCELLED, TSI_ALWAYS), 107 108 GST_PENDING_SYNTHETIC_CLICK_SECOND_PRESSED = 109 G(GS_PENDING_SYNTHETIC_CLICK, 1, TS_PRESSED, TSI_NOT_PROCESSED), 110 111 GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED = 112 G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 113 0, 114 TS_RELEASED, 115 TSI_NOT_PROCESSED), 116 117 GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED_HANDLED = 118 G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_RELEASED, TSI_PROCESSED), 119 120 GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED = 121 G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_MOVED, TSI_ALWAYS), 122 123 GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_STATIONARY = 124 G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_STATIONARY, TSI_ALWAYS), 125 126 GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED = 127 G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_CANCELLED, TSI_ALWAYS), 128 129 GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED = 130 G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 1, TS_PRESSED, TSI_NOT_PROCESSED), 131 132 GST_SCROLL_FIRST_RELEASED = 133 G(GS_SCROLL, 0, TS_RELEASED, TSI_ALWAYS), 134 135 // Once scroll has started, process all touch-move events. 136 GST_SCROLL_FIRST_MOVED = 137 G(GS_SCROLL, 0, TS_MOVED, TSI_ALWAYS), 138 139 GST_SCROLL_FIRST_CANCELLED = 140 G(GS_SCROLL, 0, TS_CANCELLED, TSI_ALWAYS), 141 142 GST_SCROLL_SECOND_PRESSED = 143 G(GS_SCROLL, 1, TS_PRESSED, TSI_NOT_PROCESSED), 144 145 GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED = 146 G(GS_PENDING_TWO_FINGER_TAP, 0, TS_RELEASED, TSI_NOT_PROCESSED), 147 148 GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED_HANDLED = 149 G(GS_PENDING_TWO_FINGER_TAP, 0, TS_RELEASED, TSI_PROCESSED), 150 151 GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED = 152 G(GS_PENDING_TWO_FINGER_TAP, 1, TS_RELEASED, TSI_NOT_PROCESSED), 153 154 GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED_HANDLED = 155 G(GS_PENDING_TWO_FINGER_TAP, 1, TS_RELEASED, TSI_PROCESSED), 156 157 GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED = 158 G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, TSI_NOT_PROCESSED), 159 160 GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED = 161 G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, TSI_NOT_PROCESSED), 162 163 GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED_HANDLED = 164 G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, TSI_PROCESSED), 165 166 GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED_HANDLED = 167 G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, TSI_PROCESSED), 168 169 GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED = 170 G(GS_PENDING_TWO_FINGER_TAP, 0, TS_CANCELLED, TSI_ALWAYS), 171 172 GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED = 173 G(GS_PENDING_TWO_FINGER_TAP, 1, TS_CANCELLED, TSI_ALWAYS), 174 175 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED = 176 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_RELEASED, TSI_NOT_PROCESSED), 177 178 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED = 179 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_RELEASED, TSI_PROCESSED), 180 181 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED = 182 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_RELEASED, TSI_NOT_PROCESSED), 183 184 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED = 185 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_RELEASED, TSI_PROCESSED), 186 187 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_MOVED = 188 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_MOVED, TSI_ALWAYS), 189 190 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_MOVED = 191 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_MOVED, TSI_ALWAYS), 192 193 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED = 194 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_CANCELLED, TSI_ALWAYS), 195 196 GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED = 197 G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_CANCELLED, TSI_ALWAYS), 198 199 GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED = 200 G(GS_PENDING_TWO_FINGER_TAP, 2, TS_PRESSED, TSI_NOT_PROCESSED), 201 202 GST_PENDING_PINCH_FIRST_MOVED = 203 G(GS_PENDING_PINCH, 0, TS_MOVED, TSI_NOT_PROCESSED), 204 205 GST_PENDING_PINCH_SECOND_MOVED = 206 G(GS_PENDING_PINCH, 1, TS_MOVED, TSI_NOT_PROCESSED), 207 208 GST_PENDING_PINCH_FIRST_MOVED_HANDLED = 209 G(GS_PENDING_PINCH, 0, TS_MOVED, TSI_PROCESSED), 210 211 GST_PENDING_PINCH_SECOND_MOVED_HANDLED = 212 G(GS_PENDING_PINCH, 1, TS_MOVED, TSI_PROCESSED), 213 214 GST_PENDING_PINCH_FIRST_CANCELLED = 215 G(GS_PENDING_PINCH, 0, TS_CANCELLED, TSI_ALWAYS), 216 217 GST_PENDING_PINCH_SECOND_CANCELLED = 218 G(GS_PENDING_PINCH, 1, TS_CANCELLED, TSI_ALWAYS), 219 220 GST_PENDING_PINCH_FIRST_RELEASED = 221 G(GS_PENDING_PINCH, 0, TS_RELEASED, TSI_ALWAYS), 222 223 GST_PENDING_PINCH_SECOND_RELEASED = 224 G(GS_PENDING_PINCH, 1, TS_RELEASED, TSI_ALWAYS), 225 226 GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED = 227 G(GS_PENDING_PINCH_NO_PINCH, 0, TS_MOVED, TSI_ALWAYS), 228 229 GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED = 230 G(GS_PENDING_PINCH_NO_PINCH, 1, TS_MOVED, TSI_ALWAYS), 231 232 GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED = 233 G(GS_PENDING_PINCH_NO_PINCH, 0, TS_CANCELLED, TSI_ALWAYS), 234 235 GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED = 236 G(GS_PENDING_PINCH_NO_PINCH, 1, TS_CANCELLED, TSI_ALWAYS), 237 238 GST_PENDING_PINCH_NO_PINCH_FIRST_RELEASED = 239 G(GS_PENDING_PINCH_NO_PINCH, 0, TS_RELEASED, TSI_ALWAYS), 240 241 GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED = 242 G(GS_PENDING_PINCH_NO_PINCH, 1, TS_RELEASED, TSI_ALWAYS), 243 244 GST_PINCH_FIRST_MOVED = 245 G(GS_PINCH, 0, TS_MOVED, TSI_NOT_PROCESSED), 246 247 GST_PINCH_FIRST_MOVED_HANDLED = 248 G(GS_PINCH, 0, TS_MOVED, TSI_PROCESSED), 249 250 GST_PINCH_SECOND_MOVED = 251 G(GS_PINCH, 1, TS_MOVED, TSI_NOT_PROCESSED), 252 253 GST_PINCH_SECOND_MOVED_HANDLED = 254 G(GS_PINCH, 1, TS_MOVED, TSI_PROCESSED), 255 256 GST_PINCH_FIRST_RELEASED = 257 G(GS_PINCH, 0, TS_RELEASED, TSI_ALWAYS), 258 259 GST_PINCH_SECOND_RELEASED = 260 G(GS_PINCH, 1, TS_RELEASED, TSI_ALWAYS), 261 262 GST_PINCH_FIRST_CANCELLED = 263 G(GS_PINCH, 0, TS_CANCELLED, TSI_ALWAYS), 264 265 GST_PINCH_SECOND_CANCELLED = 266 G(GS_PINCH, 1, TS_CANCELLED, TSI_ALWAYS), 267 268 GST_PINCH_THIRD_PRESSED = 269 G(GS_PINCH, 2, TS_PRESSED, TSI_NOT_PROCESSED), 270 271 GST_PINCH_THIRD_MOVED = 272 G(GS_PINCH, 2, TS_MOVED, TSI_NOT_PROCESSED), 273 274 GST_PINCH_THIRD_MOVED_HANDLED = 275 G(GS_PINCH, 2, TS_MOVED, TSI_PROCESSED), 276 277 GST_PINCH_THIRD_RELEASED = 278 G(GS_PINCH, 2, TS_RELEASED, TSI_ALWAYS), 279 280 GST_PINCH_THIRD_CANCELLED = 281 G(GS_PINCH, 2, TS_CANCELLED, TSI_ALWAYS), 282 283 GST_PINCH_FOURTH_PRESSED = 284 G(GS_PINCH, 3, TS_PRESSED, TSI_NOT_PROCESSED), 285 286 GST_PINCH_FOURTH_MOVED = 287 G(GS_PINCH, 3, TS_MOVED, TSI_NOT_PROCESSED), 288 289 GST_PINCH_FOURTH_MOVED_HANDLED = 290 G(GS_PINCH, 3, TS_MOVED, TSI_PROCESSED), 291 292 GST_PINCH_FOURTH_RELEASED = 293 G(GS_PINCH, 3, TS_RELEASED, TSI_ALWAYS), 294 295 GST_PINCH_FOURTH_CANCELLED = 296 G(GS_PINCH, 3, TS_CANCELLED, TSI_ALWAYS), 297 298 GST_PINCH_FIFTH_PRESSED = 299 G(GS_PINCH, 4, TS_PRESSED, TSI_NOT_PROCESSED), 300 301 GST_PINCH_FIFTH_MOVED = 302 G(GS_PINCH, 4, TS_MOVED, TSI_NOT_PROCESSED), 303 304 GST_PINCH_FIFTH_MOVED_HANDLED = 305 G(GS_PINCH, 4, TS_MOVED, TSI_PROCESSED), 306 307 GST_PINCH_FIFTH_RELEASED = 308 G(GS_PINCH, 4, TS_RELEASED, TSI_ALWAYS), 309 310 GST_PINCH_FIFTH_CANCELLED = 311 G(GS_PINCH, 4, TS_CANCELLED, TSI_ALWAYS), 312 }; 313 314 // Builds a signature. Signatures are assembled by joining together 315 // multiple bits. 316 // 1 LSB bit so that the computed signature is always greater than 0 317 // 3 bits for the |type|. 318 // 2 bit for |touch_status| 319 // 12 bits for |touch_id| 320 // 14 bits for the |gesture_state|. 321 EdgeStateSignatureType Signature(GestureState gesture_state, 322 unsigned int touch_id, 323 ui::EventType type, 324 TouchStatusInternal touch_status) { 325 CHECK((touch_id & 0xfff) == touch_id); 326 TouchState touch_state = TouchEventTypeToTouchState(type); 327 EdgeStateSignatureType signature = static_cast<EdgeStateSignatureType> 328 (G(gesture_state, touch_id, touch_state, touch_status)); 329 330 switch (signature) { 331 case GST_NO_GESTURE_FIRST_PRESSED: 332 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED: 333 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED_HANDLED: 334 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED: 335 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED_PROCESSED: 336 case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY: 337 case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED: 338 case GST_PENDING_SYNTHETIC_CLICK_SECOND_PRESSED: 339 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED: 340 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED_HANDLED: 341 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED: 342 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_STATIONARY: 343 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED: 344 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED: 345 case GST_SCROLL_FIRST_RELEASED: 346 case GST_SCROLL_FIRST_MOVED: 347 case GST_SCROLL_FIRST_CANCELLED: 348 case GST_SCROLL_SECOND_PRESSED: 349 case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED: 350 case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED_HANDLED: 351 case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED: 352 case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED_HANDLED: 353 case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED: 354 case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED: 355 case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED_HANDLED: 356 case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED_HANDLED: 357 case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED: 358 case GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED: 359 case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED: 360 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_MOVED: 361 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_MOVED: 362 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED: 363 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED: 364 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED: 365 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED: 366 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED: 367 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED: 368 case GST_PENDING_PINCH_FIRST_MOVED: 369 case GST_PENDING_PINCH_SECOND_MOVED: 370 case GST_PENDING_PINCH_FIRST_MOVED_HANDLED: 371 case GST_PENDING_PINCH_SECOND_MOVED_HANDLED: 372 case GST_PENDING_PINCH_FIRST_RELEASED: 373 case GST_PENDING_PINCH_SECOND_RELEASED: 374 case GST_PENDING_PINCH_FIRST_CANCELLED: 375 case GST_PENDING_PINCH_SECOND_CANCELLED: 376 case GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED: 377 case GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED: 378 case GST_PENDING_PINCH_NO_PINCH_FIRST_RELEASED: 379 case GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED: 380 case GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED: 381 case GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED: 382 case GST_PINCH_FIRST_MOVED: 383 case GST_PINCH_FIRST_MOVED_HANDLED: 384 case GST_PINCH_SECOND_MOVED: 385 case GST_PINCH_SECOND_MOVED_HANDLED: 386 case GST_PINCH_FIRST_RELEASED: 387 case GST_PINCH_SECOND_RELEASED: 388 case GST_PINCH_FIRST_CANCELLED: 389 case GST_PINCH_SECOND_CANCELLED: 390 case GST_PINCH_THIRD_PRESSED: 391 case GST_PINCH_THIRD_MOVED: 392 case GST_PINCH_THIRD_MOVED_HANDLED: 393 case GST_PINCH_THIRD_RELEASED: 394 case GST_PINCH_THIRD_CANCELLED: 395 case GST_PINCH_FOURTH_PRESSED: 396 case GST_PINCH_FOURTH_MOVED: 397 case GST_PINCH_FOURTH_MOVED_HANDLED: 398 case GST_PINCH_FOURTH_RELEASED: 399 case GST_PINCH_FOURTH_CANCELLED: 400 case GST_PINCH_FIFTH_PRESSED: 401 case GST_PINCH_FIFTH_MOVED: 402 case GST_PINCH_FIFTH_MOVED_HANDLED: 403 case GST_PINCH_FIFTH_RELEASED: 404 case GST_PINCH_FIFTH_CANCELLED: 405 break; 406 default: 407 signature = GST_INVALID; 408 break; 409 } 410 411 return signature; 412 } 413 #undef G 414 415 float BoundingBoxDiagonal(const gfx::Rect& rect) { 416 float width = rect.width() * rect.width(); 417 float height = rect.height() * rect.height(); 418 return sqrt(width + height); 419 } 420 421 unsigned int ComputeTouchBitmask(const GesturePoint* points) { 422 unsigned int touch_bitmask = 0; 423 for (int i = 0; i < GestureSequence::kMaxGesturePoints; ++i) { 424 if (points[i].in_use()) 425 touch_bitmask |= 1 << points[i].touch_id(); 426 } 427 return touch_bitmask; 428 } 429 430 const float kFlingCurveNormalization = 1.0f / 1875.f; 431 432 float CalibrateFlingVelocity(float velocity) { 433 const unsigned last_coefficient = 434 GestureConfiguration::NumAccelParams - 1; 435 float normalized_velocity = fabs(velocity * kFlingCurveNormalization); 436 float nu = 0.0f, x = 1.f; 437 438 for (int i = last_coefficient ; i >= 0; i--) { 439 float a = GestureConfiguration::fling_acceleration_curve_coefficients(i); 440 nu += x * a; 441 x *= normalized_velocity; 442 } 443 if (velocity < 0.f) 444 return std::max(nu * velocity, -GestureConfiguration::fling_velocity_cap()); 445 else 446 return std::min(nu * velocity, GestureConfiguration::fling_velocity_cap()); 447 } 448 449 450 void UpdateGestureEventLatencyInfo(const TouchEvent& event, 451 GestureSequence::Gestures* gestures) { 452 // If the touch event does not cause any rendering scheduled, we first 453 // end the touch event's LatencyInfo. Then we copy the touch event's 454 // LatencyInfo into the generated gesture's LatencyInfo. Since one touch 455 // event can generate multiple gesture events, we have to clear the gesture 456 // event's trace_id, remove its ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 457 // so when the gesture event passes through RWHI, a new trace_id will be 458 // assigned and new ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT will be added. 459 if (!event.latency()->FindLatency( 460 ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, NULL)) { 461 ui::LatencyInfo* touch_latency = 462 const_cast<ui::LatencyInfo*>(event.latency()); 463 touch_latency->AddLatencyNumber( 464 ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, 0); 465 GestureSequence::Gestures::iterator it = gestures->begin(); 466 for (; it != gestures->end(); it++) { 467 ui::LatencyInfo* gesture_latency = (*it)->latency(); 468 *gesture_latency = *touch_latency; 469 gesture_latency->trace_id = -1; 470 gesture_latency->terminated = false; 471 gesture_latency->RemoveLatency( 472 ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT); 473 } 474 } 475 } 476 477 } // namespace 478 479 //////////////////////////////////////////////////////////////////////////////// 480 // GestureSequence Public: 481 482 GestureSequence::GestureSequence(GestureSequenceDelegate* delegate) 483 : state_(GS_NO_GESTURE), 484 flags_(0), 485 pinch_distance_start_(0.f), 486 pinch_distance_current_(0.f), 487 scroll_type_(ST_FREE), 488 point_count_(0), 489 delegate_(delegate) { 490 CHECK(delegate_); 491 } 492 493 GestureSequence::~GestureSequence() { 494 } 495 496 GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture( 497 const TouchEvent& event, 498 EventResult result) { 499 StopTimersIfRequired(event); 500 last_touch_location_ = event.location(); 501 if (result & ER_CONSUMED) 502 return NULL; 503 504 // Set a limit on the number of simultaneous touches in a gesture. 505 if (event.touch_id() >= kMaxGesturePoints) 506 return NULL; 507 508 if (event.type() == ui::ET_TOUCH_PRESSED) { 509 if (point_count_ == kMaxGesturePoints) 510 return NULL; 511 GesturePoint* new_point = &points_[event.touch_id()]; 512 // We shouldn't be able to get two PRESSED events from the same 513 // finger without either a RELEASE or CANCEL in between. But let's not crash 514 // in a release build. 515 if (new_point->in_use()) { 516 LOG(ERROR) << "Received a second press for a point: " << event.touch_id(); 517 new_point->ResetVelocity(); 518 new_point->UpdateValues(event); 519 return NULL; 520 } 521 new_point->set_point_id(point_count_++); 522 new_point->set_touch_id(event.touch_id()); 523 } 524 525 GestureState last_state = state_; 526 527 // NOTE: when modifying these state transitions, also update gestures.dot 528 scoped_ptr<Gestures> gestures(new Gestures()); 529 GesturePoint& point = GesturePointForEvent(event); 530 point.UpdateValues(event); 531 RecreateBoundingBox(); 532 flags_ = event.flags(); 533 const int point_id = point.point_id(); 534 if (point_id < 0) 535 return NULL; 536 537 // Send GESTURE_BEGIN for any touch pressed. 538 if (event.type() == ui::ET_TOUCH_PRESSED) 539 AppendBeginGestureEvent(point, gestures.get()); 540 541 TouchStatusInternal status_internal = (result == ER_UNHANDLED) ? 542 TSI_NOT_PROCESSED : TSI_PROCESSED; 543 544 EdgeStateSignatureType signature = Signature(state_, point_id, 545 event.type(), status_internal); 546 547 if (signature == GST_INVALID) 548 signature = Signature(state_, point_id, event.type(), TSI_ALWAYS); 549 550 switch (signature) { 551 case GST_INVALID: 552 break; 553 554 case GST_NO_GESTURE_FIRST_PRESSED: 555 TouchDown(event, point, gestures.get()); 556 set_state(GS_PENDING_SYNTHETIC_CLICK); 557 break; 558 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED: 559 if (Click(event, point, gestures.get())) 560 point.UpdateForTap(); 561 else 562 PrependTapCancelGestureEvent(point, gestures.get()); 563 set_state(GS_NO_GESTURE); 564 break; 565 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED: 566 case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY: 567 if (ScrollStart(event, point, gestures.get())) { 568 PrependTapCancelGestureEvent(point, gestures.get()); 569 set_state(GS_SCROLL); 570 if (ScrollUpdate(event, point, gestures.get())) 571 point.UpdateForScroll(); 572 } 573 break; 574 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED: 575 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_STATIONARY: 576 // No scrolling allowed, so nothing happens. 577 break; 578 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED_PROCESSED: 579 if (point.IsInScrollWindow(event)) { 580 PrependTapCancelGestureEvent(point, gestures.get()); 581 set_state(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL); 582 } 583 break; 584 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED_HANDLED: 585 case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED: 586 PrependTapCancelGestureEvent(point, gestures.get()); 587 set_state(GS_NO_GESTURE); 588 break; 589 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED: 590 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED_HANDLED: 591 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED: 592 set_state(GS_NO_GESTURE); 593 break; 594 case GST_SCROLL_FIRST_MOVED: 595 if (scroll_type_ == ST_VERTICAL || 596 scroll_type_ == ST_HORIZONTAL) 597 BreakRailScroll(event, point, gestures.get()); 598 if (ScrollUpdate(event, point, gestures.get())) 599 point.UpdateForScroll(); 600 break; 601 case GST_SCROLL_FIRST_RELEASED: 602 case GST_SCROLL_FIRST_CANCELLED: 603 ScrollEnd(event, point, gestures.get()); 604 set_state(GS_NO_GESTURE); 605 break; 606 case GST_PENDING_SYNTHETIC_CLICK_SECOND_PRESSED: 607 PrependTapCancelGestureEvent(point, gestures.get()); 608 TwoFingerTapOrPinch(event, point, gestures.get()); 609 break; 610 case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED: 611 TwoFingerTapOrPinch(event, point, gestures.get()); 612 break; 613 case GST_SCROLL_SECOND_PRESSED: 614 PinchStart(event, point, gestures.get()); 615 set_state(GS_PINCH); 616 break; 617 case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED: 618 case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED: 619 TwoFingerTouchReleased(event, point, gestures.get()); 620 set_state(GS_SCROLL); 621 break; 622 case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED: 623 case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED: 624 if (TwoFingerTouchMove(event, point, gestures.get())) 625 set_state(GS_PINCH); 626 break; 627 case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED_HANDLED: 628 case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED_HANDLED: 629 set_state(GS_PENDING_TWO_FINGER_TAP_NO_PINCH); 630 break; 631 case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED_HANDLED: 632 case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED_HANDLED: 633 case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED: 634 case GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED: 635 scroll_type_ = ST_FREE; 636 set_state(GS_SCROLL); 637 break; 638 case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED: 639 set_state(GS_PENDING_PINCH); 640 break; 641 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_MOVED: 642 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_MOVED: 643 // No pinch allowed, so nothing happens. 644 break; 645 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED: 646 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED: 647 TwoFingerTouchReleased(event, point, gestures.get()); 648 // We transit into GS_SCROLL even though the touch move can be 649 // consumed and no scroll should happen. crbug.com/240399. 650 set_state(GS_SCROLL); 651 break; 652 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED: 653 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED: 654 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED: 655 case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED: 656 // We transit into GS_SCROLL even though the touch move can be 657 // consumed and no scroll should happen. crbug.com/240399. 658 scroll_type_ = ST_FREE; 659 set_state(GS_SCROLL); 660 break; 661 case GST_PENDING_PINCH_FIRST_MOVED: 662 case GST_PENDING_PINCH_SECOND_MOVED: 663 if (TwoFingerTouchMove(event, point, gestures.get())) 664 set_state(GS_PINCH); 665 break; 666 case GST_PENDING_PINCH_FIRST_MOVED_HANDLED: 667 case GST_PENDING_PINCH_SECOND_MOVED_HANDLED: 668 set_state(GS_PENDING_PINCH_NO_PINCH); 669 break; 670 case GST_PENDING_PINCH_FIRST_RELEASED: 671 case GST_PENDING_PINCH_SECOND_RELEASED: 672 case GST_PENDING_PINCH_FIRST_CANCELLED: 673 case GST_PENDING_PINCH_SECOND_CANCELLED: 674 // We transit into GS_SCROLL even though the touch move can be 675 // consumed and no scroll should happen. crbug.com/240399. 676 scroll_type_ = ST_FREE; 677 set_state(GS_SCROLL); 678 break; 679 case GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED: 680 case GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED: 681 // No pinch allowed, so nothing happens. 682 break; 683 case GST_PENDING_PINCH_NO_PINCH_FIRST_RELEASED: 684 case GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED: 685 case GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED: 686 case GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED: 687 // We transit into GS_SCROLL even though the touch move can be 688 // consumed and no scroll should happen. crbug.com/240399. 689 scroll_type_ = ST_FREE; 690 set_state(GS_SCROLL); 691 break; 692 case GST_PINCH_FIRST_MOVED_HANDLED: 693 case GST_PINCH_SECOND_MOVED_HANDLED: 694 case GST_PINCH_THIRD_MOVED_HANDLED: 695 case GST_PINCH_FOURTH_MOVED_HANDLED: 696 case GST_PINCH_FIFTH_MOVED_HANDLED: 697 break; 698 case GST_PINCH_FIRST_MOVED: 699 case GST_PINCH_SECOND_MOVED: 700 case GST_PINCH_THIRD_MOVED: 701 case GST_PINCH_FOURTH_MOVED: 702 case GST_PINCH_FIFTH_MOVED: 703 if (PinchUpdate(event, point, gestures.get())) { 704 for (int i = 0; i < point_count_; ++i) 705 GetPointByPointId(i)->UpdateForScroll(); 706 } 707 break; 708 case GST_PINCH_FIRST_RELEASED: 709 case GST_PINCH_SECOND_RELEASED: 710 case GST_PINCH_THIRD_RELEASED: 711 case GST_PINCH_FOURTH_RELEASED: 712 case GST_PINCH_FIFTH_RELEASED: 713 case GST_PINCH_FIRST_CANCELLED: 714 case GST_PINCH_SECOND_CANCELLED: 715 case GST_PINCH_THIRD_CANCELLED: 716 case GST_PINCH_FOURTH_CANCELLED: 717 case GST_PINCH_FIFTH_CANCELLED: 718 // Was it a swipe? i.e. were all the fingers moving in the same 719 // direction? 720 MaybeSwipe(event, point, gestures.get()); 721 722 if (point_count_ == 2) { 723 PinchEnd(event, point, gestures.get()); 724 725 // Once pinch ends, it should still be possible to scroll with the 726 // remaining finger on the screen. 727 set_state(GS_SCROLL); 728 } else { 729 // Nothing else to do if we have more than 2 fingers active, since after 730 // the release/cancel, there are still enough fingers to do pinch. 731 // pinch_distance_current_ and pinch_distance_start_ will be updated 732 // when the bounding-box is updated. 733 } 734 ResetVelocities(); 735 break; 736 case GST_PINCH_THIRD_PRESSED: 737 case GST_PINCH_FOURTH_PRESSED: 738 case GST_PINCH_FIFTH_PRESSED: 739 pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_); 740 pinch_distance_start_ = pinch_distance_current_; 741 break; 742 } 743 744 if (event.type() == ui::ET_TOUCH_RELEASED || 745 event.type() == ui::ET_TOUCH_CANCELLED) 746 AppendEndGestureEvent(point, gestures.get()); 747 748 if (state_ != last_state) 749 DVLOG(4) << "Gesture Sequence" 750 << " State: " << state_ 751 << " touch id: " << event.touch_id(); 752 753 if (last_state == GS_PENDING_SYNTHETIC_CLICK && state_ != last_state) { 754 GetLongPressTimer()->Stop(); 755 GetShowPressTimer()->Stop(); 756 } 757 758 // The set of point_ids must be contiguous and include 0. 759 // When a touch point is released, all points with ids greater than the 760 // released point must have their ids decremented, or the set of point_ids 761 // could end up with gaps. 762 if (event.type() == ui::ET_TOUCH_RELEASED || 763 event.type() == ui::ET_TOUCH_CANCELLED) { 764 for (int i = 0; i < kMaxGesturePoints; ++i) { 765 GesturePoint& iter_point = points_[i]; 766 if (iter_point.point_id() > point.point_id()) 767 iter_point.set_point_id(iter_point.point_id() - 1); 768 } 769 770 point.Reset(); 771 --point_count_; 772 CHECK_GE(point_count_, 0); 773 RecreateBoundingBox(); 774 if (state_ == GS_PINCH) { 775 pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_); 776 pinch_distance_start_ = pinch_distance_current_; 777 } 778 } 779 780 UpdateGestureEventLatencyInfo(event, gestures.get()); 781 return gestures.release(); 782 } 783 784 void GestureSequence::RecreateBoundingBox() { 785 // TODO(sad): Recreating the bounding box at every touch-event is not very 786 // efficient. This should be made better. 787 if (point_count_ == 0) { 788 bounding_box_.SetRect(0, 0, 0, 0); 789 } else if (point_count_ == 1) { 790 bounding_box_ = GetPointByPointId(0)->enclosing_rectangle(); 791 } else { 792 int left = INT_MAX / 20, top = INT_MAX / 20; 793 int right = INT_MIN / 20, bottom = INT_MIN / 20; 794 for (int i = 0; i < kMaxGesturePoints; ++i) { 795 if (!points_[i].in_use()) 796 continue; 797 // Using the |enclosing_rectangle()| for the touch-points would be ideal. 798 // However, this becomes brittle especially when a finger is in motion 799 // because the change in radius can overshadow the actual change in 800 // position. So the actual position of the point is used instead. 801 const gfx::Point& point = points_[i].last_touch_position(); 802 left = std::min(left, point.x()); 803 right = std::max(right, point.x()); 804 top = std::min(top, point.y()); 805 bottom = std::max(bottom, point.y()); 806 } 807 bounding_box_.SetRect(left, top, right - left, bottom - top); 808 } 809 } 810 811 void GestureSequence::ResetVelocities() { 812 for (int i = 0; i < kMaxGesturePoints; ++i) { 813 if (points_[i].in_use()) 814 points_[i].ResetVelocity(); 815 } 816 } 817 818 //////////////////////////////////////////////////////////////////////////////// 819 // GestureSequence Protected: 820 821 base::OneShotTimer<GestureSequence>* GestureSequence::CreateTimer() { 822 return new base::OneShotTimer<GestureSequence>(); 823 } 824 825 base::OneShotTimer<GestureSequence>* GestureSequence::GetLongPressTimer() { 826 if (!long_press_timer_.get()) 827 long_press_timer_.reset(CreateTimer()); 828 return long_press_timer_.get(); 829 } 830 831 base::OneShotTimer<GestureSequence>* GestureSequence::GetShowPressTimer() { 832 if (!show_press_timer_.get()) 833 show_press_timer_.reset(CreateTimer()); 834 return show_press_timer_.get(); 835 } 836 837 //////////////////////////////////////////////////////////////////////////////// 838 // GestureSequence Private: 839 840 GesturePoint& GestureSequence::GesturePointForEvent( 841 const TouchEvent& event) { 842 return points_[event.touch_id()]; 843 } 844 845 GesturePoint* GestureSequence::GetPointByPointId(int point_id) { 846 DCHECK(0 <= point_id && point_id < kMaxGesturePoints); 847 for (int i = 0; i < kMaxGesturePoints; ++i) { 848 GesturePoint& point = points_[i]; 849 if (point.in_use() && point.point_id() == point_id) 850 return &point; 851 } 852 NOTREACHED(); 853 return NULL; 854 } 855 856 bool GestureSequence::IsSecondTouchDownCloseEnoughForTwoFingerTap() { 857 gfx::Point p1 = GetPointByPointId(0)->last_touch_position(); 858 gfx::Point p2 = GetPointByPointId(1)->last_touch_position(); 859 double max_distance = 860 GestureConfiguration::max_distance_for_two_finger_tap_in_pixels(); 861 double distance = (p1.x() - p2.x()) * (p1.x() - p2.x()) + 862 (p1.y() - p2.y()) * (p1.y() - p2.y()); 863 if (distance < max_distance * max_distance) 864 return true; 865 return false; 866 } 867 868 GestureEvent* GestureSequence::CreateGestureEvent( 869 const GestureEventDetails& details, 870 const gfx::Point& location, 871 int flags, 872 base::Time timestamp, 873 unsigned int touch_id_bitmask) { 874 GestureEventDetails gesture_details(details); 875 gesture_details.set_touch_points(point_count_); 876 gesture_details.set_bounding_box(bounding_box_); 877 base::TimeDelta time_stamp = 878 base::TimeDelta::FromMicroseconds(timestamp.ToDoubleT() * 1000000); 879 return new GestureEvent(gesture_details.type(), location.x(), location.y(), 880 flags, time_stamp, gesture_details, 881 touch_id_bitmask); 882 } 883 884 void GestureSequence::AppendTapDownGestureEvent(const GesturePoint& point, 885 Gestures* gestures) { 886 gestures->push_back(CreateGestureEvent( 887 GestureEventDetails(ui::ET_GESTURE_TAP_DOWN, 0, 0), 888 point.first_touch_position(), 889 flags_, 890 base::Time::FromDoubleT(point.last_touch_time()), 891 1 << point.touch_id())); 892 } 893 894 void GestureSequence::PrependTapCancelGestureEvent(const GesturePoint& point, 895 Gestures* gestures) { 896 gestures->insert(gestures->begin(), CreateGestureEvent( 897 GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL, 0, 0), 898 point.first_touch_position(), 899 flags_, 900 base::Time::FromDoubleT(point.last_touch_time()), 901 1 << point.touch_id())); 902 } 903 904 void GestureSequence::AppendBeginGestureEvent(const GesturePoint& point, 905 Gestures* gestures) { 906 gestures->push_back(CreateGestureEvent( 907 GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 908 point.first_touch_position(), 909 flags_, 910 base::Time::FromDoubleT(point.last_touch_time()), 911 1 << point.touch_id())); 912 } 913 914 void GestureSequence::AppendEndGestureEvent(const GesturePoint& point, 915 Gestures* gestures) { 916 gestures->push_back(CreateGestureEvent( 917 GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 918 point.first_touch_position(), 919 flags_, 920 base::Time::FromDoubleT(point.last_touch_time()), 921 1 << point.touch_id())); 922 } 923 924 void GestureSequence::AppendClickGestureEvent(const GesturePoint& point, 925 int tap_count, 926 Gestures* gestures) { 927 gfx::Rect er = point.enclosing_rectangle(); 928 gfx::Point center = er.CenterPoint(); 929 gestures->push_back(CreateGestureEvent( 930 GestureEventDetails(ui::ET_GESTURE_TAP, tap_count, 0), 931 center, 932 flags_, 933 base::Time::FromDoubleT(point.last_touch_time()), 934 1 << point.touch_id())); 935 } 936 937 void GestureSequence::AppendScrollGestureBegin(const GesturePoint& point, 938 const gfx::Point& location, 939 Gestures* gestures) { 940 gestures->push_back(CreateGestureEvent( 941 GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0), 942 location, 943 flags_, 944 base::Time::FromDoubleT(point.last_touch_time()), 945 1 << point.touch_id())); 946 } 947 948 void GestureSequence::AppendScrollGestureEnd(const GesturePoint& point, 949 const gfx::Point& location, 950 Gestures* gestures, 951 float x_velocity, 952 float y_velocity) { 953 float railed_x_velocity = x_velocity; 954 float railed_y_velocity = y_velocity; 955 last_scroll_prediction_offset_.set_x(0); 956 last_scroll_prediction_offset_.set_y(0); 957 958 if (scroll_type_ == ST_HORIZONTAL) 959 railed_y_velocity = 0; 960 else if (scroll_type_ == ST_VERTICAL) 961 railed_x_velocity = 0; 962 963 if (railed_x_velocity != 0 || railed_y_velocity != 0) { 964 965 gestures->push_back(CreateGestureEvent( 966 GestureEventDetails(ui::ET_SCROLL_FLING_START, 967 CalibrateFlingVelocity(railed_x_velocity), 968 CalibrateFlingVelocity(railed_y_velocity), 969 CalibrateFlingVelocity(x_velocity), 970 CalibrateFlingVelocity(y_velocity)), 971 location, 972 flags_, 973 base::Time::FromDoubleT(point.last_touch_time()), 974 1 << point.touch_id())); 975 } else { 976 gestures->push_back(CreateGestureEvent( 977 GestureEventDetails(ui::ET_GESTURE_SCROLL_END, 0, 0), 978 location, 979 flags_, 980 base::Time::FromDoubleT(point.last_touch_time()), 981 1 << point.touch_id())); 982 } 983 } 984 985 void GestureSequence::AppendScrollGestureUpdate(GesturePoint& point, 986 Gestures* gestures) { 987 static bool use_scroll_prediction = CommandLine::ForCurrentProcess()-> 988 HasSwitch(switches::kEnableScrollPrediction); 989 gfx::Vector2dF d; 990 gfx::Point location; 991 if (point_count_ == 1) { 992 d = point.ScrollDelta(); 993 location = point.last_touch_position(); 994 } else { 995 location = bounding_box_.CenterPoint(); 996 d = location - latest_multi_scroll_update_location_; 997 latest_multi_scroll_update_location_ = location; 998 } 999 1000 if (use_scroll_prediction) { 1001 // Remove the extra distance added by the last scroll prediction and add 1002 // the new prediction offset. 1003 d -= last_scroll_prediction_offset_; 1004 last_scroll_prediction_offset_.set_x( 1005 GestureConfiguration::scroll_prediction_seconds() * point.XVelocity()); 1006 last_scroll_prediction_offset_.set_y( 1007 GestureConfiguration::scroll_prediction_seconds() * point.YVelocity()); 1008 d += last_scroll_prediction_offset_; 1009 location += gfx::Vector2d(last_scroll_prediction_offset_.x(), 1010 last_scroll_prediction_offset_.y()); 1011 } 1012 1013 gfx::Vector2dF o = d; 1014 1015 if (scroll_type_ == ST_HORIZONTAL) 1016 d.set_y(0); 1017 else if (scroll_type_ == ST_VERTICAL) 1018 d.set_x(0); 1019 if (d.IsZero()) 1020 return; 1021 1022 GestureEventDetails details(ui::ET_GESTURE_SCROLL_UPDATE, 1023 d.x(), d.y(), o.x(), o.y()); 1024 details.SetScrollVelocity( 1025 scroll_type_ == ST_VERTICAL ? 0 : point.XVelocity(), 1026 scroll_type_ == ST_HORIZONTAL ? 0 : point.YVelocity(), 1027 point.XVelocity(), 1028 point.YVelocity()); 1029 gestures->push_back(CreateGestureEvent( 1030 details, 1031 location, 1032 flags_, 1033 base::Time::FromDoubleT(point.last_touch_time()), 1034 ComputeTouchBitmask(points_))); 1035 } 1036 1037 void GestureSequence::AppendPinchGestureBegin(const GesturePoint& p1, 1038 const GesturePoint& p2, 1039 Gestures* gestures) { 1040 gfx::Point center = bounding_box_.CenterPoint(); 1041 gestures->push_back(CreateGestureEvent( 1042 GestureEventDetails(ui::ET_GESTURE_PINCH_BEGIN, 0, 0), 1043 center, 1044 flags_, 1045 base::Time::FromDoubleT(p1.last_touch_time()), 1046 1 << p1.touch_id() | 1 << p2.touch_id())); 1047 } 1048 1049 void GestureSequence::AppendPinchGestureEnd(const GesturePoint& p1, 1050 const GesturePoint& p2, 1051 float scale, 1052 Gestures* gestures) { 1053 gfx::Point center = bounding_box_.CenterPoint(); 1054 gestures->push_back(CreateGestureEvent( 1055 GestureEventDetails(ui::ET_GESTURE_PINCH_END, 0, 0), 1056 center, 1057 flags_, 1058 base::Time::FromDoubleT(p1.last_touch_time()), 1059 1 << p1.touch_id() | 1 << p2.touch_id())); 1060 } 1061 1062 void GestureSequence::AppendPinchGestureUpdate(const GesturePoint& point, 1063 float scale, 1064 Gestures* gestures) { 1065 // TODO(sad): Compute rotation and include it in delta_y. 1066 // http://crbug.com/113145 1067 gestures->push_back(CreateGestureEvent( 1068 GestureEventDetails(ui::ET_GESTURE_PINCH_UPDATE, scale, 0), 1069 bounding_box_.CenterPoint(), 1070 flags_, 1071 base::Time::FromDoubleT(point.last_touch_time()), 1072 ComputeTouchBitmask(points_))); 1073 } 1074 1075 void GestureSequence::AppendSwipeGesture(const GesturePoint& point, 1076 int swipe_x, 1077 int swipe_y, 1078 Gestures* gestures) { 1079 gestures->push_back(CreateGestureEvent( 1080 GestureEventDetails(ui::ET_GESTURE_MULTIFINGER_SWIPE, swipe_x, swipe_y), 1081 bounding_box_.CenterPoint(), 1082 flags_, 1083 base::Time::FromDoubleT(point.last_touch_time()), 1084 ComputeTouchBitmask(points_))); 1085 } 1086 1087 void GestureSequence::AppendTwoFingerTapGestureEvent(Gestures* gestures) { 1088 const GesturePoint* point = GetPointByPointId(0); 1089 const gfx::Rect rect = point->enclosing_rectangle(); 1090 gestures->push_back(CreateGestureEvent( 1091 GestureEventDetails(ui::ET_GESTURE_TWO_FINGER_TAP, 1092 rect.width(), 1093 rect.height()), 1094 point->enclosing_rectangle().CenterPoint(), 1095 flags_, 1096 base::Time::FromDoubleT(point->last_touch_time()), 1097 1 << point->touch_id())); 1098 } 1099 1100 bool GestureSequence::Click(const TouchEvent& event, 1101 const GesturePoint& point, 1102 Gestures* gestures) { 1103 DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); 1104 if (point.IsInClickWindow(event)) { 1105 int tap_count = 1; 1106 if (point.IsInTripleClickWindow(event)) 1107 tap_count = 3; 1108 else if (point.IsInDoubleClickWindow(event)) 1109 tap_count = 2; 1110 if (tap_count == 1 && GetShowPressTimer()->IsRunning()) { 1111 GetShowPressTimer()->Stop(); 1112 AppendShowPressGestureEvent(); 1113 } 1114 AppendClickGestureEvent(point, tap_count, gestures); 1115 return true; 1116 } else if (point.IsInsideManhattanSquare(event) && 1117 !GetLongPressTimer()->IsRunning()) { 1118 AppendLongTapGestureEvent(point, gestures); 1119 } 1120 return false; 1121 } 1122 1123 bool GestureSequence::ScrollStart(const TouchEvent& event, 1124 GesturePoint& point, 1125 Gestures* gestures) { 1126 DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); 1127 if (!point.IsInScrollWindow(event)) 1128 return false; 1129 AppendScrollGestureBegin(point, point.first_touch_position(), gestures); 1130 if (point.IsInHorizontalRailWindow()) 1131 scroll_type_ = ST_HORIZONTAL; 1132 else if (point.IsInVerticalRailWindow()) 1133 scroll_type_ = ST_VERTICAL; 1134 else 1135 scroll_type_ = ST_FREE; 1136 return true; 1137 } 1138 1139 void GestureSequence::BreakRailScroll(const TouchEvent& event, 1140 GesturePoint& point, 1141 Gestures* gestures) { 1142 DCHECK(state_ == GS_SCROLL); 1143 if (scroll_type_ == ST_HORIZONTAL && 1144 point.BreaksHorizontalRail()) 1145 scroll_type_ = ST_FREE; 1146 else if (scroll_type_ == ST_VERTICAL && 1147 point.BreaksVerticalRail()) 1148 scroll_type_ = ST_FREE; 1149 } 1150 1151 bool GestureSequence::ScrollUpdate(const TouchEvent& event, 1152 GesturePoint& point, 1153 Gestures* gestures) { 1154 DCHECK(state_ == GS_SCROLL); 1155 if (!point.DidScroll(event, 0)) 1156 return false; 1157 AppendScrollGestureUpdate(point, gestures); 1158 return true; 1159 } 1160 1161 bool GestureSequence::TouchDown(const TouchEvent& event, 1162 const GesturePoint& point, 1163 Gestures* gestures) { 1164 DCHECK(state_ == GS_NO_GESTURE); 1165 AppendTapDownGestureEvent(point, gestures); 1166 GetLongPressTimer()->Start( 1167 FROM_HERE, 1168 base::TimeDelta::FromMilliseconds( 1169 GestureConfiguration::long_press_time_in_seconds() * 1000), 1170 this, 1171 &GestureSequence::AppendLongPressGestureEvent); 1172 1173 GetShowPressTimer()->Start( 1174 FROM_HERE, 1175 base::TimeDelta::FromMilliseconds( 1176 GestureConfiguration::show_press_delay_in_ms()), 1177 this, 1178 &GestureSequence::AppendShowPressGestureEvent); 1179 1180 return true; 1181 } 1182 1183 bool GestureSequence::TwoFingerTouchDown(const TouchEvent& event, 1184 const GesturePoint& point, 1185 Gestures* gestures) { 1186 DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK || 1187 state_ == GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL || 1188 state_ == GS_SCROLL); 1189 1190 if (state_ == GS_SCROLL) { 1191 AppendScrollGestureEnd(point, point.last_touch_position(), gestures, 1192 0.f, 0.f); 1193 } 1194 second_touch_time_ = event.time_stamp(); 1195 return true; 1196 } 1197 1198 bool GestureSequence::TwoFingerTouchMove(const TouchEvent& event, 1199 const GesturePoint& point, 1200 Gestures* gestures) { 1201 DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP || 1202 state_ == GS_PENDING_PINCH); 1203 1204 base::TimeDelta time_delta = event.time_stamp() - second_touch_time_; 1205 base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 * 1206 ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click()); 1207 if (time_delta > max_delta || !point.IsInsideManhattanSquare(event)) { 1208 PinchStart(event, point, gestures); 1209 return true; 1210 } 1211 return false; 1212 } 1213 1214 bool GestureSequence::TwoFingerTouchReleased(const TouchEvent& event, 1215 const GesturePoint& point, 1216 Gestures* gestures) { 1217 DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP || 1218 state_ == GS_PENDING_TWO_FINGER_TAP_NO_PINCH); 1219 base::TimeDelta time_delta = event.time_stamp() - second_touch_time_; 1220 base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 * 1221 ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click()); 1222 if (time_delta < max_delta && point.IsInsideManhattanSquare(event)) 1223 AppendTwoFingerTapGestureEvent(gestures); 1224 return true; 1225 } 1226 1227 void GestureSequence::AppendLongPressGestureEvent() { 1228 const GesturePoint* point = GetPointByPointId(0); 1229 scoped_ptr<GestureEvent> gesture(CreateGestureEvent( 1230 GestureEventDetails(ui::ET_GESTURE_LONG_PRESS, 0, 0), 1231 point->first_touch_position(), 1232 flags_, 1233 base::Time::FromDoubleT(point->last_touch_time()), 1234 1 << point->touch_id())); 1235 delegate_->DispatchPostponedGestureEvent(gesture.get()); 1236 } 1237 1238 void GestureSequence::AppendShowPressGestureEvent() { 1239 const GesturePoint* point = GetPointByPointId(0); 1240 scoped_ptr<GestureEvent> gesture(CreateGestureEvent( 1241 GestureEventDetails(ui::ET_GESTURE_SHOW_PRESS, 0, 0), 1242 point->first_touch_position(), 1243 flags_, 1244 base::Time::FromDoubleT(point->last_touch_time()), 1245 1 << point->touch_id())); 1246 delegate_->DispatchPostponedGestureEvent(gesture.get()); 1247 } 1248 1249 void GestureSequence::AppendLongTapGestureEvent(const GesturePoint& point, 1250 Gestures* gestures) { 1251 gfx::Rect er = point.enclosing_rectangle(); 1252 gfx::Point center = er.CenterPoint(); 1253 gestures->push_back(CreateGestureEvent( 1254 GestureEventDetails(ui::ET_GESTURE_LONG_TAP, 0, 0), 1255 center, 1256 flags_, 1257 base::Time::FromDoubleT(point.last_touch_time()), 1258 1 << point.touch_id())); 1259 } 1260 1261 bool GestureSequence::ScrollEnd(const TouchEvent& event, 1262 GesturePoint& point, 1263 Gestures* gestures) { 1264 DCHECK(state_ == GS_SCROLL); 1265 if (point.IsInFlickWindow(event)) { 1266 AppendScrollGestureEnd(point, point.last_touch_position(), gestures, 1267 point.XVelocity(), point.YVelocity()); 1268 } else { 1269 AppendScrollGestureEnd(point, point.last_touch_position(), gestures, 1270 0.f, 0.f); 1271 } 1272 return true; 1273 } 1274 1275 bool GestureSequence::PinchStart(const TouchEvent& event, 1276 const GesturePoint& point, 1277 Gestures* gestures) { 1278 DCHECK(state_ == GS_SCROLL || 1279 state_ == GS_PENDING_TWO_FINGER_TAP || 1280 state_ == GS_PENDING_PINCH); 1281 1282 // Once pinch starts, we immediately break rail scroll. 1283 scroll_type_ = ST_FREE; 1284 1285 const GesturePoint* point1 = GetPointByPointId(0); 1286 const GesturePoint* point2 = GetPointByPointId(1); 1287 1288 pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_); 1289 pinch_distance_start_ = pinch_distance_current_; 1290 latest_multi_scroll_update_location_ = bounding_box_.CenterPoint(); 1291 AppendPinchGestureBegin(*point1, *point2, gestures); 1292 1293 if (state_ == GS_PENDING_TWO_FINGER_TAP || 1294 state_ == GS_PENDING_PINCH) { 1295 gfx::Point center = bounding_box_.CenterPoint(); 1296 AppendScrollGestureBegin(point, center, gestures); 1297 } 1298 1299 return true; 1300 } 1301 1302 bool GestureSequence::PinchUpdate(const TouchEvent& event, 1303 GesturePoint& point, 1304 Gestures* gestures) { 1305 DCHECK(state_ == GS_PINCH); 1306 1307 // It is possible that the none of the touch-points changed their position, 1308 // but their radii changed, and that caused the bounding box to also change. 1309 // But in such cases, we do not want to either pinch or scroll. 1310 // To avoid small jiggles, it is also necessary to make sure that at least one 1311 // of the fingers moved enough before a pinch or scroll update is created. 1312 bool did_scroll = false; 1313 for (int i = 0; i < kMaxGesturePoints; ++i) { 1314 if (!points_[i].in_use() || !points_[i].DidScroll(event, 0)) 1315 continue; 1316 did_scroll = true; 1317 break; 1318 } 1319 1320 if (!did_scroll) 1321 return false; 1322 1323 float distance = BoundingBoxDiagonal(bounding_box_); 1324 1325 if (abs(distance - pinch_distance_current_) >= 1326 GestureConfiguration::min_pinch_update_distance_in_pixels()) { 1327 AppendPinchGestureUpdate(point, 1328 distance / pinch_distance_current_, gestures); 1329 pinch_distance_current_ = distance; 1330 } 1331 AppendScrollGestureUpdate(point, gestures); 1332 1333 return true; 1334 } 1335 1336 bool GestureSequence::PinchEnd(const TouchEvent& event, 1337 const GesturePoint& point, 1338 Gestures* gestures) { 1339 DCHECK(state_ == GS_PINCH); 1340 1341 GesturePoint* point1 = GetPointByPointId(0); 1342 GesturePoint* point2 = GetPointByPointId(1); 1343 1344 float distance = BoundingBoxDiagonal(bounding_box_); 1345 AppendPinchGestureEnd(*point1, *point2, 1346 distance / pinch_distance_start_, gestures); 1347 1348 pinch_distance_start_ = 0; 1349 pinch_distance_current_ = 0; 1350 return true; 1351 } 1352 1353 bool GestureSequence::MaybeSwipe(const TouchEvent& event, 1354 const GesturePoint& point, 1355 Gestures* gestures) { 1356 DCHECK(state_ == GS_PINCH); 1357 float velocity_x = 0.f, velocity_y = 0.f; 1358 bool swipe_x = true, swipe_y = true; 1359 int sign_x = 0, sign_y = 0; 1360 int i = 0; 1361 1362 for (i = 0; i < kMaxGesturePoints; ++i) { 1363 if (points_[i].in_use()) 1364 break; 1365 } 1366 DCHECK(i < kMaxGesturePoints); 1367 1368 velocity_x = points_[i].XVelocity(); 1369 velocity_y = points_[i].YVelocity(); 1370 sign_x = velocity_x < 0.f ? -1 : 1; 1371 sign_y = velocity_y < 0.f ? -1 : 1; 1372 1373 for (++i; i < kMaxGesturePoints; ++i) { 1374 if (!points_[i].in_use()) 1375 continue; 1376 1377 if (sign_x * points_[i].XVelocity() < 0) 1378 swipe_x = false; 1379 1380 if (sign_y * points_[i].YVelocity() < 0) 1381 swipe_y = false; 1382 1383 velocity_x += points_[i].XVelocity(); 1384 velocity_y += points_[i].YVelocity(); 1385 } 1386 1387 float min_velocity = GestureConfiguration::min_swipe_speed(); 1388 min_velocity *= min_velocity; 1389 1390 velocity_x = fabs(velocity_x / point_count_); 1391 velocity_y = fabs(velocity_y / point_count_); 1392 if (velocity_x < min_velocity) 1393 swipe_x = false; 1394 if (velocity_y < min_velocity) 1395 swipe_y = false; 1396 1397 if (!swipe_x && !swipe_y) 1398 return false; 1399 1400 if (!swipe_x) 1401 velocity_x = 0.001f; 1402 if (!swipe_y) 1403 velocity_y = 0.001f; 1404 1405 float ratio = velocity_x > velocity_y ? velocity_x / velocity_y : 1406 velocity_y / velocity_x; 1407 if (ratio < GestureConfiguration::max_swipe_deviation_ratio()) 1408 return false; 1409 1410 if (velocity_x > velocity_y) 1411 sign_y = 0; 1412 else 1413 sign_x = 0; 1414 1415 AppendSwipeGesture(point, sign_x, sign_y, gestures); 1416 1417 return true; 1418 } 1419 1420 void GestureSequence::TwoFingerTapOrPinch(const TouchEvent& event, 1421 const GesturePoint& point, 1422 Gestures* gestures) { 1423 if (IsSecondTouchDownCloseEnoughForTwoFingerTap()) { 1424 TwoFingerTouchDown(event, point, gestures); 1425 set_state(GS_PENDING_TWO_FINGER_TAP); 1426 } else { 1427 set_state(GS_PENDING_PINCH); 1428 } 1429 } 1430 1431 1432 void GestureSequence::StopTimersIfRequired(const TouchEvent& event) { 1433 if ((!GetLongPressTimer()->IsRunning() && 1434 !GetShowPressTimer()->IsRunning()) || 1435 event.type() != ui::ET_TOUCH_MOVED) 1436 return; 1437 1438 // Since a timer is running, there should be a non-NULL point. 1439 const GesturePoint* point = GetPointByPointId(0); 1440 if (!ui::gestures::IsInsideManhattanSquare(point->first_touch_position(), 1441 event.location())) { 1442 GetLongPressTimer()->Stop(); 1443 GetShowPressTimer()->Stop(); 1444 } 1445 } 1446 1447 } // namespace ui 1448