Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: content/browser/renderer_host/input/touch_to_gesture_queue.cc

Issue 120513005: [Android] Perform eager gesture recognition on MotionEvents (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove LongPressDetector entirely (happiness) Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/browser/renderer_host/input/touch_to_gesture_queue.h"
6
7 #include "base/auto_reset.h"
8 #include "base/logging.h"
9 #include "content/common/input/web_input_event_traits.h"
10
11 using blink::WebGestureEvent;
12 using blink::WebInputEvent;
13 using blink::WebTouchEvent;
14 using blink::WebTouchPoint;
15
16 namespace content {
17 namespace {
18
19 bool IsTouchSequenceBegin(const WebTouchEvent& event) {
20 if (event.type != WebInputEvent::TouchStart)
21 return false;
22 if (!event.touchesLength)
23 return false;
24 for (size_t i = 0; i < event.touchesLength; i++) {
25 if (event.touches[i].state != WebTouchPoint::StatePressed)
26 return false;
27 }
28 return true;
29 }
30
31 bool IsScrollStart(const WebGestureEvent& event) {
32 return event.type == WebInputEvent::GestureScrollBegin;
33 }
34
35 bool IsFlingCancel(const WebGestureEvent& event) {
36 return event.type == WebInputEvent::GestureFlingCancel;
37 }
38
39 bool IsFlingStart(const WebGestureEvent& event) {
40 return event.type == WebInputEvent::GestureFlingStart;
41 }
42
43 bool IsTapStart(const WebGestureEvent& event) {
44 return event.type == WebInputEvent::GestureTapDown;
45 }
46
47 bool IsTapEnd(const WebGestureEvent& event) {
48 switch (event.type) {
49 case WebInputEvent::GestureTapCancel:
50 case WebInputEvent::GestureTap:
51 case WebInputEvent::GestureTapUnconfirmed:
52 case WebInputEvent::GestureDoubleTap:
53 return true;
54 default:
55 break;
56 }
57 return false;
58 }
59
60 bool IsTimeout(const WebGestureEvent& event) {
tdresser 2014/01/14 16:25:30 Perhaps IsTimeout -> IsTriggeredByTimeout?
jdduke (slow) 2014/01/14 23:24:03 Done.
61 switch (event.type) {
62 case WebInputEvent::GestureShowPress:
63 case WebInputEvent::GestureLongPress:
64 case WebInputEvent::GestureTapUnconfirmed:
65 return true;
66 default:
67 break;
68 }
69 return false;
70 }
71
72 InputEventAckState Intersection(InputEventAckState ack_old,
tdresser 2014/01/14 16:25:30 The word "Intersection" applied to an enum could b
jdduke (slow) 2014/01/14 23:24:03 Hmm, I'll noodle on this.
73 InputEventAckState ack_new) {
74 if (ack_new == INPUT_EVENT_ACK_STATE_UNKNOWN) {
75 NOTREACHED() << "New acks should never be undefined.";
76 return ack_old;
77 }
78
79 if (ack_old == INPUT_EVENT_ACK_STATE_UNKNOWN ||
80 ack_old == INPUT_EVENT_ACK_STATE_NOT_CONSUMED)
81 return ack_new;
82
83 // If a partial touch sequence has been consumed, or has no consumer,
84 // subsequent touches have no bearing on the overall gesture disposition.
85 return ack_old;
86 }
87
88 WebGestureEvent CreateGesture(WebInputEvent::Type type) {
89 DCHECK(WebInputEvent::isGestureEventType(type));
90 WebGestureEvent event;
91 event.type = type;
92 event.sourceDevice = WebGestureEvent::Touchscreen;
93 return event;
94 }
95
96 } // namespace
97
98 TouchToGestureQueue::TouchToGestureQueue(TouchToGestureQueueClient* client)
99 : client_(client),
100 handling_touch_event_(false),
101 outstanding_tap_(false),
102 outstanding_fling_(false) {
103 DCHECK(client_);
104 }
105
106 TouchToGestureQueue::~TouchToGestureQueue() {}
107
108 void TouchToGestureQueue::OnTouchEventHandlingBegin(
109 const WebTouchEvent& event) {
110 DCHECK(!handling_touch_event_);
111 handling_touch_event_ = true;
112
113 if (IsTouchSequenceBegin(event))
114 sequences_.push_back(TouchToGestureSequence());
115
116 Tail().Push(event);
117 }
118
119 void TouchToGestureQueue::OnTouchEventHandlingEnd() {
120 DCHECK(handling_touch_event_);
121 DCHECK(!sequences_.empty());
122
123 handling_touch_event_ = false;
124 client_->ForwardTouchEvent(Tail().LastTouch());
125 }
126
127 void TouchToGestureQueue::OnGestureEvent(const WebGestureEvent& event) {
128 if (handling_touch_event_) {
129 Tail().Push(event);
130 return;
131 }
132
133 if (IsTimeout(event)) {
134 // Touches preceding the timeout event are still awaiting an ack.
135 if (!Tail().IsEmpty())
136 Tail().Push(event);
137 // Touches preceding the timeout have been handled and gestures are allowed.
138 else if (Tail().IsGestureAllowed())
139 ForwardGestureEvent(event);
140 // The timeout gesture should be dropped.
141 return;
142 }
143
144 // Synthetic gestures may be generated by the platform, in which case they
145 // should simply be forwarded immediately.
146 ForwardGestureEvent(event);
147 }
148
149 void TouchToGestureQueue::OnTouchEventAck(InputEventAckState ack_state) {
150 // Transition to the next touch sequence. This transition is deferred
151 // until the ack in the event that the sequence receives a timeout event.
152 if (Head().IsEmpty()) {
153 CancelTapIfNecessary();
154 CancelFlingIfNecessary();
155 sequences_.pop_front();
156 }
157
158 // TODO(jdduke): Settle on touch-slop disposition behavior, crbug/333947.
159 TouchToGesture touch_to_gesture = Head().OnTouchEventAck(ack_state);
160 for (size_t i = 0; i < touch_to_gesture.gestures.size(); ++i)
161 ForwardGestureEvent(touch_to_gesture.gestures[i]);
162
163 // Immediately cancel a TapDown if TouchStart went unconsumed, but a
164 // subsequent TouchMove is consumed.
165 if (!Head().IsGestureAllowed())
166 CancelTapIfNecessary();
167 }
168
169 void TouchToGestureQueue::ForwardGestureEvent(const WebGestureEvent& event) {
tdresser 2014/01/14 16:25:30 I don't think this is any more readable than a big
jdduke (slow) 2014/01/14 23:24:03 You're totally right, this originally started with
170 if (IsTapStart(event))
171 outstanding_tap_ = true;
172 else if (IsTapEnd(event))
173 outstanding_tap_ = false;
174 else if (IsFlingStart(event))
175 outstanding_fling_ = true;
176 else if (IsFlingCancel(event))
177 outstanding_fling_ = false;
178 else if (IsScrollStart(event))
179 CancelTapIfNecessary();
180
181 client_->ForwardGestureEvent(event);
182 }
183
184 void TouchToGestureQueue::CancelTapIfNecessary() {
185 if (!outstanding_tap_)
186 return;
187
188 ForwardGestureEvent(CreateGesture(WebInputEvent::GestureTapCancel));
189 DCHECK(!outstanding_tap_);
190 }
191
192 void TouchToGestureQueue::CancelFlingIfNecessary() {
193 if (!outstanding_fling_)
194 return;
195
196 ForwardGestureEvent(CreateGesture(WebInputEvent::GestureFlingCancel));
197 DCHECK(!outstanding_fling_);
198 }
199
200 TouchToGestureQueue::TouchToGestureSequence& TouchToGestureQueue::Head() {
201 DCHECK(!sequences_.empty());
202 return sequences_.front();
203 }
204
205 TouchToGestureQueue::TouchToGestureSequence& TouchToGestureQueue::Tail() {
206 DCHECK(!sequences_.empty());
207 return sequences_.back();
208 }
209
210 TouchToGestureQueue::TouchToGestureSequence::TouchToGestureSequence()
211 : ack_state(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
212
213 TouchToGestureQueue::TouchToGestureSequence::~TouchToGestureSequence() {}
214
215 void TouchToGestureQueue::TouchToGestureSequence::Push(
216 const blink::WebTouchEvent& event) {
217 TouchToGesture touch_to_gesture;
218 touch_to_gesture.touch = event;
219 sequence.push_back(touch_to_gesture);
220 }
221
222 void TouchToGestureQueue::TouchToGestureSequence::Push(
223 const blink::WebGestureEvent& event) {
224 DCHECK(!IsEmpty());
225 sequence.back().gestures.push_back(event);
226 }
227
228 TouchToGestureQueue::TouchToGesture
229 TouchToGestureQueue::TouchToGestureSequence::OnTouchEventAck(
230 InputEventAckState new_ack_state) {
231 DCHECK(!IsEmpty());
232
233 ack_state = Intersection(ack_state, new_ack_state);
234 DCHECK_NE(ack_state, INPUT_EVENT_ACK_STATE_UNKNOWN);
235
236 TouchToGesture touch_to_gesture =
237 IsGestureAllowed() ? sequence.front() : TouchToGesture();
238 sequence.pop_front();
239 return touch_to_gesture;
240 }
241
242 bool TouchToGestureQueue::TouchToGestureSequence::IsGestureAllowed() const {
243 return ack_state == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS ||
244 ack_state == INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
245 }
246
247 bool TouchToGestureQueue::TouchToGestureSequence::IsEmpty() const {
248 return sequence.empty();
249 }
250
251 const blink::WebTouchEvent&
252 TouchToGestureQueue::TouchToGestureSequence::LastTouch() const {
253 DCHECK(!IsEmpty());
254 return sequence.back().touch;
255 }
256
257 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698