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