Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / events / blink / blink_event_util.cc
blobb389600f23b33709d46b444a4dcb420368403f6b
1 // Copyright 2015 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.
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
8 #include "ui/events/blink/blink_event_util.h"
10 #include <cmath>
12 #include "base/time/time.h"
13 #include "third_party/WebKit/public/web/WebInputEvent.h"
14 #include "ui/events/event_constants.h"
15 #include "ui/events/gesture_detection/gesture_event_data.h"
16 #include "ui/events/gesture_detection/motion_event.h"
17 #include "ui/events/gesture_event_details.h"
18 #include "ui/gfx/geometry/safe_integer_conversions.h"
20 using blink::WebGestureEvent;
21 using blink::WebInputEvent;
22 using blink::WebTouchEvent;
23 using blink::WebTouchPoint;
25 namespace ui {
26 namespace {
28 WebInputEvent::Type ToWebInputEventType(MotionEvent::Action action) {
29 switch (action) {
30 case MotionEvent::ACTION_DOWN:
31 return WebInputEvent::TouchStart;
32 case MotionEvent::ACTION_MOVE:
33 return WebInputEvent::TouchMove;
34 case MotionEvent::ACTION_UP:
35 return WebInputEvent::TouchEnd;
36 case MotionEvent::ACTION_CANCEL:
37 return WebInputEvent::TouchCancel;
38 case MotionEvent::ACTION_POINTER_DOWN:
39 return WebInputEvent::TouchStart;
40 case MotionEvent::ACTION_POINTER_UP:
41 return WebInputEvent::TouchEnd;
43 NOTREACHED() << "Invalid MotionEvent::Action.";
44 return WebInputEvent::Undefined;
47 // Note that |is_action_pointer| is meaningful only in the context of
48 // |ACTION_POINTER_UP| and |ACTION_POINTER_DOWN|; other actions map directly to
49 // WebTouchPoint::State.
50 WebTouchPoint::State ToWebTouchPointState(const MotionEvent& event,
51 size_t pointer_index) {
52 switch (event.GetAction()) {
53 case MotionEvent::ACTION_DOWN:
54 return WebTouchPoint::StatePressed;
55 case MotionEvent::ACTION_MOVE:
56 return WebTouchPoint::StateMoved;
57 case MotionEvent::ACTION_UP:
58 return WebTouchPoint::StateReleased;
59 case MotionEvent::ACTION_CANCEL:
60 return WebTouchPoint::StateCancelled;
61 case MotionEvent::ACTION_POINTER_DOWN:
62 return static_cast<int>(pointer_index) == event.GetActionIndex()
63 ? WebTouchPoint::StatePressed
64 : WebTouchPoint::StateStationary;
65 case MotionEvent::ACTION_POINTER_UP:
66 return static_cast<int>(pointer_index) == event.GetActionIndex()
67 ? WebTouchPoint::StateReleased
68 : WebTouchPoint::StateStationary;
70 NOTREACHED() << "Invalid MotionEvent::Action.";
71 return WebTouchPoint::StateUndefined;
74 WebTouchPoint CreateWebTouchPoint(const MotionEvent& event,
75 size_t pointer_index) {
76 WebTouchPoint touch;
77 touch.id = event.GetPointerId(pointer_index);
78 touch.state = ToWebTouchPointState(event, pointer_index);
79 touch.position.x = event.GetX(pointer_index);
80 touch.position.y = event.GetY(pointer_index);
81 touch.screenPosition.x = event.GetRawX(pointer_index);
82 touch.screenPosition.y = event.GetRawY(pointer_index);
84 // A note on touch ellipse specifications:
86 // Android MotionEvent provides the major and minor axes of the touch ellipse,
87 // as well as the orientation of the major axis clockwise from vertical, in
88 // radians. See:
89 // http://developer.android.com/reference/android/view/MotionEvent.html
91 // The proposed extension to W3C Touch Events specifies the touch ellipse
92 // using two radii along x- & y-axes and a positive acute rotation angle in
93 // degrees. See:
94 // http://dvcs.w3.org/hg/webevents/raw-file/default/touchevents.html
96 float major_radius = event.GetTouchMajor(pointer_index) / 2.f;
97 float minor_radius = event.GetTouchMinor(pointer_index) / 2.f;
99 DCHECK_LE(minor_radius, major_radius);
100 DCHECK_IMPLIES(major_radius, minor_radius);
102 float orientation_deg = event.GetOrientation(pointer_index) * 180.f / M_PI;
103 DCHECK_GE(major_radius, 0);
104 DCHECK_GE(minor_radius, 0);
105 DCHECK_GE(major_radius, minor_radius);
106 if (event.GetToolType(pointer_index) == MotionEvent::TOOL_TYPE_STYLUS) {
107 // Orientation lies in [-180, 180] for a stylus. Normalise to [-90, 90).
108 // Allow a small bound tolerance to account for floating point conversion.
109 // TODO(e_hakkinen): crbug.com/493728: Pass also unaltered orientation
110 // to touch in order not to lose quadrant information.
111 DCHECK_GT(orientation_deg, -180.01f);
112 DCHECK_LT(orientation_deg, 180.01f);
113 if (orientation_deg >= 90.f)
114 orientation_deg -= 180.f;
115 else if (orientation_deg < -90.f)
116 orientation_deg += 180.f;
117 } else {
118 // Orientation lies in [-90, 90] for a touch. Normalise to [-90, 90).
119 // Allow a small bound tolerance to account for floating point conversion.
120 DCHECK_GT(orientation_deg, -90.01f);
121 DCHECK_LT(orientation_deg, 90.01f);
122 if (orientation_deg >= 90.f)
123 orientation_deg -= 180.f;
125 if (orientation_deg >= 0) {
126 // The case orientation_deg == 0 is handled here on purpose: although the
127 // 'else' block is equivalent in this case, we want to pass the 0 value
128 // unchanged (and 0 is the default value for many devices that don't
129 // report elliptical touches).
130 touch.radiusX = minor_radius;
131 touch.radiusY = major_radius;
132 touch.rotationAngle = orientation_deg;
133 } else {
134 touch.radiusX = major_radius;
135 touch.radiusY = minor_radius;
136 touch.rotationAngle = orientation_deg + 90;
139 touch.force = event.GetPressure(pointer_index);
141 return touch;
144 } // namespace
146 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
147 const MotionEvent& event,
148 bool may_cause_scrolling) {
149 static_assert(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) ==
150 static_cast<int>(blink::WebTouchEvent::touchesLengthCap),
151 "inconsistent maximum number of active touch points");
153 blink::WebTouchEvent result;
155 result.type = ToWebInputEventType(event.GetAction());
156 result.cancelable = (result.type != WebInputEvent::TouchCancel);
157 result.timeStampSeconds =
158 (event.GetEventTime() - base::TimeTicks()).InSecondsF(),
159 result.causesScrollingIfUncanceled = may_cause_scrolling;
160 result.modifiers = EventFlagsToWebEventModifiers(event.GetFlags());
161 DCHECK_NE(event.GetUniqueEventId(), 0U);
162 result.uniqueTouchEventId = event.GetUniqueEventId();
163 result.touchesLength =
164 std::min(static_cast<unsigned>(event.GetPointerCount()),
165 static_cast<unsigned>(WebTouchEvent::touchesLengthCap));
166 DCHECK_GT(result.touchesLength, 0U);
168 for (size_t i = 0; i < result.touchesLength; ++i)
169 result.touches[i] = CreateWebTouchPoint(event, i);
171 return result;
174 int EventFlagsToWebEventModifiers(int flags) {
175 int modifiers = 0;
177 if (flags & EF_SHIFT_DOWN)
178 modifiers |= blink::WebInputEvent::ShiftKey;
179 if (flags & EF_CONTROL_DOWN)
180 modifiers |= blink::WebInputEvent::ControlKey;
181 if (flags & EF_ALT_DOWN)
182 modifiers |= blink::WebInputEvent::AltKey;
183 if (flags & EF_COMMAND_DOWN)
184 modifiers |= blink::WebInputEvent::MetaKey;
186 if (flags & EF_LEFT_MOUSE_BUTTON)
187 modifiers |= blink::WebInputEvent::LeftButtonDown;
188 if (flags & EF_MIDDLE_MOUSE_BUTTON)
189 modifiers |= blink::WebInputEvent::MiddleButtonDown;
190 if (flags & EF_RIGHT_MOUSE_BUTTON)
191 modifiers |= blink::WebInputEvent::RightButtonDown;
192 if (flags & EF_CAPS_LOCK_DOWN)
193 modifiers |= blink::WebInputEvent::CapsLockOn;
194 if (flags & EF_IS_REPEAT)
195 modifiers |= blink::WebInputEvent::IsAutoRepeat;
197 return modifiers;
200 WebGestureEvent CreateWebGestureEvent(const GestureEventDetails& details,
201 base::TimeDelta timestamp,
202 const gfx::PointF& location,
203 const gfx::PointF& raw_location,
204 int flags) {
205 WebGestureEvent gesture;
206 gesture.timeStampSeconds = timestamp.InSecondsF();
207 gesture.x = gfx::ToFlooredInt(location.x());
208 gesture.y = gfx::ToFlooredInt(location.y());
209 gesture.globalX = gfx::ToFlooredInt(raw_location.x());
210 gesture.globalY = gfx::ToFlooredInt(raw_location.y());
211 gesture.modifiers = EventFlagsToWebEventModifiers(flags);
212 gesture.sourceDevice = blink::WebGestureDeviceTouchscreen;
214 switch (details.type()) {
215 case ET_GESTURE_SHOW_PRESS:
216 gesture.type = WebInputEvent::GestureShowPress;
217 gesture.data.showPress.width = details.bounding_box_f().width();
218 gesture.data.showPress.height = details.bounding_box_f().height();
219 break;
220 case ET_GESTURE_DOUBLE_TAP:
221 gesture.type = WebInputEvent::GestureDoubleTap;
222 DCHECK_EQ(1, details.tap_count());
223 gesture.data.tap.tapCount = details.tap_count();
224 gesture.data.tap.width = details.bounding_box_f().width();
225 gesture.data.tap.height = details.bounding_box_f().height();
226 break;
227 case ET_GESTURE_TAP:
228 gesture.type = WebInputEvent::GestureTap;
229 DCHECK_GE(details.tap_count(), 1);
230 gesture.data.tap.tapCount = details.tap_count();
231 gesture.data.tap.width = details.bounding_box_f().width();
232 gesture.data.tap.height = details.bounding_box_f().height();
233 break;
234 case ET_GESTURE_TAP_UNCONFIRMED:
235 gesture.type = WebInputEvent::GestureTapUnconfirmed;
236 DCHECK_EQ(1, details.tap_count());
237 gesture.data.tap.tapCount = details.tap_count();
238 gesture.data.tap.width = details.bounding_box_f().width();
239 gesture.data.tap.height = details.bounding_box_f().height();
240 break;
241 case ET_GESTURE_LONG_PRESS:
242 gesture.type = WebInputEvent::GestureLongPress;
243 gesture.data.longPress.width = details.bounding_box_f().width();
244 gesture.data.longPress.height = details.bounding_box_f().height();
245 break;
246 case ET_GESTURE_LONG_TAP:
247 gesture.type = WebInputEvent::GestureLongTap;
248 gesture.data.longPress.width = details.bounding_box_f().width();
249 gesture.data.longPress.height = details.bounding_box_f().height();
250 break;
251 case ET_GESTURE_TWO_FINGER_TAP:
252 gesture.type = blink::WebInputEvent::GestureTwoFingerTap;
253 gesture.data.twoFingerTap.firstFingerWidth = details.first_finger_width();
254 gesture.data.twoFingerTap.firstFingerHeight =
255 details.first_finger_height();
256 break;
257 case ET_GESTURE_SCROLL_BEGIN:
258 gesture.type = WebInputEvent::GestureScrollBegin;
259 gesture.data.scrollBegin.deltaXHint = details.scroll_x_hint();
260 gesture.data.scrollBegin.deltaYHint = details.scroll_y_hint();
261 break;
262 case ET_GESTURE_SCROLL_UPDATE:
263 gesture.type = WebInputEvent::GestureScrollUpdate;
264 gesture.data.scrollUpdate.deltaX = details.scroll_x();
265 gesture.data.scrollUpdate.deltaY = details.scroll_y();
266 gesture.data.scrollUpdate.previousUpdateInSequencePrevented =
267 details.previous_scroll_update_in_sequence_prevented();
268 break;
269 case ET_GESTURE_SCROLL_END:
270 gesture.type = WebInputEvent::GestureScrollEnd;
271 break;
272 case ET_SCROLL_FLING_START:
273 gesture.type = WebInputEvent::GestureFlingStart;
274 gesture.data.flingStart.velocityX = details.velocity_x();
275 gesture.data.flingStart.velocityY = details.velocity_y();
276 break;
277 case ET_SCROLL_FLING_CANCEL:
278 gesture.type = WebInputEvent::GestureFlingCancel;
279 break;
280 case ET_GESTURE_PINCH_BEGIN:
281 gesture.type = WebInputEvent::GesturePinchBegin;
282 break;
283 case ET_GESTURE_PINCH_UPDATE:
284 gesture.type = WebInputEvent::GesturePinchUpdate;
285 gesture.data.pinchUpdate.scale = details.scale();
286 break;
287 case ET_GESTURE_PINCH_END:
288 gesture.type = WebInputEvent::GesturePinchEnd;
289 break;
290 case ET_GESTURE_TAP_CANCEL:
291 gesture.type = WebInputEvent::GestureTapCancel;
292 break;
293 case ET_GESTURE_TAP_DOWN:
294 gesture.type = WebInputEvent::GestureTapDown;
295 gesture.data.tapDown.width = details.bounding_box_f().width();
296 gesture.data.tapDown.height = details.bounding_box_f().height();
297 break;
298 case ET_GESTURE_BEGIN:
299 case ET_GESTURE_END:
300 case ET_GESTURE_SWIPE:
301 // The caller is responsible for discarding these gestures appropriately.
302 gesture.type = WebInputEvent::Undefined;
303 break;
304 default:
305 NOTREACHED() << "EventType provided wasn't a valid gesture event: "
306 << details.type();
309 return gesture;
312 WebGestureEvent CreateWebGestureEventFromGestureEventData(
313 const GestureEventData& data) {
314 return CreateWebGestureEvent(data.details, data.time - base::TimeTicks(),
315 gfx::PointF(data.x, data.y),
316 gfx::PointF(data.raw_x, data.raw_y), data.flags);
319 } // namespace ui