Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / content / common / input / web_input_event_traits.cc
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.
4
5 #include "content/common/input/web_input_event_traits.h"
6
7 #include <bitset>
8
9 #include "base/logging.h"
10
11 using blink::WebGestureEvent;
12 using blink::WebInputEvent;
13 using blink::WebKeyboardEvent;
14 using blink::WebMouseEvent;
15 using blink::WebMouseWheelEvent;
16 using blink::WebTouchEvent;
17
18 namespace content {
19 namespace {
20
21 const int kInvalidTouchIndex = -1;
22
23 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce,
24                  const WebKeyboardEvent& event) {
25   return false;
26 }
27
28 void Coalesce(const WebKeyboardEvent& event_to_coalesce,
29               WebKeyboardEvent* event) {
30   DCHECK(CanCoalesce(event_to_coalesce, *event));
31 }
32
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;
37 }
38
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;
47 }
48
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;
57 }
58
59 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
60   return accelerated_delta * acceleration_ratio;
61 }
62
63 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
64   if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
65     return 1.f;
66   return unaccelerated_delta / accelerated_delta;
67 }
68
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;
92 }
93
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)
98       return i;
99   }
100   return kInvalidTouchIndex;
101 }
102
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)
110     return false;
111
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)
121       return false;
122     if (!unmatched_event_touches[event_touch_index])
123       return false;
124     unmatched_event_touches[event_touch_index] = false;
125   }
126   return unmatched_event_touches.none();
127 }
128
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;
143   }
144 }
145
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;
151 }
152
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;
158 }
159
160 struct WebInputEventSize {
161   template <class EventType>
162   bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const {
163     *type_size = sizeof(EventType);
164     return true;
165   }
166 };
167
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)));
175     return true;
176   }
177 };
178
179 struct WebInputEventDelete {
180   template <class EventType>
181   bool Execute(WebInputEvent* event, bool* /* dummy_var */) const {
182     if (!event)
183       return false;
184     DCHECK_EQ(sizeof(EventType), event->size);
185     delete static_cast<EventType*>(event);
186     return true;
187   }
188 };
189
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)
195       return false;
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));
200   }
201 };
202
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));
209     return true;
210   }
211 };
212
213 template <typename Operator, typename ArgIn, typename ArgOut>
214 bool Apply(Operator op,
215            WebInputEvent::Type type,
216            const ArgIn& arg_in,
217            ArgOut* arg_out) {
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);
228
229   NOTREACHED() << "Unknown webkit event type " << type;
230   return false;
231 }
232
233 }  // namespace
234
235 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) {
236 #define CASE_TYPE(t) case WebInputEvent::t:  return #t
237   switch(type) {
238     CASE_TYPE(Undefined);
239     CASE_TYPE(MouseDown);
240     CASE_TYPE(MouseUp);
241     CASE_TYPE(MouseMove);
242     CASE_TYPE(MouseEnter);
243     CASE_TYPE(MouseLeave);
244     CASE_TYPE(ContextMenu);
245     CASE_TYPE(MouseWheel);
246     CASE_TYPE(RawKeyDown);
247     CASE_TYPE(KeyDown);
248     CASE_TYPE(KeyUp);
249     CASE_TYPE(Char);
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);
269     CASE_TYPE(TouchEnd);
270     CASE_TYPE(TouchCancel);
271     default:
272       // Must include default to let blink::WebInputEvent add new event types
273       // before they're added here.
274       DLOG(WARNING) <<
275           "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n";
276       break;
277   }
278 #undef CASE_TYPE
279   return "";
280 }
281
282 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) {
283   size_t size = 0;
284   Apply(WebInputEventSize(), type, type, &size);
285   return size;
286 }
287
288 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) {
289   ScopedWebInputEvent scoped_event;
290   Apply(WebInputEventClone(), event.type, event, &scoped_event);
291   return scoped_event.Pass();
292 }
293
294 void WebInputEventTraits::Delete(WebInputEvent* event) {
295   if (!event)
296     return;
297   bool dummy_var = false;
298   Apply(WebInputEventDelete(), event->type, event, &dummy_var);
299 }
300
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)
305     return false;
306   return Apply(WebInputEventCanCoalesce(),
307                event.type,
308                event_to_coalesce,
309                &event);
310 }
311
312 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce,
313                                    WebInputEvent* event) {
314   DCHECK(event);
315   Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event);
316 }
317
318 bool WebInputEventTraits::IgnoresAckDisposition(
319     blink::WebInputEvent::Type type) {
320   switch (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:
335       return true;
336     default:
337       break;
338   }
339   return false;
340 }
341
342 }  // namespace content