Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / events / gesture_detection / touch_disposition_gesture_filter.cc
1 // Copyright 2014 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 "ui/events/gesture_detection/touch_disposition_gesture_filter.h"
6
7 #include "base/auto_reset.h"
8 #include "base/logging.h"
9 #include "ui/events/gesture_event_details.h"
10
11 namespace ui {
12 namespace {
13
14 // A BitSet32 is used for tracking dropped gesture types.
15 COMPILE_ASSERT(ET_GESTURE_TYPE_END - ET_GESTURE_TYPE_START < 32,
16                gesture_type_count_too_large);
17
18 GestureEventData CreateGesture(EventType type,
19                                int motion_event_id,
20                                MotionEvent::ToolType primary_tool_type,
21                                const GestureEventDataPacket& packet) {
22   return GestureEventData(GestureEventDetails(type, 0, 0),
23                           motion_event_id,
24                           primary_tool_type,
25                           packet.timestamp(),
26                           packet.touch_location().x(),
27                           packet.touch_location().y(),
28                           packet.raw_touch_location().x(),
29                           packet.raw_touch_location().y(),
30                           1,
31                           gfx::RectF(packet.touch_location(), gfx::SizeF()));
32 }
33
34 enum RequiredTouches {
35   RT_NONE = 0,
36   RT_START = 1 << 0,
37   RT_CURRENT = 1 << 1,
38 };
39
40 struct DispositionHandlingInfo {
41   // A bitwise-OR of |RequiredTouches|.
42   int required_touches;
43   EventType antecedent_event_type;
44
45   explicit DispositionHandlingInfo(int required_touches)
46       : required_touches(required_touches), antecedent_event_type(ET_UNKNOWN) {}
47
48   DispositionHandlingInfo(int required_touches,
49                           EventType antecedent_event_type)
50       : required_touches(required_touches),
51         antecedent_event_type(antecedent_event_type) {}
52 };
53
54 DispositionHandlingInfo Info(int required_touches) {
55   return DispositionHandlingInfo(required_touches);
56 }
57
58 DispositionHandlingInfo Info(int required_touches,
59                              EventType antecedent_event_type) {
60   return DispositionHandlingInfo(required_touches, antecedent_event_type);
61 }
62
63 // This approach to disposition handling is described at http://goo.gl/5G8PWJ.
64 DispositionHandlingInfo GetDispositionHandlingInfo(EventType type) {
65   switch (type) {
66     case ET_GESTURE_TAP_DOWN:
67       return Info(RT_START);
68     case ET_GESTURE_TAP_CANCEL:
69       return Info(RT_START);
70     case ET_GESTURE_SHOW_PRESS:
71       return Info(RT_START);
72     case ET_GESTURE_LONG_PRESS:
73       return Info(RT_START);
74     case ET_GESTURE_LONG_TAP:
75       return Info(RT_START | RT_CURRENT);
76     case ET_GESTURE_TAP:
77       return Info(RT_START | RT_CURRENT, ET_GESTURE_TAP_UNCONFIRMED);
78     case ET_GESTURE_TAP_UNCONFIRMED:
79       return Info(RT_START | RT_CURRENT);
80     case ET_GESTURE_DOUBLE_TAP:
81       return Info(RT_START | RT_CURRENT, ET_GESTURE_TAP_UNCONFIRMED);
82     case ET_GESTURE_SCROLL_BEGIN:
83       return Info(RT_START);
84     case ET_GESTURE_SCROLL_UPDATE:
85       return Info(RT_CURRENT, ET_GESTURE_SCROLL_BEGIN);
86     case ET_GESTURE_SCROLL_END:
87       return Info(RT_NONE, ET_GESTURE_SCROLL_BEGIN);
88     case ET_SCROLL_FLING_START:
89       // We rely on |EndScrollGestureIfNecessary| to end the scroll if the fling
90       // start is prevented.
91       return Info(RT_NONE, ET_GESTURE_SCROLL_UPDATE);
92     case ET_SCROLL_FLING_CANCEL:
93       return Info(RT_NONE, ET_SCROLL_FLING_START);
94     case ET_GESTURE_PINCH_BEGIN:
95       return Info(RT_START, ET_GESTURE_SCROLL_BEGIN);
96     case ET_GESTURE_PINCH_UPDATE:
97       return Info(RT_CURRENT, ET_GESTURE_PINCH_BEGIN);
98     case ET_GESTURE_PINCH_END:
99       return Info(RT_NONE, ET_GESTURE_PINCH_BEGIN);
100     case ET_GESTURE_BEGIN:
101       return Info(RT_START);
102     case ET_GESTURE_END:
103       return Info(RT_NONE, ET_GESTURE_BEGIN);
104     case ET_GESTURE_SWIPE:
105       return Info(RT_START, ET_GESTURE_SCROLL_BEGIN);
106     case ET_GESTURE_TWO_FINGER_TAP:
107       return Info(RT_START);
108     default:
109       break;
110   }
111   NOTREACHED();
112   return Info(RT_NONE);
113 }
114
115 int GetGestureTypeIndex(EventType type) {
116   DCHECK_GE(type, ET_GESTURE_TYPE_START);
117   DCHECK_LE(type, ET_GESTURE_TYPE_END);
118   return type - ET_GESTURE_TYPE_START;
119 }
120
121 bool IsTouchStartEvent(GestureEventDataPacket::GestureSource gesture_source) {
122   return gesture_source == GestureEventDataPacket::TOUCH_SEQUENCE_START ||
123          gesture_source == GestureEventDataPacket::TOUCH_START;
124 }
125
126 }  // namespace
127
128 // TouchDispositionGestureFilter
129
130 TouchDispositionGestureFilter::TouchDispositionGestureFilter(
131     TouchDispositionGestureFilterClient* client)
132     : client_(client),
133       ending_event_motion_event_id_(0),
134       ending_event_primary_tool_type_(MotionEvent::TOOL_TYPE_UNKNOWN),
135       needs_tap_ending_event_(false),
136       needs_show_press_event_(false),
137       needs_fling_ending_event_(false),
138       needs_scroll_ending_event_(false) {
139   DCHECK(client_);
140 }
141
142 TouchDispositionGestureFilter::~TouchDispositionGestureFilter() {
143 }
144
145 TouchDispositionGestureFilter::PacketResult
146 TouchDispositionGestureFilter::OnGesturePacket(
147     const GestureEventDataPacket& packet) {
148   if (packet.gesture_source() == GestureEventDataPacket::UNDEFINED ||
149       packet.gesture_source() == GestureEventDataPacket::INVALID)
150     return INVALID_PACKET_TYPE;
151
152   if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_START)
153     sequences_.push(GestureSequence());
154
155   if (IsEmpty())
156     return INVALID_PACKET_ORDER;
157
158   if (packet.gesture_source() == GestureEventDataPacket::TOUCH_TIMEOUT &&
159       Tail().empty()) {
160     // Handle the timeout packet immediately if the packet preceding the timeout
161     // has already been dispatched.
162     FilterAndSendPacket(packet);
163     return SUCCESS;
164   }
165
166   Tail().push(packet);
167   return SUCCESS;
168 }
169
170 void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) {
171   // Spurious touch acks from the renderer should not trigger a crash.
172   if (IsEmpty() || (Head().empty() && sequences_.size() == 1))
173     return;
174
175   if (Head().empty())
176     PopGestureSequence();
177
178   GestureSequence& sequence = Head();
179
180   // Dispatch the packet corresponding to the ack'ed touch, as well as any
181   // additional timeout-based packets queued before the ack was received.
182   bool touch_packet_for_current_ack_handled = false;
183   while (!sequence.empty()) {
184     DCHECK_NE(sequence.front().gesture_source(),
185               GestureEventDataPacket::UNDEFINED);
186     DCHECK_NE(sequence.front().gesture_source(),
187               GestureEventDataPacket::INVALID);
188
189     GestureEventDataPacket::GestureSource source =
190         sequence.front().gesture_source();
191     if (source != GestureEventDataPacket::TOUCH_TIMEOUT) {
192       // We should handle at most one non-timeout based packet.
193       if (touch_packet_for_current_ack_handled)
194         break;
195       state_.OnTouchEventAck(event_consumed, IsTouchStartEvent(source));
196       touch_packet_for_current_ack_handled = true;
197     }
198     // We need to pop the current sequence before sending the packet, because
199     // sending the packet could result in this method being re-entered (e.g. on
200     // Aura, we could trigger a touch-cancel). As popping the sequence destroys
201     // the packet, we copy the packet before popping it.
202     const GestureEventDataPacket packet = sequence.front();
203     sequence.pop();
204     FilterAndSendPacket(packet);
205   }
206   DCHECK(touch_packet_for_current_ack_handled);
207 }
208
209 bool TouchDispositionGestureFilter::IsEmpty() const {
210   return sequences_.empty();
211 }
212
213 void TouchDispositionGestureFilter::FilterAndSendPacket(
214     const GestureEventDataPacket& packet) {
215   if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_START) {
216     CancelTapIfNecessary(packet);
217     EndScrollIfNecessary(packet);
218     CancelFlingIfNecessary(packet);
219   } else if (packet.gesture_source() == GestureEventDataPacket::TOUCH_START) {
220     CancelTapIfNecessary(packet);
221   }
222
223   for (size_t i = 0; i < packet.gesture_count(); ++i) {
224     const GestureEventData& gesture = packet.gesture(i);
225     DCHECK_GE(gesture.details.type(), ET_GESTURE_TYPE_START);
226     DCHECK_LE(gesture.details.type(), ET_GESTURE_TYPE_END);
227     if (state_.Filter(gesture.details.type())) {
228       CancelTapIfNecessary(packet);
229       continue;
230     }
231     if (packet.gesture_source() == GestureEventDataPacket::TOUCH_TIMEOUT) {
232       // Sending a timed gesture could delete |this|, so we need to return
233       // directly after the |SendGesture| call.
234       SendGesture(gesture, packet);
235       return;
236     }
237
238     SendGesture(gesture, packet);
239   }
240
241   if (packet.gesture_source() ==
242       GestureEventDataPacket::TOUCH_SEQUENCE_CANCEL) {
243     EndScrollIfNecessary(packet);
244     CancelTapIfNecessary(packet);
245   } else if (packet.gesture_source() ==
246              GestureEventDataPacket::TOUCH_SEQUENCE_END) {
247     EndScrollIfNecessary(packet);
248   }
249 }
250
251 void TouchDispositionGestureFilter::SendGesture(
252     const GestureEventData& event,
253     const GestureEventDataPacket& packet_being_sent) {
254   // TODO(jdduke): Factor out gesture stream reparation code into a standalone
255   // utility class.
256   switch (event.type()) {
257     case ET_GESTURE_LONG_TAP:
258       if (!needs_tap_ending_event_)
259         return;
260       CancelTapIfNecessary(packet_being_sent);
261       CancelFlingIfNecessary(packet_being_sent);
262       break;
263     case ET_GESTURE_TAP_DOWN:
264       DCHECK(!needs_tap_ending_event_);
265       ending_event_motion_event_id_ = event.motion_event_id;
266       ending_event_primary_tool_type_ = event.primary_tool_type;
267       needs_show_press_event_ = true;
268       needs_tap_ending_event_ = true;
269       break;
270     case ET_GESTURE_SHOW_PRESS:
271       if (!needs_show_press_event_)
272         return;
273       needs_show_press_event_ = false;
274       break;
275     case ET_GESTURE_DOUBLE_TAP:
276       CancelTapIfNecessary(packet_being_sent);
277       needs_show_press_event_ = false;
278       break;
279     case ET_GESTURE_TAP:
280       DCHECK(needs_tap_ending_event_);
281       if (needs_show_press_event_) {
282         SendGesture(GestureEventData(ET_GESTURE_SHOW_PRESS, event),
283                     packet_being_sent);
284         DCHECK(!needs_show_press_event_);
285       }
286       needs_tap_ending_event_ = false;
287       break;
288     case ET_GESTURE_TAP_CANCEL:
289       needs_show_press_event_ = false;
290       needs_tap_ending_event_ = false;
291       break;
292     case ET_GESTURE_SCROLL_BEGIN:
293       CancelTapIfNecessary(packet_being_sent);
294       CancelFlingIfNecessary(packet_being_sent);
295       EndScrollIfNecessary(packet_being_sent);
296       ending_event_motion_event_id_ = event.motion_event_id;
297       ending_event_primary_tool_type_ = event.primary_tool_type;
298       needs_scroll_ending_event_ = true;
299       break;
300     case ET_GESTURE_SCROLL_END:
301       needs_scroll_ending_event_ = false;
302       break;
303     case ET_SCROLL_FLING_START:
304       CancelFlingIfNecessary(packet_being_sent);
305       ending_event_motion_event_id_ = event.motion_event_id;
306       ending_event_primary_tool_type_ = event.primary_tool_type;
307       needs_fling_ending_event_ = true;
308       needs_scroll_ending_event_ = false;
309       break;
310     case ET_SCROLL_FLING_CANCEL:
311       needs_fling_ending_event_ = false;
312       break;
313     default:
314       break;
315   }
316   client_->ForwardGestureEvent(event);
317 }
318
319 void TouchDispositionGestureFilter::CancelTapIfNecessary(
320     const GestureEventDataPacket& packet_being_sent) {
321   if (!needs_tap_ending_event_)
322     return;
323
324   SendGesture(CreateGesture(ET_GESTURE_TAP_CANCEL,
325                             ending_event_motion_event_id_,
326                             ending_event_primary_tool_type_,
327                             packet_being_sent),
328               packet_being_sent);
329   DCHECK(!needs_tap_ending_event_);
330 }
331
332 void TouchDispositionGestureFilter::CancelFlingIfNecessary(
333     const GestureEventDataPacket& packet_being_sent) {
334   if (!needs_fling_ending_event_)
335     return;
336
337   SendGesture(CreateGesture(ET_SCROLL_FLING_CANCEL,
338                             ending_event_motion_event_id_,
339                             ending_event_primary_tool_type_,
340                             packet_being_sent),
341               packet_being_sent);
342   DCHECK(!needs_fling_ending_event_);
343 }
344
345 void TouchDispositionGestureFilter::EndScrollIfNecessary(
346     const GestureEventDataPacket& packet_being_sent) {
347   if (!needs_scroll_ending_event_)
348     return;
349
350   SendGesture(CreateGesture(ET_GESTURE_SCROLL_END,
351                             ending_event_motion_event_id_,
352                             ending_event_primary_tool_type_,
353                             packet_being_sent),
354               packet_being_sent);
355   DCHECK(!needs_scroll_ending_event_);
356 }
357
358 void TouchDispositionGestureFilter::PopGestureSequence() {
359   DCHECK(Head().empty());
360   state_ = GestureHandlingState();
361   sequences_.pop();
362 }
363
364 TouchDispositionGestureFilter::GestureSequence&
365 TouchDispositionGestureFilter::Head() {
366   DCHECK(!sequences_.empty());
367   return sequences_.front();
368 }
369
370 TouchDispositionGestureFilter::GestureSequence&
371 TouchDispositionGestureFilter::Tail() {
372   DCHECK(!sequences_.empty());
373   return sequences_.back();
374 }
375
376 // TouchDispositionGestureFilter::GestureHandlingState
377
378 TouchDispositionGestureFilter::GestureHandlingState::GestureHandlingState()
379     : start_touch_consumed_(false),
380       current_touch_consumed_(false) {}
381
382 void TouchDispositionGestureFilter::GestureHandlingState::OnTouchEventAck(
383     bool event_consumed,
384     bool is_touch_start_event) {
385   current_touch_consumed_ = event_consumed;
386   if (event_consumed && is_touch_start_event)
387     start_touch_consumed_ = true;
388 }
389
390 bool TouchDispositionGestureFilter::GestureHandlingState::Filter(
391     EventType gesture_type) {
392   DispositionHandlingInfo disposition_handling_info =
393       GetDispositionHandlingInfo(gesture_type);
394
395   int required_touches = disposition_handling_info.required_touches;
396   EventType antecedent_event_type =
397       disposition_handling_info.antecedent_event_type;
398   if ((required_touches & RT_START && start_touch_consumed_) ||
399       (required_touches & RT_CURRENT && current_touch_consumed_) ||
400       (antecedent_event_type != ET_UNKNOWN &&
401        last_gesture_of_type_dropped_.has_bit(
402            GetGestureTypeIndex(antecedent_event_type)))) {
403     last_gesture_of_type_dropped_.mark_bit(GetGestureTypeIndex(gesture_type));
404     return true;
405   }
406   last_gesture_of_type_dropped_.clear_bit(GetGestureTypeIndex(gesture_type));
407   return false;
408 }
409
410 }  // namespace content