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