- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / ui_events_helper.cc
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 & WebKit::WebInputEvent::ShiftKey)
17     flags |= ui::EF_SHIFT_DOWN;
18   if (modifiers & WebKit::WebInputEvent::ControlKey)
19     flags |= ui::EF_CONTROL_DOWN;
20   if (modifiers & WebKit::WebInputEvent::AltKey)
21     flags |= ui::EF_ALT_DOWN;
22
23   if (modifiers & WebKit::WebInputEvent::LeftButtonDown)
24     flags |= ui::EF_LEFT_MOUSE_BUTTON;
25   if (modifiers & WebKit::WebInputEvent::RightButtonDown)
26     flags |= ui::EF_RIGHT_MOUSE_BUTTON;
27   if (modifiers & WebKit::WebInputEvent::MiddleButtonDown)
28     flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
29
30   if (modifiers & WebKit::WebInputEvent::CapsLockOn)
31     flags |= ui::EF_CAPS_LOCK_DOWN;
32
33   return flags;
34 }
35
36 ui::EventType WebTouchPointStateToEventType(
37     WebKit::WebTouchPoint::State state) {
38   switch (state) {
39     case WebKit::WebTouchPoint::StateReleased:
40       return ui::ET_TOUCH_RELEASED;
41
42     case WebKit::WebTouchPoint::StatePressed:
43       return ui::ET_TOUCH_PRESSED;
44
45     case WebKit::WebTouchPoint::StateMoved:
46       return ui::ET_TOUCH_MOVED;
47
48     case WebKit::WebTouchPoint::StateCancelled:
49       return ui::ET_TOUCH_CANCELLED;
50
51     default:
52       return ui::ET_UNKNOWN;
53   }
54 }
55
56 WebKit::WebTouchPoint::State TouchPointStateFromEvent(
57     const ui::TouchEvent& event) {
58   switch (event.type()) {
59     case ui::ET_TOUCH_PRESSED:
60       return WebKit::WebTouchPoint::StatePressed;
61     case ui::ET_TOUCH_RELEASED:
62       return WebKit::WebTouchPoint::StateReleased;
63     case ui::ET_TOUCH_MOVED:
64       return WebKit::WebTouchPoint::StateMoved;
65     case ui::ET_TOUCH_CANCELLED:
66       return WebKit::WebTouchPoint::StateCancelled;
67     default:
68       return WebKit::WebTouchPoint::StateUndefined;
69   }
70 }
71
72 WebKit::WebInputEvent::Type TouchEventTypeFromEvent(
73     const ui::TouchEvent& event) {
74   switch (event.type()) {
75     case ui::ET_TOUCH_PRESSED:
76       return WebKit::WebInputEvent::TouchStart;
77     case ui::ET_TOUCH_RELEASED:
78       return WebKit::WebInputEvent::TouchEnd;
79     case ui::ET_TOUCH_MOVED:
80       return WebKit::WebInputEvent::TouchMove;
81     case ui::ET_TOUCH_CANCELLED:
82       return WebKit::WebInputEvent::TouchCancel;
83     default:
84       return WebKit::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 WebKit::WebTouchEvent& touch = touch_with_latency.event;
97   ui::EventType type = ui::ET_UNKNOWN;
98   switch (touch.type) {
99     case WebKit::WebInputEvent::TouchStart:
100       type = ui::ET_TOUCH_PRESSED;
101       break;
102     case WebKit::WebInputEvent::TouchEnd:
103       type = ui::ET_TOUCH_RELEASED;
104       break;
105     case WebKit::WebInputEvent::TouchMove:
106       type = ui::ET_TOUCH_MOVED;
107       break;
108     case WebKit::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 WebKit::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 WebKit::WebGestureEvent MakeWebGestureEventFromUIEvent(
152     const ui::GestureEvent& event) {
153   WebKit::WebGestureEvent gesture_event;
154
155   switch (event.type()) {
156     case ui::ET_GESTURE_TAP:
157       gesture_event.type = WebKit::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 = WebKit::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 = WebKit::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 = WebKit::WebInputEvent::GestureTapCancel;
178       break;
179     case ui::ET_GESTURE_SCROLL_BEGIN:
180       gesture_event.type = WebKit::WebInputEvent::GestureScrollBegin;
181       break;
182     case ui::ET_GESTURE_SCROLL_UPDATE:
183       gesture_event.type = WebKit::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 = WebKit::WebInputEvent::GestureScrollEnd;
189       break;
190     case ui::ET_GESTURE_PINCH_BEGIN:
191       gesture_event.type = WebKit::WebInputEvent::GesturePinchBegin;
192       break;
193     case ui::ET_GESTURE_PINCH_UPDATE:
194       gesture_event.type = WebKit::WebInputEvent::GesturePinchUpdate;
195       gesture_event.data.pinchUpdate.scale = event.details().scale();
196       break;
197     case ui::ET_GESTURE_PINCH_END:
198       gesture_event.type = WebKit::WebInputEvent::GesturePinchEnd;
199       break;
200     case ui::ET_SCROLL_FLING_START:
201       gesture_event.type = WebKit::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 = WebKit::WebInputEvent::GestureFlingCancel;
207       break;
208     case ui::ET_GESTURE_LONG_PRESS:
209       gesture_event.type = WebKit::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 = WebKit::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 = WebKit::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 = WebKit::WebInputEvent::Undefined;
233       break;
234     default:
235       NOTREACHED() << "Unknown gesture type: " << event.type();
236   }
237
238   gesture_event.sourceDevice = WebKit::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 |= WebKit::WebInputEvent::ShiftKey;
250   if (flags & ui::EF_CONTROL_DOWN)
251     modifiers |= WebKit::WebInputEvent::ControlKey;
252   if (flags & ui::EF_ALT_DOWN)
253     modifiers |= WebKit::WebInputEvent::AltKey;
254   // TODO(beng): MetaKey/META_MASK
255   if (flags & ui::EF_LEFT_MOUSE_BUTTON)
256     modifiers |= WebKit::WebInputEvent::LeftButtonDown;
257   if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
258     modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
259   if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
260     modifiers |= WebKit::WebInputEvent::RightButtonDown;
261   if (flags & ui::EF_CAPS_LOCK_DOWN)
262     modifiers |= WebKit::WebInputEvent::CapsLockOn;
263   return modifiers;
264 }
265
266 WebKit::WebTouchPoint* UpdateWebTouchEventFromUIEvent(
267     const ui::TouchEvent& event,
268     WebKit::WebTouchEvent* web_event) {
269   WebKit::WebTouchPoint* point = NULL;
270   switch (event.type()) {
271     case ui::ET_TOUCH_PRESSED:
272       // Add a new touch point.
273       if (web_event->touchesLength < WebKit::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 == WebKit::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     WebKit::WebTouchPoint* iter = web_event->touches + i;
326     if (iter != point)
327       iter->state = WebKit::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