Fix various stray bugs in the GN auto-roller, and repair the DEPS file.
[chromium-blink-merge.git] / content / common / input / web_input_event_traits.cc
blobc3be7423900fcb4c4c257c3a42c083d462fb57aa
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"
11 #include "base/strings/stringprintf.h"
13 using base::StringAppendF;
14 using base::SStringPrintf;
15 using blink::WebGestureEvent;
16 using blink::WebInputEvent;
17 using blink::WebKeyboardEvent;
18 using blink::WebMouseEvent;
19 using blink::WebMouseWheelEvent;
20 using blink::WebTouchEvent;
21 using blink::WebTouchPoint;
22 using std::numeric_limits;
24 namespace content {
25 namespace {
27 const int kInvalidTouchIndex = -1;
29 void ApppendEventDetails(const WebKeyboardEvent& event, std::string* result) {
30 StringAppendF(result,
31 "{\n WinCode: %d\n NativeCode: %d\n IsSystem: %d\n"
32 " Text: %s\n UnmodifiedText: %s\n KeyIdentifier: %s\n}",
33 event.windowsKeyCode,
34 event.nativeKeyCode,
35 event.isSystemKey,
36 reinterpret_cast<const char*>(event.text),
37 reinterpret_cast<const char*>(event.unmodifiedText),
38 reinterpret_cast<const char*>(event.keyIdentifier));
41 void ApppendEventDetails(const WebMouseEvent& event, std::string* result) {
42 StringAppendF(result,
43 "{\n Button: %d\n Pos: (%d, %d)\n WindowPos: (%d, %d)\n"
44 " GlobalPos: (%d, %d)\n Movement: (%d, %d)\n Clicks: %d\n}",
45 event.button,
46 event.x,
47 event.y,
48 event.windowX,
49 event.windowY,
50 event.globalX,
51 event.globalY,
52 event.movementX,
53 event.movementY,
54 event.clickCount);
57 void ApppendEventDetails(const WebMouseWheelEvent& event, std::string* result) {
58 StringAppendF(result,
59 "{\n Delta: (%f, %f)\n WheelTicks: (%f, %f)\n Accel: (%f, %f)\n"
60 " ScrollByPage: %d\n HasPreciseScrollingDeltas: %d\n"
61 " Phase: (%d, %d)\n CanRubberband: (%d, %d)\n CanScroll: %d\n}",
62 event.deltaX,
63 event.deltaY,
64 event.wheelTicksX,
65 event.wheelTicksY,
66 event.accelerationRatioX,
67 event.accelerationRatioY,
68 event.scrollByPage,
69 event.hasPreciseScrollingDeltas,
70 event.phase,
71 event.momentumPhase,
72 event.canRubberbandLeft,
73 event.canRubberbandRight,
74 event.canScroll);
77 void ApppendEventDetails(const WebGestureEvent& event, std::string* result) {
78 StringAppendF(result,
79 "{\n Pos: (%d, %d)\n GlobalPos: (%d, %d)\n SourceDevice: %d\n"
80 " RawData: (%f, %f, %f, %f, %d)\n}",
81 event.x,
82 event.y,
83 event.globalX,
84 event.globalY,
85 event.sourceDevice,
86 event.data.scrollUpdate.deltaX,
87 event.data.scrollUpdate.deltaY,
88 event.data.scrollUpdate.velocityX,
89 event.data.scrollUpdate.velocityY,
90 event.data.scrollUpdate.previousUpdateInSequencePrevented);
93 void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) {
94 StringAppendF(result,
95 " (ID: %d, State: %d, ScreenPos: (%f, %f), Pos: (%f, %f),"
96 " Radius: (%f, %f), Rot: %f, Force: %f),\n",
97 point.id,
98 point.state,
99 point.screenPosition.x,
100 point.screenPosition.y,
101 point.position.x,
102 point.position.y,
103 point.radiusX,
104 point.radiusY,
105 point.rotationAngle,
106 point.force);
109 void ApppendEventDetails(const WebTouchEvent& event, std::string* result) {
110 StringAppendF(result,
111 "{\n Touches: %u, Cancelable: %d, CausesScrolling: %d,"
112 " uniqueTouchEventId: %u\n[\n",
113 event.touchesLength, event.cancelable,
114 event.causesScrollingIfUncanceled, event.uniqueTouchEventId);
115 for (unsigned i = 0; i < event.touchesLength; ++i)
116 ApppendTouchPointDetails(event.touches[i], result);
117 result->append(" ]\n}");
120 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce,
121 const WebKeyboardEvent& event) {
122 return false;
125 void Coalesce(const WebKeyboardEvent& event_to_coalesce,
126 WebKeyboardEvent* event) {
127 DCHECK(CanCoalesce(event_to_coalesce, *event));
130 bool CanCoalesce(const WebMouseEvent& event_to_coalesce,
131 const WebMouseEvent& event) {
132 return event.type == event_to_coalesce.type &&
133 event.type == WebInputEvent::MouseMove;
136 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) {
137 DCHECK(CanCoalesce(event_to_coalesce, *event));
138 // Accumulate movement deltas.
139 int x = event->movementX;
140 int y = event->movementY;
141 *event = event_to_coalesce;
142 event->movementX += x;
143 event->movementY += y;
146 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
147 const WebMouseWheelEvent& event) {
148 return event.modifiers == event_to_coalesce.modifiers &&
149 event.scrollByPage == event_to_coalesce.scrollByPage &&
150 event.phase == event_to_coalesce.phase &&
151 event.momentumPhase == event_to_coalesce.momentumPhase &&
152 event.hasPreciseScrollingDeltas ==
153 event_to_coalesce.hasPreciseScrollingDeltas &&
154 event.canScroll == event_to_coalesce.canScroll;
157 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
158 return accelerated_delta * acceleration_ratio;
161 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
162 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
163 return 1.f;
164 return unaccelerated_delta / accelerated_delta;
167 void Coalesce(const WebMouseWheelEvent& event_to_coalesce,
168 WebMouseWheelEvent* event) {
169 DCHECK(CanCoalesce(event_to_coalesce, *event));
170 float unaccelerated_x =
171 GetUnacceleratedDelta(event->deltaX,
172 event->accelerationRatioX) +
173 GetUnacceleratedDelta(event_to_coalesce.deltaX,
174 event_to_coalesce.accelerationRatioX);
175 float unaccelerated_y =
176 GetUnacceleratedDelta(event->deltaY,
177 event->accelerationRatioY) +
178 GetUnacceleratedDelta(event_to_coalesce.deltaY,
179 event_to_coalesce.accelerationRatioY);
180 event->deltaX += event_to_coalesce.deltaX;
181 event->deltaY += event_to_coalesce.deltaY;
182 event->wheelTicksX += event_to_coalesce.wheelTicksX;
183 event->wheelTicksY += event_to_coalesce.wheelTicksY;
184 event->accelerationRatioX =
185 GetAccelerationRatio(event->deltaX, unaccelerated_x);
186 event->accelerationRatioY =
187 GetAccelerationRatio(event->deltaY, unaccelerated_y);
190 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|.
191 int GetIndexOfTouchID(const WebTouchEvent& event, int id) {
192 for (unsigned i = 0; i < event.touchesLength; ++i) {
193 if (event.touches[i].id == id)
194 return i;
196 return kInvalidTouchIndex;
199 bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
200 const WebTouchEvent& event) {
201 if (event.type != event_to_coalesce.type ||
202 event.type != WebInputEvent::TouchMove ||
203 event.modifiers != event_to_coalesce.modifiers ||
204 event.touchesLength != event_to_coalesce.touchesLength ||
205 event.touchesLength > WebTouchEvent::touchesLengthCap)
206 return false;
208 static_assert(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U,
209 "suboptimal touchesLengthCap size");
210 // Ensure that we have a 1-to-1 mapping of pointer ids between touches.
211 std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches(
212 (1 << event.touchesLength) - 1);
213 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) {
214 int event_touch_index =
215 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id);
216 if (event_touch_index == kInvalidTouchIndex)
217 return false;
218 if (!unmatched_event_touches[event_touch_index])
219 return false;
220 unmatched_event_touches[event_touch_index] = false;
222 return unmatched_event_touches.none();
225 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
226 DCHECK(CanCoalesce(event_to_coalesce, *event));
227 // The WebTouchPoints include absolute position information. So it is
228 // sufficient to simply replace the previous event with the new event->
229 // However, it is necessary to make sure that all the points have the
230 // correct state, i.e. the touch-points that moved in the last event, but
231 // didn't change in the current event, will have Stationary state. It is
232 // necessary to change them back to Moved state.
233 WebTouchEvent old_event = *event;
234 *event = event_to_coalesce;
235 for (unsigned i = 0; i < event->touchesLength; ++i) {
236 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id);
237 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved)
238 event->touches[i].state = blink::WebTouchPoint::StateMoved;
240 event->causesScrollingIfUncanceled |= old_event.causesScrollingIfUncanceled;
243 bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
244 const WebGestureEvent& event) {
245 if (event.type != event_to_coalesce.type ||
246 event.sourceDevice != event_to_coalesce.sourceDevice ||
247 event.modifiers != event_to_coalesce.modifiers)
248 return false;
250 if (event.type == WebInputEvent::GestureScrollUpdate)
251 return true;
253 // GesturePinchUpdate scales can be combined only if they share a focal point,
254 // e.g., with double-tap drag zoom.
255 if (event.type == WebInputEvent::GesturePinchUpdate &&
256 event.x == event_to_coalesce.x &&
257 event.y == event_to_coalesce.y)
258 return true;
260 return false;
263 void Coalesce(const WebGestureEvent& event_to_coalesce,
264 WebGestureEvent* event) {
265 DCHECK(CanCoalesce(event_to_coalesce, *event));
266 if (event->type == WebInputEvent::GestureScrollUpdate) {
267 event->data.scrollUpdate.deltaX +=
268 event_to_coalesce.data.scrollUpdate.deltaX;
269 event->data.scrollUpdate.deltaY +=
270 event_to_coalesce.data.scrollUpdate.deltaY;
271 DCHECK_EQ(
272 event->data.scrollUpdate.previousUpdateInSequencePrevented,
273 event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented);
274 } else if (event->type == WebInputEvent::GesturePinchUpdate) {
275 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale;
276 // Ensure the scale remains bounded above 0 and below Infinity so that
277 // we can reliably perform operations like log on the values.
278 if (event->data.pinchUpdate.scale < numeric_limits<float>::min())
279 event->data.pinchUpdate.scale = numeric_limits<float>::min();
280 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max())
281 event->data.pinchUpdate.scale = numeric_limits<float>::max();
285 struct WebInputEventToString {
286 template <class EventType>
287 bool Execute(const WebInputEvent& event, std::string* result) const {
288 SStringPrintf(result, "%s (Time: %lf, Modifiers: %d)\n",
289 WebInputEventTraits::GetName(event.type),
290 event.timeStampSeconds,
291 event.modifiers);
292 const EventType& typed_event = static_cast<const EventType&>(event);
293 ApppendEventDetails(typed_event, result);
294 return true;
298 struct WebInputEventSize {
299 template <class EventType>
300 bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const {
301 *type_size = sizeof(EventType);
302 return true;
306 struct WebInputEventClone {
307 template <class EventType>
308 bool Execute(const WebInputEvent& event,
309 ScopedWebInputEvent* scoped_event) const {
310 DCHECK_EQ(sizeof(EventType), event.size);
311 *scoped_event = ScopedWebInputEvent(
312 new EventType(static_cast<const EventType&>(event)));
313 return true;
317 struct WebInputEventDelete {
318 template <class EventType>
319 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const {
320 if (!event)
321 return false;
322 DCHECK_EQ(sizeof(EventType), event->size);
323 delete static_cast<EventType*>(event);
324 return true;
328 struct WebInputEventCanCoalesce {
329 template <class EventType>
330 bool Execute(const WebInputEvent& event_to_coalesce,
331 const WebInputEvent* event) const {
332 if (event_to_coalesce.type != event->type)
333 return false;
334 DCHECK_EQ(sizeof(EventType), event->size);
335 DCHECK_EQ(sizeof(EventType), event_to_coalesce.size);
336 return CanCoalesce(static_cast<const EventType&>(event_to_coalesce),
337 *static_cast<const EventType*>(event));
341 struct WebInputEventCoalesce {
342 template <class EventType>
343 bool Execute(const WebInputEvent& event_to_coalesce,
344 WebInputEvent* event) const {
345 // New events get coalesced into older events, and the newer timestamp
346 // should always be preserved.
347 // On Windows sometimes there could be wild timestamp value, so ignore the
348 // check on Windows.
349 // TODO(miletus): Make it work on Windows. crbug.com/517921.
350 #if !defined(OS_WIN)
351 // In some test cases, due to clock precision and data conversion loss,
352 // we allow a small epsilon.
353 DCHECK_GE(event_to_coalesce.timeStampSeconds - event->timeStampSeconds,
354 -2.0e-3);
355 #endif // !defined(OS_WIN)
357 const double time_stamp_seconds = event_to_coalesce.timeStampSeconds;
358 Coalesce(static_cast<const EventType&>(event_to_coalesce),
359 static_cast<EventType*>(event));
360 event->timeStampSeconds = time_stamp_seconds;
361 return true;
365 template <typename Operator, typename ArgIn, typename ArgOut>
366 bool Apply(Operator op,
367 WebInputEvent::Type type,
368 const ArgIn& arg_in,
369 ArgOut* arg_out) {
370 if (WebInputEvent::isMouseEventType(type))
371 return op.template Execute<WebMouseEvent>(arg_in, arg_out);
372 else if (type == WebInputEvent::MouseWheel)
373 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out);
374 else if (WebInputEvent::isKeyboardEventType(type))
375 return op.template Execute<WebKeyboardEvent>(arg_in, arg_out);
376 else if (WebInputEvent::isTouchEventType(type))
377 return op.template Execute<WebTouchEvent>(arg_in, arg_out);
378 else if (WebInputEvent::isGestureEventType(type))
379 return op.template Execute<WebGestureEvent>(arg_in, arg_out);
381 NOTREACHED() << "Unknown webkit event type " << type;
382 return false;
385 } // namespace
387 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) {
388 #define CASE_TYPE(t) case WebInputEvent::t: return #t
389 switch(type) {
390 CASE_TYPE(Undefined);
391 CASE_TYPE(MouseDown);
392 CASE_TYPE(MouseUp);
393 CASE_TYPE(MouseMove);
394 CASE_TYPE(MouseEnter);
395 CASE_TYPE(MouseLeave);
396 CASE_TYPE(ContextMenu);
397 CASE_TYPE(MouseWheel);
398 CASE_TYPE(RawKeyDown);
399 CASE_TYPE(KeyDown);
400 CASE_TYPE(KeyUp);
401 CASE_TYPE(Char);
402 CASE_TYPE(GestureScrollBegin);
403 CASE_TYPE(GestureScrollEnd);
404 CASE_TYPE(GestureScrollUpdate);
405 CASE_TYPE(GestureFlingStart);
406 CASE_TYPE(GestureFlingCancel);
407 CASE_TYPE(GestureShowPress);
408 CASE_TYPE(GestureTap);
409 CASE_TYPE(GestureTapUnconfirmed);
410 CASE_TYPE(GestureTapDown);
411 CASE_TYPE(GestureTapCancel);
412 CASE_TYPE(GestureDoubleTap);
413 CASE_TYPE(GestureTwoFingerTap);
414 CASE_TYPE(GestureLongPress);
415 CASE_TYPE(GestureLongTap);
416 CASE_TYPE(GesturePinchBegin);
417 CASE_TYPE(GesturePinchEnd);
418 CASE_TYPE(GesturePinchUpdate);
419 CASE_TYPE(TouchStart);
420 CASE_TYPE(TouchMove);
421 CASE_TYPE(TouchEnd);
422 CASE_TYPE(TouchCancel);
423 default:
424 // Must include default to let blink::WebInputEvent add new event types
425 // before they're added here.
426 DLOG(WARNING) <<
427 "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n";
428 break;
430 #undef CASE_TYPE
431 return "";
434 std::string WebInputEventTraits::ToString(const WebInputEvent& event) {
435 std::string result;
436 Apply(WebInputEventToString(), event.type, event, &result);
437 return result;
440 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) {
441 size_t size = 0;
442 Apply(WebInputEventSize(), type, type, &size);
443 return size;
446 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) {
447 ScopedWebInputEvent scoped_event;
448 Apply(WebInputEventClone(), event.type, event, &scoped_event);
449 return scoped_event.Pass();
452 void WebInputEventTraits::Delete(WebInputEvent* event) {
453 if (!event)
454 return;
455 bool dummy_var = false;
456 Apply(WebInputEventDelete(), event->type, event, &dummy_var);
459 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce,
460 const WebInputEvent& event) {
461 // Early out before casting.
462 if (event_to_coalesce.type != event.type)
463 return false;
464 return Apply(WebInputEventCanCoalesce(),
465 event.type,
466 event_to_coalesce,
467 &event);
470 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce,
471 WebInputEvent* event) {
472 DCHECK(event);
473 Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event);
476 bool WebInputEventTraits::WillReceiveAckFromRenderer(
477 const WebInputEvent& event) {
478 switch (event.type) {
479 case WebInputEvent::MouseDown:
480 case WebInputEvent::MouseUp:
481 case WebInputEvent::MouseEnter:
482 case WebInputEvent::MouseLeave:
483 case WebInputEvent::ContextMenu:
484 case WebInputEvent::GestureScrollBegin:
485 case WebInputEvent::GestureScrollEnd:
486 case WebInputEvent::GestureShowPress:
487 case WebInputEvent::GestureTapUnconfirmed:
488 case WebInputEvent::GestureTapDown:
489 case WebInputEvent::GestureTapCancel:
490 case WebInputEvent::GesturePinchBegin:
491 case WebInputEvent::GesturePinchEnd:
492 case WebInputEvent::TouchCancel:
493 return false;
494 case WebInputEvent::TouchStart:
495 case WebInputEvent::TouchEnd:
496 return static_cast<const WebTouchEvent&>(event).cancelable;
497 default:
498 return true;
502 uint32 WebInputEventTraits::GetUniqueTouchEventId(const WebInputEvent& event) {
503 if (WebInputEvent::isTouchEventType(event.type)) {
504 return static_cast<const WebTouchEvent&>(event).uniqueTouchEventId;
506 return 0U;
509 } // namespace content