• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WebModifiersToUIFlags(int modifiers)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 
WebTouchPointStateToEventType(blink::WebTouchPoint::State state)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 
TouchPointStateFromEvent(const ui::TouchEvent & event)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 
TouchEventTypeFromEvent(const ui::TouchEvent & event)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 
MakeUITouchEventsFromWebTouchEvents(const TouchEventWithLatencyInfo & touch_with_latency,ScopedVector<ui::TouchEvent> * list,TouchEventCoordinateSystem coordinate_system)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 
MakeWebGestureEventFromUIEvent(const ui::GestureEvent & event)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 
EventFlagsToWebEventModifiers(int flags)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 
UpdateWebTouchEventFromUIEvent(const ui::TouchEvent & event,blink::WebTouchEvent * web_event)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