Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: ui/events/gestures/gesture_sequence.cc

Issue 458363002: Remove old Aura Gesture Detection Pipeline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix window compile issue. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698