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

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

Issue 120513005: [Android] Perform eager gesture recognition on MotionEvents (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code cleanup 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/gesture_event_queue.h"
6
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "content/common/input/web_input_event_traits.h"
11
12 using blink::WebGestureEvent;
13 using blink::WebInputEvent;
14 using blink::WebTouchEvent;
15 using blink::WebTouchPoint;
16
17 namespace content {
18 namespace {
19
20 InputEventAckState GetMostRestrictiveState(InputEventAckState ack_old,
21 InputEventAckState ack_new) {
22 DCHECK_NE(INPUT_EVENT_ACK_STATE_UNKNOWN, ack_new);
23
24 switch (ack_old) {
25 case INPUT_EVENT_ACK_STATE_UNKNOWN:
26 return ack_new;
27
28 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
29 return ack_new == INPUT_EVENT_ACK_STATE_CONSUMED ? ack_new : ack_old;
30
31 case INPUT_EVENT_ACK_STATE_CONSUMED:
32 case INPUT_EVENT_ACK_STATE_IGNORED:
33 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
34 default:
35 return ack_old;
36 };
37 }
38
39 WebGestureEvent CreateGesture(WebInputEvent::Type type) {
40 DCHECK(WebInputEvent::isGestureEventType(type));
41 WebGestureEvent event;
42 event.type = type;
43 event.sourceDevice = WebGestureEvent::Touchscreen;
44 return event;
45 }
46
47 } // namespace
48
49 GestureEventQueue::GestureEventQueue(GestureEventQueueClient* client)
50 : client_(client),
51 packet_sender_(base::Bind(&GestureEventQueue::SendPacket,
52 base::Unretained(this))),
53 outstanding_tap_(false),
54 outstanding_fling_(false) {
55 DCHECK(client_);
56 }
57
58 GestureEventQueue::~GestureEventQueue() {}
59
60 void GestureEventQueue::OnGestureEventPacket(const GestureEventPacket& packet) {
61 switch (packet.gesture_source()) {
62 case GestureEventPacket::TOUCH_BEGIN:
63 sequences_.push_back(GestureSequence());
64 break;
65
66 case GestureEventPacket::TOUCH:
67 break;
68
69 case GestureEventPacket::TOUCH_TIMEOUT:
70 // Handle the timeout packet immediately if the packet preceding the
71 // timeout has already been dispatched.
72 if (Tail().IsEmpty()) {
73 if (Tail().IsGestureAllowed())
74 SendPacket(packet);
75 return;
76 }
77 break;
78
79 case GestureEventPacket::SYNTHETIC:
80 // Handle the synthetic packet immediately if no other packets pending.
81 if (sequences_.empty() || Tail().IsEmpty()) {
82 SendPacket(packet);
83 return;
84 }
85 // Otherwise, queue the packet and process it in-order, irrespective
86 // of the touch sequence disposition.
87 break;
88 }
89
90 Tail().Push(packet);
91 }
92
93 void GestureEventQueue::OnTouchEventAck(InputEventAckState ack_state) {
94 if (Head().IsEmpty()) {
95 CancelTapIfNecessary();
96 CancelFlingIfNecessary();
97 sequences_.pop_front();
98 }
99
100 Head().OnTouchEventAck(ack_state, packet_sender_);
101
102 // Immediately cancel a TapDown if TouchStart went unconsumed, but a
103 // subsequent TouchMove is consumed.
104 if (!Head().IsGestureAllowed())
105 CancelTapIfNecessary();
106 }
107
108 void GestureEventQueue::SendPacket(const GestureEventPacket& packet) {
109 for (size_t i = 0; i < packet.gesture_count(); ++i)
110 SendGesture(packet.gesture(i));
111 }
112
113 void GestureEventQueue::SendGesture(const WebGestureEvent& event) {
114 switch (event.type) {
115 case WebInputEvent::GestureScrollBegin:
116 case WebInputEvent::GestureLongTap:
117 CancelTapIfNecessary();
118 break;
119 case WebInputEvent::GestureTapDown:
120 outstanding_tap_ = true;
121 break;
122 case WebInputEvent::GestureTapCancel:
123 case WebInputEvent::GestureTap:
124 case WebInputEvent::GestureTapUnconfirmed:
125 case WebInputEvent::GestureDoubleTap:
126 outstanding_tap_ = false;
127 break;
128 case WebInputEvent::GestureFlingStart:
129 outstanding_fling_ = true;
130 break;
131 case WebInputEvent::GestureFlingCancel:
132 outstanding_fling_ = false;
133 break;
134 default:
135 break;
136 }
137 client_->ForwardGestureEvent(event);
138 }
139
140 void GestureEventQueue::CancelTapIfNecessary() {
141 if (!outstanding_tap_)
142 return;
143
144 SendGesture(CreateGesture(WebInputEvent::GestureTapCancel));
145 DCHECK(!outstanding_tap_);
146 }
147
148 void GestureEventQueue::CancelFlingIfNecessary() {
149 if (!outstanding_fling_)
150 return;
151
152 SendGesture(CreateGesture(WebInputEvent::GestureFlingCancel));
153 DCHECK(!outstanding_fling_);
154 }
155
156 GestureEventQueue::GestureSequence& GestureEventQueue::Head() {
157 DCHECK(!sequences_.empty());
158 return sequences_.front();
159 }
160
161 GestureEventQueue::GestureSequence& GestureEventQueue::Tail() {
162 DCHECK(!sequences_.empty());
163 return sequences_.back();
164 }
165
166
167 GestureEventQueue::GestureSequence::GestureSequence()
168 : ack_state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
169
170 GestureEventQueue::GestureSequence::~GestureSequence() {}
171
172 void GestureEventQueue::GestureSequence::Push(
173 const GestureEventPacket& packet) {
174 if (packet.gesture_source() == GestureEventPacket::TOUCH_TIMEOUT ||
175 packet.gesture_source() == GestureEventPacket::SYNTHETIC) {
176 // Timeout-derived gestures should have been forwarded or dropped
177 // immediately if the sequence was empty.
178 DCHECK(!IsEmpty());
179 }
180 sequence_.push_back(packet);
181 }
182
183 void GestureEventQueue::GestureSequence::OnTouchEventAck(
184 InputEventAckState new_ack_state,
185 const PacketSender& packet_sender) {
186 InputEventAckState old_ack_state = ack_state_;
187 ack_state_ = GetMostRestrictiveState(old_ack_state, new_ack_state);
188
189 bool packet_for_current_ack_handled = false;
190 while (!IsEmpty()) {
191 const GestureEventPacket& packet = sequence_.front();
192
193 switch (packet.gesture_source()) {
194 case GestureEventPacket::TOUCH_BEGIN:
195 case GestureEventPacket::TOUCH:
196 // We should handle at most one packet corresponding to a given ack.
197 if (packet_for_current_ack_handled)
198 return;
199 packet_for_current_ack_handled = true;
200
201 if (IsGestureAllowed())
202 packet_sender.Run(packet);
203 break;
204
205 case GestureEventPacket::TOUCH_TIMEOUT:
206 if (IsGestureAllowed())
207 packet_sender.Run(packet);
208 break;
209
210 case GestureEventPacket::SYNTHETIC:
211 // Synthetic gestures should be dispatched regardless of the touch
212 // sequence disposition.
213 packet_sender.Run(packet);
214 break;
215 };
216
217 sequence_.pop_front();
218 }
219 DCHECK(packet_for_current_ack_handled);
220 }
221
222 bool GestureEventQueue::GestureSequence::IsGestureAllowed() const {
223 return ack_state_ == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS ||
224 ack_state_ == INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
225 }
226
227 bool GestureEventQueue::GestureSequence::IsEmpty() const {
228 return sequence_.empty();
229 }
230
231 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698