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"
9 #include "base/logging.h"
11 using blink::WebGestureEvent;
12 using blink::WebInputEvent;
13 using blink::WebKeyboardEvent;
14 using blink::WebMouseEvent;
15 using blink::WebMouseWheelEvent;
16 using blink::WebTouchEvent;
21 const int kInvalidTouchIndex = -1;
23 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce,
24 const WebKeyboardEvent& event) {
28 void Coalesce(const WebKeyboardEvent& event_to_coalesce,
29 WebKeyboardEvent* event) {
30 DCHECK(CanCoalesce(event_to_coalesce, *event));
33 bool CanCoalesce(const WebMouseEvent& event_to_coalesce,
34 const WebMouseEvent& event) {
35 return event.type == event_to_coalesce.type &&
36 event.type == WebInputEvent::MouseMove;
39 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) {
40 DCHECK(CanCoalesce(event_to_coalesce, *event));
41 // Accumulate movement deltas.
42 int x = event->movementX;
43 int y = event->movementY;
44 *event = event_to_coalesce;
45 event->movementX += x;
46 event->movementY += y;
49 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
50 const WebMouseWheelEvent& event) {
51 return event.modifiers == event_to_coalesce.modifiers &&
52 event.scrollByPage == event_to_coalesce.scrollByPage &&
53 event.phase == event_to_coalesce.phase &&
54 event.momentumPhase == event_to_coalesce.momentumPhase &&
55 event.hasPreciseScrollingDeltas ==
56 event_to_coalesce.hasPreciseScrollingDeltas;
59 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
60 return accelerated_delta * acceleration_ratio;
63 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
64 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
66 return unaccelerated_delta / accelerated_delta;
69 void Coalesce(const WebMouseWheelEvent& event_to_coalesce,
70 WebMouseWheelEvent* event) {
71 DCHECK(CanCoalesce(event_to_coalesce, *event));
72 float unaccelerated_x =
73 GetUnacceleratedDelta(event->deltaX,
74 event->accelerationRatioX) +
75 GetUnacceleratedDelta(event_to_coalesce.deltaX,
76 event_to_coalesce.accelerationRatioX);
77 float unaccelerated_y =
78 GetUnacceleratedDelta(event->deltaY,
79 event->accelerationRatioY) +
80 GetUnacceleratedDelta(event_to_coalesce.deltaY,
81 event_to_coalesce.accelerationRatioY);
82 event->deltaX += event_to_coalesce.deltaX;
83 event->deltaY += event_to_coalesce.deltaY;
84 event->wheelTicksX += event_to_coalesce.wheelTicksX;
85 event->wheelTicksY += event_to_coalesce.wheelTicksY;
86 event->accelerationRatioX =
87 GetAccelerationRatio(event->deltaX, unaccelerated_x);
88 event->accelerationRatioY =
89 GetAccelerationRatio(event->deltaY, unaccelerated_y);
90 DCHECK_GE(event_to_coalesce.timeStampSeconds, event->timeStampSeconds);
91 event->timeStampSeconds = event_to_coalesce.timeStampSeconds;
94 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|.
95 int GetIndexOfTouchID(const WebTouchEvent& event, int id) {
96 for (unsigned i = 0; i < event.touchesLength; ++i) {
97 if (event.touches[i].id == id)
100 return kInvalidTouchIndex;
103 bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
104 const WebTouchEvent& event) {
105 if (event.type != event_to_coalesce.type ||
106 event.type != WebInputEvent::TouchMove ||
107 event.modifiers != event_to_coalesce.modifiers ||
108 event.touchesLength != event_to_coalesce.touchesLength ||
109 event.touchesLength > WebTouchEvent::touchesLengthCap)
112 COMPILE_ASSERT(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U,
113 suboptimal_touches_length_cap_size);
114 // Ensure that we have a 1-to-1 mapping of pointer ids between touches.
115 std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches(
116 (1 << event.touchesLength) - 1);
117 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) {
118 int event_touch_index =
119 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id);
120 if (event_touch_index == kInvalidTouchIndex)
122 if (!unmatched_event_touches[event_touch_index])
124 unmatched_event_touches[event_touch_index] = false;
126 return unmatched_event_touches.none();
129 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
130 DCHECK(CanCoalesce(event_to_coalesce, *event));
131 // The WebTouchPoints include absolute position information. So it is
132 // sufficient to simply replace the previous event with the new event->
133 // However, it is necessary to make sure that all the points have the
134 // correct state, i.e. the touch-points that moved in the last event, but
135 // didn't change in the current event, will have Stationary state. It is
136 // necessary to change them back to Moved state.
137 WebTouchEvent old_event = *event;
138 *event = event_to_coalesce;
139 for (unsigned i = 0; i < event->touchesLength; ++i) {
140 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id);
141 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved)
142 event->touches[i].state = blink::WebTouchPoint::StateMoved;
146 bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
147 const WebGestureEvent& event) {
148 return event.type == event_to_coalesce.type &&
149 event.type == WebInputEvent::GestureScrollUpdate &&
150 event.modifiers == event_to_coalesce.modifiers;
153 void Coalesce(const WebGestureEvent& event_to_coalesce,
154 WebGestureEvent* event) {
155 DCHECK(CanCoalesce(event_to_coalesce, *event));
156 event->data.scrollUpdate.deltaX += event_to_coalesce.data.scrollUpdate.deltaX;
157 event->data.scrollUpdate.deltaY += event_to_coalesce.data.scrollUpdate.deltaY;
160 struct WebInputEventSize {
161 template <class EventType>
162 bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const {
163 *type_size = sizeof(EventType);
168 struct WebInputEventClone {
169 template <class EventType>
170 bool Execute(const WebInputEvent& event,
171 ScopedWebInputEvent* scoped_event) const {
172 DCHECK_EQ(sizeof(EventType), event.size);
173 *scoped_event = ScopedWebInputEvent(
174 new EventType(static_cast<const EventType&>(event)));
179 struct WebInputEventDelete {
180 template <class EventType>
181 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const {
184 DCHECK_EQ(sizeof(EventType), event->size);
185 delete static_cast<EventType*>(event);
190 struct WebInputEventCanCoalesce {
191 template <class EventType>
192 bool Execute(const WebInputEvent& event_to_coalesce,
193 const WebInputEvent* event) const {
194 if (event_to_coalesce.type != event->type)
196 DCHECK_EQ(sizeof(EventType), event->size);
197 DCHECK_EQ(sizeof(EventType), event_to_coalesce.size);
198 return CanCoalesce(static_cast<const EventType&>(event_to_coalesce),
199 *static_cast<const EventType*>(event));
203 struct WebInputEventCoalesce {
204 template <class EventType>
205 bool Execute(const WebInputEvent& event_to_coalesce,
206 WebInputEvent* event) const {
207 Coalesce(static_cast<const EventType&>(event_to_coalesce),
208 static_cast<EventType*>(event));
213 template <typename Operator, typename ArgIn, typename ArgOut>
214 bool Apply(Operator op,
215 WebInputEvent::Type type,
218 if (WebInputEvent::isMouseEventType(type))
219 return op.template Execute<WebMouseEvent>(arg_in, arg_out);
220 else if (type == WebInputEvent::MouseWheel)
221 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out);
222 else if (WebInputEvent::isKeyboardEventType(type))
223 return op.template Execute<WebKeyboardEvent>(arg_in, arg_out);
224 else if (WebInputEvent::isTouchEventType(type))
225 return op.template Execute<WebTouchEvent>(arg_in, arg_out);
226 else if (WebInputEvent::isGestureEventType(type))
227 return op.template Execute<WebGestureEvent>(arg_in, arg_out);
229 NOTREACHED() << "Unknown webkit event type " << type;
235 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) {
236 #define CASE_TYPE(t) case WebInputEvent::t: return #t
238 CASE_TYPE(Undefined);
239 CASE_TYPE(MouseDown);
241 CASE_TYPE(MouseMove);
242 CASE_TYPE(MouseEnter);
243 CASE_TYPE(MouseLeave);
244 CASE_TYPE(ContextMenu);
245 CASE_TYPE(MouseWheel);
246 CASE_TYPE(RawKeyDown);
250 CASE_TYPE(GestureScrollBegin);
251 CASE_TYPE(GestureScrollEnd);
252 CASE_TYPE(GestureScrollUpdate);
253 CASE_TYPE(GestureFlingStart);
254 CASE_TYPE(GestureFlingCancel);
255 CASE_TYPE(GestureShowPress);
256 CASE_TYPE(GestureTap);
257 CASE_TYPE(GestureTapUnconfirmed);
258 CASE_TYPE(GestureTapDown);
259 CASE_TYPE(GestureTapCancel);
260 CASE_TYPE(GestureDoubleTap);
261 CASE_TYPE(GestureTwoFingerTap);
262 CASE_TYPE(GestureLongPress);
263 CASE_TYPE(GestureLongTap);
264 CASE_TYPE(GesturePinchBegin);
265 CASE_TYPE(GesturePinchEnd);
266 CASE_TYPE(GesturePinchUpdate);
267 CASE_TYPE(TouchStart);
268 CASE_TYPE(TouchMove);
270 CASE_TYPE(TouchCancel);
272 // Must include default to let blink::WebInputEvent add new event types
273 // before they're added here.
275 "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n";
282 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) {
284 Apply(WebInputEventSize(), type, type, &size);
288 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) {
289 ScopedWebInputEvent scoped_event;
290 Apply(WebInputEventClone(), event.type, event, &scoped_event);
291 return scoped_event.Pass();
294 void WebInputEventTraits::Delete(WebInputEvent* event) {
297 bool dummy_var = false;
298 Apply(WebInputEventDelete(), event->type, event, &dummy_var);
301 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce,
302 const WebInputEvent& event) {
303 // Early out before casting.
304 if (event_to_coalesce.type != event.type)
306 return Apply(WebInputEventCanCoalesce(),
312 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce,
313 WebInputEvent* event) {
315 Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event);
318 bool WebInputEventTraits::IgnoresAckDisposition(
319 blink::WebInputEvent::Type type) {
321 case WebInputEvent::GestureTapDown:
322 case WebInputEvent::GestureShowPress:
323 case WebInputEvent::GestureTapCancel:
324 case WebInputEvent::GestureTap:
325 case WebInputEvent::GesturePinchBegin:
326 case WebInputEvent::GesturePinchEnd:
327 case WebInputEvent::GestureScrollBegin:
328 case WebInputEvent::GestureScrollEnd:
329 case WebInputEvent::TouchCancel:
330 case WebInputEvent::MouseDown:
331 case WebInputEvent::MouseUp:
332 case WebInputEvent::MouseEnter:
333 case WebInputEvent::MouseLeave:
334 case WebInputEvent::ContextMenu:
342 } // namespace content