Home | History | Annotate | Download | only in renderer_host
      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 "content/browser/renderer_host/ui_events_helper.h"
      6 
      7 #include "third_party/WebKit/public/web/WebInputEvent.h"
      8 #include "ui/events/event.h"
      9 #include "ui/events/event_constants.h"
     10 
     11 namespace {
     12 
     13 int WebModifiersToUIFlags(int modifiers) {
     14   int flags = ui::EF_NONE;
     15 
     16   if (modifiers & blink::WebInputEvent::ShiftKey)
     17     flags |= ui::EF_SHIFT_DOWN;
     18   if (modifiers & blink::WebInputEvent::ControlKey)
     19     flags |= ui::EF_CONTROL_DOWN;
     20   if (modifiers & blink::WebInputEvent::AltKey)
     21     flags |= ui::EF_ALT_DOWN;
     22 
     23   if (modifiers & blink::WebInputEvent::LeftButtonDown)
     24     flags |= ui::EF_LEFT_MOUSE_BUTTON;
     25   if (modifiers & blink::WebInputEvent::RightButtonDown)
     26     flags |= ui::EF_RIGHT_MOUSE_BUTTON;
     27   if (modifiers & blink::WebInputEvent::MiddleButtonDown)
     28     flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
     29 
     30   if (modifiers & blink::WebInputEvent::CapsLockOn)
     31     flags |= ui::EF_CAPS_LOCK_DOWN;
     32 
     33   return flags;
     34 }
     35 
     36 ui::EventType WebTouchPointStateToEventType(
     37     blink::WebTouchPoint::State state) {
     38   switch (state) {
     39     case blink::WebTouchPoint::StateReleased:
     40       return ui::ET_TOUCH_RELEASED;
     41 
     42     case blink::WebTouchPoint::StatePressed:
     43       return ui::ET_TOUCH_PRESSED;
     44 
     45     case blink::WebTouchPoint::StateMoved:
     46       return ui::ET_TOUCH_MOVED;
     47 
     48     case blink::WebTouchPoint::StateCancelled:
     49       return ui::ET_TOUCH_CANCELLED;
     50 
     51     default:
     52       return ui::ET_UNKNOWN;
     53   }
     54 }
     55 
     56 blink::WebTouchPoint::State TouchPointStateFromEvent(
     57     const ui::TouchEvent& event) {
     58   switch (event.type()) {
     59     case ui::ET_TOUCH_PRESSED:
     60       return blink::WebTouchPoint::StatePressed;
     61     case ui::ET_TOUCH_RELEASED:
     62       return blink::WebTouchPoint::StateReleased;
     63     case ui::ET_TOUCH_MOVED:
     64       return blink::WebTouchPoint::StateMoved;
     65     case ui::ET_TOUCH_CANCELLED:
     66       return blink::WebTouchPoint::StateCancelled;
     67     default:
     68       return blink::WebTouchPoint::StateUndefined;
     69   }
     70 }
     71 
     72 blink::WebInputEvent::Type TouchEventTypeFromEvent(
     73     const ui::TouchEvent& event) {
     74   switch (event.type()) {
     75     case ui::ET_TOUCH_PRESSED:
     76       return blink::WebInputEvent::TouchStart;
     77     case ui::ET_TOUCH_RELEASED:
     78       return blink::WebInputEvent::TouchEnd;
     79     case ui::ET_TOUCH_MOVED:
     80       return blink::WebInputEvent::TouchMove;
     81     case ui::ET_TOUCH_CANCELLED:
     82       return blink::WebInputEvent::TouchCancel;
     83     default:
     84       return blink::WebInputEvent::Undefined;
     85   }
     86 }
     87 
     88 }  // namespace
     89 
     90 namespace content {
     91 
     92 bool MakeUITouchEventsFromWebTouchEvents(
     93     const TouchEventWithLatencyInfo& touch_with_latency,
     94     ScopedVector<ui::TouchEvent>* list,
     95     TouchEventCoordinateSystem coordinate_system) {
     96   const blink::WebTouchEvent& touch = touch_with_latency.event;
     97   ui::EventType type = ui::ET_UNKNOWN;
     98   switch (touch.type) {
     99     case blink::WebInputEvent::TouchStart:
    100       type = ui::ET_TOUCH_PRESSED;
    101       break;
    102     case blink::WebInputEvent::TouchEnd:
    103       type = ui::ET_TOUCH_RELEASED;
    104       break;
    105     case blink::WebInputEvent::TouchMove:
    106       type = ui::ET_TOUCH_MOVED;
    107       break;
    108     case blink::WebInputEvent::TouchCancel:
    109       type = ui::ET_TOUCH_CANCELLED;
    110       break;
    111     default:
    112       NOTREACHED();
    113       return false;
    114   }
    115 
    116   int flags = WebModifiersToUIFlags(touch.modifiers);
    117   base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
    118       static_cast<int64>(touch.timeStampSeconds * 1000000));
    119   for (unsigned i = 0; i < touch.touchesLength; ++i) {
    120     const blink::WebTouchPoint& point = touch.touches[i];
    121     if (WebTouchPointStateToEventType(point.state) != type)
    122       continue;
    123     // In aura, the touch-event needs to be in the screen coordinate, since the
    124     // touch-event is routed to RootWindow first. In Windows, on the other hand,
    125     // the touch-event is dispatched directly to the gesture-recognizer, so the
    126     // location needs to be in the local coordinate space.
    127 #if defined(USE_AURA)
    128     gfx::Point location;
    129     if (coordinate_system == LOCAL_COORDINATES)
    130       location = gfx::Point(point.position.x, point.position.y);
    131     else
    132       location = gfx::Point(point.screenPosition.x, point.screenPosition.y);
    133 #else
    134     gfx::Point location(point.position.x, point.position.y);
    135 #endif
    136     ui::TouchEvent* uievent = new ui::TouchEvent(type,
    137           location,
    138           flags,
    139           point.id,
    140           timestamp,
    141           point.radiusX,
    142           point.radiusY,
    143           point.rotationAngle,
    144           point.force);
    145     uievent->set_latency(touch_with_latency.latency);
    146     list->push_back(uievent);
    147   }
    148   return true;
    149 }
    150 
    151 blink::WebGestureEvent MakeWebGestureEventFromUIEvent(
    152     const ui::GestureEvent& event) {
    153   blink::WebGestureEvent gesture_event;
    154 
    155   switch (event.type()) {
    156     case ui::ET_GESTURE_TAP:
    157       gesture_event.type = blink::WebInputEvent::GestureTap;
    158       gesture_event.data.tap.tapCount = event.details().tap_count();
    159       gesture_event.data.tap.width = event.details().bounding_box().width();
    160       gesture_event.data.tap.height = event.details().bounding_box().height();
    161       break;
    162     case ui::ET_GESTURE_TAP_DOWN:
    163       gesture_event.type = blink::WebInputEvent::GestureTapDown;
    164       gesture_event.data.tapDown.width =
    165           event.details().bounding_box().width();
    166       gesture_event.data.tapDown.height =
    167           event.details().bounding_box().height();
    168       break;
    169     case ui::ET_GESTURE_SHOW_PRESS:
    170       gesture_event.type = blink::WebInputEvent::GestureShowPress;
    171       gesture_event.data.showPress.width =
    172           event.details().bounding_box().width();
    173       gesture_event.data.showPress.height =
    174           event.details().bounding_box().height();
    175       break;
    176     case ui::ET_GESTURE_TAP_CANCEL:
    177       gesture_event.type = blink::WebInputEvent::GestureTapCancel;
    178       break;
    179     case ui::ET_GESTURE_SCROLL_BEGIN:
    180       gesture_event.type = blink::WebInputEvent::GestureScrollBegin;
    181       break;
    182     case ui::ET_GESTURE_SCROLL_UPDATE:
    183       gesture_event.type = blink::WebInputEvent::GestureScrollUpdate;
    184       gesture_event.data.scrollUpdate.deltaX = event.details().scroll_x();
    185       gesture_event.data.scrollUpdate.deltaY = event.details().scroll_y();
    186       break;
    187     case ui::ET_GESTURE_SCROLL_END:
    188       gesture_event.type = blink::WebInputEvent::GestureScrollEnd;
    189       break;
    190     case ui::ET_GESTURE_PINCH_BEGIN:
    191       gesture_event.type = blink::WebInputEvent::GesturePinchBegin;
    192       break;
    193     case ui::ET_GESTURE_PINCH_UPDATE:
    194       gesture_event.type = blink::WebInputEvent::GesturePinchUpdate;
    195       gesture_event.data.pinchUpdate.scale = event.details().scale();
    196       break;
    197     case ui::ET_GESTURE_PINCH_END:
    198       gesture_event.type = blink::WebInputEvent::GesturePinchEnd;
    199       break;
    200     case ui::ET_SCROLL_FLING_START:
    201       gesture_event.type = blink::WebInputEvent::GestureFlingStart;
    202       gesture_event.data.flingStart.velocityX = event.details().velocity_x();
    203       gesture_event.data.flingStart.velocityY = event.details().velocity_y();
    204       break;
    205     case ui::ET_SCROLL_FLING_CANCEL:
    206       gesture_event.type = blink::WebInputEvent::GestureFlingCancel;
    207       break;
    208     case ui::ET_GESTURE_LONG_PRESS:
    209       gesture_event.type = blink::WebInputEvent::GestureLongPress;
    210       gesture_event.data.longPress.width =
    211           event.details().bounding_box().width();
    212       gesture_event.data.longPress.height =
    213           event.details().bounding_box().height();
    214       break;
    215     case ui::ET_GESTURE_LONG_TAP:
    216       gesture_event.type = blink::WebInputEvent::GestureLongTap;
    217       gesture_event.data.longPress.width =
    218           event.details().bounding_box().width();
    219       gesture_event.data.longPress.height =
    220           event.details().bounding_box().height();
    221       break;
    222     case ui::ET_GESTURE_TWO_FINGER_TAP:
    223       gesture_event.type = blink::WebInputEvent::GestureTwoFingerTap;
    224       gesture_event.data.twoFingerTap.firstFingerWidth =
    225           event.details().first_finger_width();
    226       gesture_event.data.twoFingerTap.firstFingerHeight =
    227           event.details().first_finger_height();
    228       break;
    229     case ui::ET_GESTURE_BEGIN:
    230     case ui::ET_GESTURE_END:
    231     case ui::ET_GESTURE_MULTIFINGER_SWIPE:
    232       gesture_event.type = blink::WebInputEvent::Undefined;
    233       break;
    234     default:
    235       NOTREACHED() << "Unknown gesture type: " << event.type();
    236   }
    237 
    238   gesture_event.sourceDevice = blink::WebGestureEvent::Touchscreen;
    239   gesture_event.modifiers = EventFlagsToWebEventModifiers(event.flags());
    240   gesture_event.timeStampSeconds = event.time_stamp().InSecondsF();
    241 
    242   return gesture_event;
    243 }
    244 
    245 int EventFlagsToWebEventModifiers(int flags) {
    246   int modifiers = 0;
    247 
    248   if (flags & ui::EF_SHIFT_DOWN)
    249     modifiers |= blink::WebInputEvent::ShiftKey;
    250   if (flags & ui::EF_CONTROL_DOWN)
    251     modifiers |= blink::WebInputEvent::ControlKey;
    252   if (flags & ui::EF_ALT_DOWN)
    253     modifiers |= blink::WebInputEvent::AltKey;
    254   // TODO(beng): MetaKey/META_MASK
    255   if (flags & ui::EF_LEFT_MOUSE_BUTTON)
    256     modifiers |= blink::WebInputEvent::LeftButtonDown;
    257   if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
    258     modifiers |= blink::WebInputEvent::MiddleButtonDown;
    259   if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
    260     modifiers |= blink::WebInputEvent::RightButtonDown;
    261   if (flags & ui::EF_CAPS_LOCK_DOWN)
    262     modifiers |= blink::WebInputEvent::CapsLockOn;
    263   return modifiers;
    264 }
    265 
    266 blink::WebTouchPoint* UpdateWebTouchEventFromUIEvent(
    267     const ui::TouchEvent& event,
    268     blink::WebTouchEvent* web_event) {
    269   blink::WebTouchPoint* point = NULL;
    270   switch (event.type()) {
    271     case ui::ET_TOUCH_PRESSED:
    272       // Add a new touch point.
    273       if (web_event->touchesLength < blink::WebTouchEvent::touchesLengthCap) {
    274         point = &web_event->touches[web_event->touchesLength++];
    275         point->id = event.touch_id();
    276       }
    277       break;
    278     case ui::ET_TOUCH_RELEASED:
    279     case ui::ET_TOUCH_CANCELLED:
    280     case ui::ET_TOUCH_MOVED: {
    281       // The touch point should have been added to the event from an earlier
    282       // _PRESSED event. So find that.
    283       // At the moment, only a maximum of 4 touch-points are allowed. So a
    284       // simple loop should be sufficient.
    285       for (unsigned i = 0; i < web_event->touchesLength; ++i) {
    286         point = web_event->touches + i;
    287         if (point->id == event.touch_id())
    288           break;
    289         point = NULL;
    290       }
    291       break;
    292     }
    293     default:
    294       DLOG(WARNING) << "Unknown touch event " << event.type();
    295       break;
    296   }
    297 
    298   if (!point)
    299     return NULL;
    300 
    301   // The spec requires the radii values to be positive (and 1 when unknown).
    302   point->radiusX = std::max(1.f, event.radius_x());
    303   point->radiusY = std::max(1.f, event.radius_y());
    304   point->rotationAngle = event.rotation_angle();
    305   point->force = event.force();
    306 
    307   // Update the location and state of the point.
    308   point->state = TouchPointStateFromEvent(event);
    309   if (point->state == blink::WebTouchPoint::StateMoved) {
    310     // It is possible for badly written touch drivers to emit Move events even
    311     // when the touch location hasn't changed. In such cases, consume the event
    312     // and pretend nothing happened.
    313     if (point->position.x == event.x() && point->position.y == event.y())
    314       return NULL;
    315   }
    316   point->position.x = event.x();
    317   point->position.y = event.y();
    318 
    319   const gfx::Point root_point = event.root_location();
    320   point->screenPosition.x = root_point.x();
    321   point->screenPosition.y = root_point.y();
    322 
    323   // Mark the rest of the points as stationary.
    324   for (unsigned i = 0; i < web_event->touchesLength; ++i) {
    325     blink::WebTouchPoint* iter = web_event->touches + i;
    326     if (iter != point)
    327       iter->state = blink::WebTouchPoint::StateStationary;
    328   }
    329 
    330   // Update the type of the touch event.
    331   web_event->type = TouchEventTypeFromEvent(event);
    332   web_event->timeStampSeconds = event.time_stamp().InSecondsF();
    333   web_event->modifiers = EventFlagsToWebEventModifiers(event.flags());
    334 
    335   return point;
    336 }
    337 
    338 }  // namespace content
    339