Home | History | Annotate | Download | only in input
      1 // Copyright 2013 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 "content/common/input/web_input_event_traits.h"
      6 
      7 #include "base/logging.h"
      8 
      9 using blink::WebGestureEvent;
     10 using blink::WebInputEvent;
     11 using blink::WebKeyboardEvent;
     12 using blink::WebMouseEvent;
     13 using blink::WebMouseWheelEvent;
     14 using blink::WebTouchEvent;
     15 
     16 namespace content {
     17 namespace {
     18 
     19 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce,
     20                  const WebKeyboardEvent& event) {
     21   return false;
     22 }
     23 
     24 void Coalesce(const WebKeyboardEvent& event_to_coalesce,
     25               WebKeyboardEvent* event) {
     26   DCHECK(CanCoalesce(event_to_coalesce, *event));
     27 }
     28 
     29 bool CanCoalesce(const WebMouseEvent& event_to_coalesce,
     30                  const WebMouseEvent& event) {
     31   return event.type == event_to_coalesce.type &&
     32          event.type == WebInputEvent::MouseMove;
     33 }
     34 
     35 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) {
     36   DCHECK(CanCoalesce(event_to_coalesce, *event));
     37   // Accumulate movement deltas.
     38   int x = event->movementX;
     39   int y = event->movementY;
     40   *event = event_to_coalesce;
     41   event->movementX += x;
     42   event->movementY += y;
     43 }
     44 
     45 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
     46                  const WebMouseWheelEvent& event) {
     47   return event.modifiers == event_to_coalesce.modifiers &&
     48          event.scrollByPage == event_to_coalesce.scrollByPage &&
     49          event.phase == event_to_coalesce.phase &&
     50          event.momentumPhase == event_to_coalesce.momentumPhase &&
     51          event.hasPreciseScrollingDeltas ==
     52              event_to_coalesce.hasPreciseScrollingDeltas;
     53 }
     54 
     55 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
     56   return accelerated_delta * acceleration_ratio;
     57 }
     58 
     59 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
     60   if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
     61     return 1.f;
     62   return unaccelerated_delta / accelerated_delta;
     63 }
     64 
     65 void Coalesce(const WebMouseWheelEvent& event_to_coalesce,
     66               WebMouseWheelEvent* event) {
     67   DCHECK(CanCoalesce(event_to_coalesce, *event));
     68   float unaccelerated_x =
     69       GetUnacceleratedDelta(event->deltaX,
     70                             event->accelerationRatioX) +
     71       GetUnacceleratedDelta(event_to_coalesce.deltaX,
     72                             event_to_coalesce.accelerationRatioX);
     73   float unaccelerated_y =
     74       GetUnacceleratedDelta(event->deltaY,
     75                             event->accelerationRatioY) +
     76       GetUnacceleratedDelta(event_to_coalesce.deltaY,
     77                             event_to_coalesce.accelerationRatioY);
     78   event->deltaX += event_to_coalesce.deltaX;
     79   event->deltaY += event_to_coalesce.deltaY;
     80   event->wheelTicksX += event_to_coalesce.wheelTicksX;
     81   event->wheelTicksY += event_to_coalesce.wheelTicksY;
     82   event->accelerationRatioX =
     83       GetAccelerationRatio(event->deltaX, unaccelerated_x);
     84   event->accelerationRatioY =
     85       GetAccelerationRatio(event->deltaY, unaccelerated_y);
     86   DCHECK_GE(event_to_coalesce.timeStampSeconds, event->timeStampSeconds);
     87   event->timeStampSeconds = event_to_coalesce.timeStampSeconds;
     88 }
     89 
     90 bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
     91                  const WebTouchEvent& event) {
     92   return event.type == event_to_coalesce.type &&
     93          event.type == WebInputEvent::TouchMove &&
     94          event.modifiers == event_to_coalesce.modifiers &&
     95          event.touchesLength == event_to_coalesce.touchesLength;
     96 }
     97 
     98 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
     99   DCHECK(CanCoalesce(event_to_coalesce, *event));
    100   // The WebTouchPoints include absolute position information. So it is
    101   // sufficient to simply replace the previous event with the new event->
    102   // However, it is necessary to make sure that all the points have the
    103   // correct state, i.e. the touch-points that moved in the last event, but
    104   // didn't change in the current event, will have Stationary state. It is
    105   // necessary to change them back to Moved state.
    106   WebTouchEvent old_event = *event;
    107   *event = event_to_coalesce;
    108   for (unsigned i = 0; i < event->touchesLength; ++i) {
    109     if (old_event.touches[i].state == blink::WebTouchPoint::StateMoved)
    110       event->touches[i].state = blink::WebTouchPoint::StateMoved;
    111   }
    112 }
    113 
    114 bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
    115                  const WebGestureEvent& event) {
    116   return event.type == event_to_coalesce.type &&
    117          event.type == WebInputEvent::GestureScrollUpdate &&
    118          event.modifiers == event_to_coalesce.modifiers;
    119 }
    120 
    121 void Coalesce(const WebGestureEvent& event_to_coalesce,
    122               WebGestureEvent* event) {
    123   DCHECK(CanCoalesce(event_to_coalesce, *event));
    124   event->data.scrollUpdate.deltaX += event_to_coalesce.data.scrollUpdate.deltaX;
    125   event->data.scrollUpdate.deltaY += event_to_coalesce.data.scrollUpdate.deltaY;
    126 }
    127 
    128 struct WebInputEventSize {
    129   template <class EventType>
    130   bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const {
    131     *type_size = sizeof(EventType);
    132     return true;
    133   }
    134 };
    135 
    136 struct WebInputEventClone {
    137   template <class EventType>
    138   bool Execute(const WebInputEvent& event,
    139                ScopedWebInputEvent* scoped_event) const {
    140     DCHECK_EQ(sizeof(EventType), event.size);
    141     *scoped_event = ScopedWebInputEvent(
    142         new EventType(static_cast<const EventType&>(event)));
    143     return true;
    144   }
    145 };
    146 
    147 struct WebInputEventDelete {
    148   template <class EventType>
    149   bool Execute(WebInputEvent* event, bool* /* dummy_var */) const {
    150     if (!event)
    151       return false;
    152     DCHECK_EQ(sizeof(EventType), event->size);
    153     delete static_cast<EventType*>(event);
    154     return true;
    155   }
    156 };
    157 
    158 struct WebInputEventCanCoalesce {
    159   template <class EventType>
    160   bool Execute(const WebInputEvent& event_to_coalesce,
    161                const WebInputEvent* event) const {
    162     if (event_to_coalesce.type != event->type)
    163       return false;
    164     DCHECK_EQ(sizeof(EventType), event->size);
    165     DCHECK_EQ(sizeof(EventType), event_to_coalesce.size);
    166     return CanCoalesce(static_cast<const EventType&>(event_to_coalesce),
    167                        *static_cast<const EventType*>(event));
    168   }
    169 };
    170 
    171 struct WebInputEventCoalesce {
    172   template <class EventType>
    173   bool Execute(const WebInputEvent& event_to_coalesce,
    174                WebInputEvent* event) const {
    175     Coalesce(static_cast<const EventType&>(event_to_coalesce),
    176              static_cast<EventType*>(event));
    177     return true;
    178   }
    179 };
    180 
    181 template <typename Operator, typename ArgIn, typename ArgOut>
    182 bool Apply(Operator op,
    183            WebInputEvent::Type type,
    184            const ArgIn& arg_in,
    185            ArgOut* arg_out) {
    186   if (WebInputEvent::isMouseEventType(type))
    187     return op.template Execute<WebMouseEvent>(arg_in, arg_out);
    188   else if (type == WebInputEvent::MouseWheel)
    189     return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out);
    190   else if (WebInputEvent::isKeyboardEventType(type))
    191     return op.template Execute<WebKeyboardEvent>(arg_in, arg_out);
    192   else if (WebInputEvent::isTouchEventType(type))
    193     return op.template Execute<WebTouchEvent>(arg_in, arg_out);
    194   else if (WebInputEvent::isGestureEventType(type))
    195     return op.template Execute<WebGestureEvent>(arg_in, arg_out);
    196 
    197   NOTREACHED() << "Unknown webkit event type " << type;
    198   return false;
    199 }
    200 
    201 }  // namespace
    202 
    203 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) {
    204 #define CASE_TYPE(t) case WebInputEvent::t:  return #t
    205   switch(type) {
    206     CASE_TYPE(Undefined);
    207     CASE_TYPE(MouseDown);
    208     CASE_TYPE(MouseUp);
    209     CASE_TYPE(MouseMove);
    210     CASE_TYPE(MouseEnter);
    211     CASE_TYPE(MouseLeave);
    212     CASE_TYPE(ContextMenu);
    213     CASE_TYPE(MouseWheel);
    214     CASE_TYPE(RawKeyDown);
    215     CASE_TYPE(KeyDown);
    216     CASE_TYPE(KeyUp);
    217     CASE_TYPE(Char);
    218     CASE_TYPE(GestureScrollBegin);
    219     CASE_TYPE(GestureScrollEnd);
    220     CASE_TYPE(GestureScrollUpdate);
    221     CASE_TYPE(GestureFlingStart);
    222     CASE_TYPE(GestureFlingCancel);
    223     CASE_TYPE(GestureShowPress);
    224     CASE_TYPE(GestureTap);
    225     CASE_TYPE(GestureTapUnconfirmed);
    226     CASE_TYPE(GestureTapDown);
    227     CASE_TYPE(GestureTapCancel);
    228     CASE_TYPE(GestureDoubleTap);
    229     CASE_TYPE(GestureTwoFingerTap);
    230     CASE_TYPE(GestureLongPress);
    231     CASE_TYPE(GestureLongTap);
    232     CASE_TYPE(GesturePinchBegin);
    233     CASE_TYPE(GesturePinchEnd);
    234     CASE_TYPE(GesturePinchUpdate);
    235     CASE_TYPE(TouchStart);
    236     CASE_TYPE(TouchMove);
    237     CASE_TYPE(TouchEnd);
    238     CASE_TYPE(TouchCancel);
    239     default:
    240       // Must include default to let blink::WebInputEvent add new event types
    241       // before they're added here.
    242       DLOG(WARNING) <<
    243           "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n";
    244       break;
    245   }
    246 #undef CASE_TYPE
    247   return "";
    248 }
    249 
    250 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) {
    251   size_t size = 0;
    252   Apply(WebInputEventSize(), type, type, &size);
    253   return size;
    254 }
    255 
    256 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) {
    257   ScopedWebInputEvent scoped_event;
    258   Apply(WebInputEventClone(), event.type, event, &scoped_event);
    259   return scoped_event.Pass();
    260 }
    261 
    262 void WebInputEventTraits::Delete(WebInputEvent* event) {
    263   if (!event)
    264     return;
    265   bool dummy_var = false;
    266   Apply(WebInputEventDelete(), event->type, event, &dummy_var);
    267 }
    268 
    269 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce,
    270                                       const WebInputEvent& event) {
    271   // Early out before casting.
    272   if (event_to_coalesce.type != event.type)
    273     return false;
    274   return Apply(WebInputEventCanCoalesce(),
    275                event.type,
    276                event_to_coalesce,
    277                &event);
    278 }
    279 
    280 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce,
    281                                    WebInputEvent* event) {
    282   DCHECK(event);
    283   Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event);
    284 }
    285 
    286 bool WebInputEventTraits::IgnoresAckDisposition(
    287     blink::WebInputEvent::Type type) {
    288   switch (type) {
    289     case WebInputEvent::GestureTapDown:
    290     case WebInputEvent::GestureShowPress:
    291     case WebInputEvent::GestureTapCancel:
    292     case WebInputEvent::GesturePinchBegin:
    293     case WebInputEvent::GesturePinchEnd:
    294     case WebInputEvent::GestureScrollBegin:
    295     case WebInputEvent::GestureScrollEnd:
    296     case WebInputEvent::TouchCancel:
    297       return true;
    298     default:
    299       break;
    300   }
    301   return false;
    302 }
    303 
    304 }  // namespace content
    305