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