Fix search results being clipped in app list.
[chromium-blink-merge.git] / ui / events / blink / blink_event_util.cc
blob835a82b243640998d7c35ad7a64114c2800d440c
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 // Allow a small bound tolerance to account for floating point conversion.
107 DCHECK_GT(orientation_deg, -90.01f);
108 DCHECK_LT(orientation_deg, 90.01f);
109 if (orientation_deg >= 0) {
110 // The case orientation_deg == 0 is handled here on purpose: although the
111 // 'else' block is equivalent in this case, we want to pass the 0 value
112 // unchanged (and 0 is the default value for many devices that don't
113 // report elliptical touches).
114 touch.radiusX = minor_radius;
115 touch.radiusY = major_radius;
116 touch.rotationAngle = orientation_deg;
117 } else {
118 touch.radiusX = major_radius;
119 touch.radiusY = minor_radius;
120 touch.rotationAngle = orientation_deg + 90;
123 touch.force = event.GetPressure(pointer_index);
125 return touch;
128 } // namespace
130 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
131 const MotionEvent& event,
132 bool may_cause_scrolling) {
133 static_assert(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) ==
134 static_cast<int>(blink::WebTouchEvent::touchesLengthCap),
135 "inconsistent maximum number of active touch points");
137 blink::WebTouchEvent result;
139 result.type = ToWebInputEventType(event.GetAction());
140 result.cancelable = (result.type != WebInputEvent::TouchCancel);
141 result.timeStampSeconds =
142 (event.GetEventTime() - base::TimeTicks()).InSecondsF(),
143 result.causesScrollingIfUncanceled = may_cause_scrolling;
144 result.modifiers = EventFlagsToWebEventModifiers(event.GetFlags());
145 result.touchesLength =
146 std::min(static_cast<unsigned>(event.GetPointerCount()),
147 static_cast<unsigned>(WebTouchEvent::touchesLengthCap));
148 DCHECK_GT(result.touchesLength, 0U);
150 for (size_t i = 0; i < result.touchesLength; ++i)
151 result.touches[i] = CreateWebTouchPoint(event, i);
153 return result;
156 int EventFlagsToWebEventModifiers(int flags) {
157 int modifiers = 0;
159 if (flags & EF_SHIFT_DOWN)
160 modifiers |= blink::WebInputEvent::ShiftKey;
161 if (flags & EF_CONTROL_DOWN)
162 modifiers |= blink::WebInputEvent::ControlKey;
163 if (flags & EF_ALT_DOWN)
164 modifiers |= blink::WebInputEvent::AltKey;
165 if (flags & EF_COMMAND_DOWN)
166 modifiers |= blink::WebInputEvent::MetaKey;
168 if (flags & EF_LEFT_MOUSE_BUTTON)
169 modifiers |= blink::WebInputEvent::LeftButtonDown;
170 if (flags & EF_MIDDLE_MOUSE_BUTTON)
171 modifiers |= blink::WebInputEvent::MiddleButtonDown;
172 if (flags & EF_RIGHT_MOUSE_BUTTON)
173 modifiers |= blink::WebInputEvent::RightButtonDown;
174 if (flags & EF_CAPS_LOCK_DOWN)
175 modifiers |= blink::WebInputEvent::CapsLockOn;
176 if (flags & EF_IS_REPEAT)
177 modifiers |= blink::WebInputEvent::IsAutoRepeat;
178 if (flags & EF_NUMPAD_KEY)
179 modifiers |= blink::WebInputEvent::IsKeyPad;
181 return modifiers;
184 WebGestureEvent CreateWebGestureEvent(const GestureEventDetails& details,
185 base::TimeDelta timestamp,
186 const gfx::PointF& location,
187 const gfx::PointF& raw_location,
188 int flags) {
189 WebGestureEvent gesture;
190 gesture.timeStampSeconds = timestamp.InSecondsF();
191 gesture.x = gfx::ToFlooredInt(location.x());
192 gesture.y = gfx::ToFlooredInt(location.y());
193 gesture.globalX = gfx::ToFlooredInt(raw_location.x());
194 gesture.globalY = gfx::ToFlooredInt(raw_location.y());
195 gesture.modifiers = EventFlagsToWebEventModifiers(flags);
196 gesture.sourceDevice = blink::WebGestureDeviceTouchscreen;
198 switch (details.type()) {
199 case ET_GESTURE_SHOW_PRESS:
200 gesture.type = WebInputEvent::GestureShowPress;
201 gesture.data.showPress.width = details.bounding_box_f().width();
202 gesture.data.showPress.height = details.bounding_box_f().height();
203 break;
204 case ET_GESTURE_DOUBLE_TAP:
205 gesture.type = WebInputEvent::GestureDoubleTap;
206 DCHECK_EQ(1, details.tap_count());
207 gesture.data.tap.tapCount = details.tap_count();
208 gesture.data.tap.width = details.bounding_box_f().width();
209 gesture.data.tap.height = details.bounding_box_f().height();
210 break;
211 case ET_GESTURE_TAP:
212 gesture.type = WebInputEvent::GestureTap;
213 DCHECK_GE(details.tap_count(), 1);
214 gesture.data.tap.tapCount = details.tap_count();
215 gesture.data.tap.width = details.bounding_box_f().width();
216 gesture.data.tap.height = details.bounding_box_f().height();
217 break;
218 case ET_GESTURE_TAP_UNCONFIRMED:
219 gesture.type = WebInputEvent::GestureTapUnconfirmed;
220 DCHECK_EQ(1, details.tap_count());
221 gesture.data.tap.tapCount = details.tap_count();
222 gesture.data.tap.width = details.bounding_box_f().width();
223 gesture.data.tap.height = details.bounding_box_f().height();
224 break;
225 case ET_GESTURE_LONG_PRESS:
226 gesture.type = WebInputEvent::GestureLongPress;
227 gesture.data.longPress.width = details.bounding_box_f().width();
228 gesture.data.longPress.height = details.bounding_box_f().height();
229 break;
230 case ET_GESTURE_LONG_TAP:
231 gesture.type = WebInputEvent::GestureLongTap;
232 gesture.data.longPress.width = details.bounding_box_f().width();
233 gesture.data.longPress.height = details.bounding_box_f().height();
234 break;
235 case ET_GESTURE_TWO_FINGER_TAP:
236 gesture.type = blink::WebInputEvent::GestureTwoFingerTap;
237 gesture.data.twoFingerTap.firstFingerWidth = details.first_finger_width();
238 gesture.data.twoFingerTap.firstFingerHeight =
239 details.first_finger_height();
240 break;
241 case ET_GESTURE_SCROLL_BEGIN:
242 gesture.type = WebInputEvent::GestureScrollBegin;
243 gesture.data.scrollBegin.deltaXHint = details.scroll_x_hint();
244 gesture.data.scrollBegin.deltaYHint = details.scroll_y_hint();
245 break;
246 case ET_GESTURE_SCROLL_UPDATE:
247 gesture.type = WebInputEvent::GestureScrollUpdate;
248 gesture.data.scrollUpdate.deltaX = details.scroll_x();
249 gesture.data.scrollUpdate.deltaY = details.scroll_y();
250 gesture.data.scrollUpdate.previousUpdateInSequencePrevented =
251 details.previous_scroll_update_in_sequence_prevented();
252 break;
253 case ET_GESTURE_SCROLL_END:
254 gesture.type = WebInputEvent::GestureScrollEnd;
255 break;
256 case ET_SCROLL_FLING_START:
257 gesture.type = WebInputEvent::GestureFlingStart;
258 gesture.data.flingStart.velocityX = details.velocity_x();
259 gesture.data.flingStart.velocityY = details.velocity_y();
260 break;
261 case ET_SCROLL_FLING_CANCEL:
262 gesture.type = WebInputEvent::GestureFlingCancel;
263 break;
264 case ET_GESTURE_PINCH_BEGIN:
265 gesture.type = WebInputEvent::GesturePinchBegin;
266 break;
267 case ET_GESTURE_PINCH_UPDATE:
268 gesture.type = WebInputEvent::GesturePinchUpdate;
269 gesture.data.pinchUpdate.scale = details.scale();
270 break;
271 case ET_GESTURE_PINCH_END:
272 gesture.type = WebInputEvent::GesturePinchEnd;
273 break;
274 case ET_GESTURE_TAP_CANCEL:
275 gesture.type = WebInputEvent::GestureTapCancel;
276 break;
277 case ET_GESTURE_TAP_DOWN:
278 gesture.type = WebInputEvent::GestureTapDown;
279 gesture.data.tapDown.width = details.bounding_box_f().width();
280 gesture.data.tapDown.height = details.bounding_box_f().height();
281 break;
282 case ET_GESTURE_BEGIN:
283 case ET_GESTURE_END:
284 case ET_GESTURE_SWIPE:
285 // The caller is responsible for discarding these gestures appropriately.
286 gesture.type = WebInputEvent::Undefined;
287 break;
288 default:
289 NOTREACHED() << "EventType provided wasn't a valid gesture event: "
290 << details.type();
293 return gesture;
296 WebGestureEvent CreateWebGestureEventFromGestureEventData(
297 const GestureEventData& data) {
298 return CreateWebGestureEvent(data.details, data.time - base::TimeTicks(),
299 gfx::PointF(data.x, data.y),
300 gfx::PointF(data.raw_x, data.raw_y), data.flags);
303 } // namespace ui