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