Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / common / input / web_input_event_traits.cc
blobfa9f433a1d7fd538a6e1cd23ce6e0424e98f6cd9
1 // Copyright 2013 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 #include "content/common/input/web_input_event_traits.h"
7 #include <bitset>
8 #include <limits>
10 #include "base/logging.h"
12 using blink::WebGestureEvent;
13 using blink::WebInputEvent;
14 using blink::WebKeyboardEvent;
15 using blink::WebMouseEvent;
16 using blink::WebMouseWheelEvent;
17 using blink::WebTouchEvent;
18 using std::numeric_limits;
20 namespace content {
21 namespace {
23 const int kInvalidTouchIndex = -1;
25 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce,
26 const WebKeyboardEvent& event) {
27 return false;
30 void Coalesce(const WebKeyboardEvent& event_to_coalesce,
31 WebKeyboardEvent* event) {
32 DCHECK(CanCoalesce(event_to_coalesce, *event));
35 bool CanCoalesce(const WebMouseEvent& event_to_coalesce,
36 const WebMouseEvent& event) {
37 return event.type == event_to_coalesce.type &&
38 event.type == WebInputEvent::MouseMove;
41 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) {
42 DCHECK(CanCoalesce(event_to_coalesce, *event));
43 // Accumulate movement deltas.
44 int x = event->movementX;
45 int y = event->movementY;
46 *event = event_to_coalesce;
47 event->movementX += x;
48 event->movementY += y;
51 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
52 const WebMouseWheelEvent& event) {
53 return event.modifiers == event_to_coalesce.modifiers &&
54 event.scrollByPage == event_to_coalesce.scrollByPage &&
55 event.phase == event_to_coalesce.phase &&
56 event.momentumPhase == event_to_coalesce.momentumPhase &&
57 event.hasPreciseScrollingDeltas ==
58 event_to_coalesce.hasPreciseScrollingDeltas;
61 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
62 return accelerated_delta * acceleration_ratio;
65 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
66 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
67 return 1.f;
68 return unaccelerated_delta / accelerated_delta;
71 void Coalesce(const WebMouseWheelEvent& event_to_coalesce,
72 WebMouseWheelEvent* event) {
73 DCHECK(CanCoalesce(event_to_coalesce, *event));
74 float unaccelerated_x =
75 GetUnacceleratedDelta(event->deltaX,
76 event->accelerationRatioX) +
77 GetUnacceleratedDelta(event_to_coalesce.deltaX,
78 event_to_coalesce.accelerationRatioX);
79 float unaccelerated_y =
80 GetUnacceleratedDelta(event->deltaY,
81 event->accelerationRatioY) +
82 GetUnacceleratedDelta(event_to_coalesce.deltaY,
83 event_to_coalesce.accelerationRatioY);
84 event->deltaX += event_to_coalesce.deltaX;
85 event->deltaY += event_to_coalesce.deltaY;
86 event->wheelTicksX += event_to_coalesce.wheelTicksX;
87 event->wheelTicksY += event_to_coalesce.wheelTicksY;
88 event->accelerationRatioX =
89 GetAccelerationRatio(event->deltaX, unaccelerated_x);
90 event->accelerationRatioY =
91 GetAccelerationRatio(event->deltaY, unaccelerated_y);
92 DCHECK_GE(event_to_coalesce.timeStampSeconds, event->timeStampSeconds);
93 event->timeStampSeconds = event_to_coalesce.timeStampSeconds;
96 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|.
97 int GetIndexOfTouchID(const WebTouchEvent& event, int id) {
98 for (unsigned i = 0; i < event.touchesLength; ++i) {
99 if (event.touches[i].id == id)
100 return i;
102 return kInvalidTouchIndex;
105 bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
106 const WebTouchEvent& event) {
107 if (event.type != event_to_coalesce.type ||
108 event.type != WebInputEvent::TouchMove ||
109 event.modifiers != event_to_coalesce.modifiers ||
110 event.touchesLength != event_to_coalesce.touchesLength ||
111 event.touchesLength > WebTouchEvent::touchesLengthCap)
112 return false;
114 COMPILE_ASSERT(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U,
115 suboptimal_touches_length_cap_size);
116 // Ensure that we have a 1-to-1 mapping of pointer ids between touches.
117 std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches(
118 (1 << event.touchesLength) - 1);
119 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) {
120 int event_touch_index =
121 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id);
122 if (event_touch_index == kInvalidTouchIndex)
123 return false;
124 if (!unmatched_event_touches[event_touch_index])
125 return false;
126 unmatched_event_touches[event_touch_index] = false;
128 return unmatched_event_touches.none();
131 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
132 DCHECK(CanCoalesce(event_to_coalesce, *event));
133 // The WebTouchPoints include absolute position information. So it is
134 // sufficient to simply replace the previous event with the new event->
135 // However, it is necessary to make sure that all the points have the
136 // correct state, i.e. the touch-points that moved in the last event, but
137 // didn't change in the current event, will have Stationary state. It is
138 // necessary to change them back to Moved state.
139 WebTouchEvent old_event = *event;
140 *event = event_to_coalesce;
141 for (unsigned i = 0; i < event->touchesLength; ++i) {
142 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id);
143 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved)
144 event->touches[i].state = blink::WebTouchPoint::StateMoved;
148 bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
149 const WebGestureEvent& event) {
150 if (event.type != event_to_coalesce.type ||
151 event.sourceDevice != event_to_coalesce.sourceDevice ||
152 event.modifiers != event_to_coalesce.modifiers)
153 return false;
155 if (event.type == WebInputEvent::GestureScrollUpdate)
156 return true;
158 // GesturePinchUpdate scales can be combined only if they share a focal point,
159 // e.g., with double-tap drag zoom.
160 if (event.type == WebInputEvent::GesturePinchUpdate &&
161 event.x == event_to_coalesce.x &&
162 event.y == event_to_coalesce.y)
163 return true;
165 return false;
168 void Coalesce(const WebGestureEvent& event_to_coalesce,
169 WebGestureEvent* event) {
170 DCHECK(CanCoalesce(event_to_coalesce, *event));
171 if (event->type == WebInputEvent::GestureScrollUpdate) {
172 event->data.scrollUpdate.deltaX +=
173 event_to_coalesce.data.scrollUpdate.deltaX;
174 event->data.scrollUpdate.deltaY +=
175 event_to_coalesce.data.scrollUpdate.deltaY;
176 } else if (event->type == WebInputEvent::GesturePinchUpdate) {
177 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale;
178 // Ensure the scale remains bounded above 0 and below Infinity so that
179 // we can reliably perform operations like log on the values.
180 if (event->data.pinchUpdate.scale < numeric_limits<float>::min())
181 event->data.pinchUpdate.scale = numeric_limits<float>::min();
182 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max())
183 event->data.pinchUpdate.scale = numeric_limits<float>::max();
187 struct WebInputEventSize {
188 template <class EventType>
189 bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const {
190 *type_size = sizeof(EventType);
191 return true;
195 struct WebInputEventClone {
196 template <class EventType>
197 bool Execute(const WebInputEvent& event,
198 ScopedWebInputEvent* scoped_event) const {
199 DCHECK_EQ(sizeof(EventType), event.size);
200 *scoped_event = ScopedWebInputEvent(
201 new EventType(static_cast<const EventType&>(event)));
202 return true;
206 struct WebInputEventDelete {
207 template <class EventType>
208 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const {
209 if (!event)
210 return false;
211 DCHECK_EQ(sizeof(EventType), event->size);
212 delete static_cast<EventType*>(event);
213 return true;
217 struct WebInputEventCanCoalesce {
218 template <class EventType>
219 bool Execute(const WebInputEvent& event_to_coalesce,
220 const WebInputEvent* event) const {
221 if (event_to_coalesce.type != event->type)
222 return false;
223 DCHECK_EQ(sizeof(EventType), event->size);
224 DCHECK_EQ(sizeof(EventType), event_to_coalesce.size);
225 return CanCoalesce(static_cast<const EventType&>(event_to_coalesce),
226 *static_cast<const EventType*>(event));
230 struct WebInputEventCoalesce {
231 template <class EventType>
232 bool Execute(const WebInputEvent& event_to_coalesce,
233 WebInputEvent* event) const {
234 Coalesce(static_cast<const EventType&>(event_to_coalesce),
235 static_cast<EventType*>(event));
236 return true;
240 template <typename Operator, typename ArgIn, typename ArgOut>
241 bool Apply(Operator op,
242 WebInputEvent::Type type,
243 const ArgIn& arg_in,
244 ArgOut* arg_out) {
245 if (WebInputEvent::isMouseEventType(type))
246 return op.template Execute<WebMouseEvent>(arg_in, arg_out);
247 else if (type == WebInputEvent::MouseWheel)
248 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out);
249 else if (WebInputEvent::isKeyboardEventType(type))
250 return op.template Execute<WebKeyboardEvent>(arg_in, arg_out);
251 else if (WebInputEvent::isTouchEventType(type))
252 return op.template Execute<WebTouchEvent>(arg_in, arg_out);
253 else if (WebInputEvent::isGestureEventType(type))
254 return op.template Execute<WebGestureEvent>(arg_in, arg_out);
256 NOTREACHED() << "Unknown webkit event type " << type;
257 return false;
260 } // namespace
262 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) {
263 #define CASE_TYPE(t) case WebInputEvent::t: return #t
264 switch(type) {
265 CASE_TYPE(Undefined);
266 CASE_TYPE(MouseDown);
267 CASE_TYPE(MouseUp);
268 CASE_TYPE(MouseMove);
269 CASE_TYPE(MouseEnter);
270 CASE_TYPE(MouseLeave);
271 CASE_TYPE(ContextMenu);
272 CASE_TYPE(MouseWheel);
273 CASE_TYPE(RawKeyDown);
274 CASE_TYPE(KeyDown);
275 CASE_TYPE(KeyUp);
276 CASE_TYPE(Char);
277 CASE_TYPE(GestureScrollBegin);
278 CASE_TYPE(GestureScrollEnd);
279 CASE_TYPE(GestureScrollUpdate);
280 CASE_TYPE(GestureFlingStart);
281 CASE_TYPE(GestureFlingCancel);
282 CASE_TYPE(GestureShowPress);
283 CASE_TYPE(GestureTap);
284 CASE_TYPE(GestureTapUnconfirmed);
285 CASE_TYPE(GestureTapDown);
286 CASE_TYPE(GestureTapCancel);
287 CASE_TYPE(GestureDoubleTap);
288 CASE_TYPE(GestureTwoFingerTap);
289 CASE_TYPE(GestureLongPress);
290 CASE_TYPE(GestureLongTap);
291 CASE_TYPE(GesturePinchBegin);
292 CASE_TYPE(GesturePinchEnd);
293 CASE_TYPE(GesturePinchUpdate);
294 CASE_TYPE(TouchStart);
295 CASE_TYPE(TouchMove);
296 CASE_TYPE(TouchEnd);
297 CASE_TYPE(TouchCancel);
298 default:
299 // Must include default to let blink::WebInputEvent add new event types
300 // before they're added here.
301 DLOG(WARNING) <<
302 "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n";
303 break;
305 #undef CASE_TYPE
306 return "";
309 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) {
310 size_t size = 0;
311 Apply(WebInputEventSize(), type, type, &size);
312 return size;
315 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) {
316 ScopedWebInputEvent scoped_event;
317 Apply(WebInputEventClone(), event.type, event, &scoped_event);
318 return scoped_event.Pass();
321 void WebInputEventTraits::Delete(WebInputEvent* event) {
322 if (!event)
323 return;
324 bool dummy_var = false;
325 Apply(WebInputEventDelete(), event->type, event, &dummy_var);
328 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce,
329 const WebInputEvent& event) {
330 // Early out before casting.
331 if (event_to_coalesce.type != event.type)
332 return false;
333 return Apply(WebInputEventCanCoalesce(),
334 event.type,
335 event_to_coalesce,
336 &event);
339 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce,
340 WebInputEvent* event) {
341 DCHECK(event);
342 Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event);
345 bool WebInputEventTraits::IgnoresAckDisposition(const WebInputEvent& event) {
346 switch (event.type) {
347 case WebInputEvent::MouseDown:
348 case WebInputEvent::MouseUp:
349 case WebInputEvent::MouseEnter:
350 case WebInputEvent::MouseLeave:
351 case WebInputEvent::ContextMenu:
352 case WebInputEvent::GestureScrollBegin:
353 case WebInputEvent::GestureScrollEnd:
354 case WebInputEvent::GestureShowPress:
355 case WebInputEvent::GestureTapUnconfirmed:
356 case WebInputEvent::GestureTapDown:
357 case WebInputEvent::GestureTapCancel:
358 case WebInputEvent::GesturePinchBegin:
359 case WebInputEvent::GesturePinchEnd:
360 case WebInputEvent::TouchCancel:
361 return true;
362 case WebInputEvent::TouchStart:
363 case WebInputEvent::TouchMove:
364 case WebInputEvent::TouchEnd:
365 return !static_cast<const WebTouchEvent&>(event).cancelable;
366 default:
367 return false;
371 } // namespace content