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