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