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