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

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: More 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 WebGestureEvent CreateGesture(WebInputEvent::Type type) {
21 DCHECK(WebInputEvent::isGestureEventType(type));
22 WebGestureEvent event;
23 event.type = type;
24 event.sourceDevice = WebGestureEvent::Touchscreen;
25 return event;
26 }
27
28 } // namespace
29
30 GestureEventQueue::GestureEventQueue(GestureEventQueueClient* client)
31 : client_(client),
32 packet_sender_(base::Bind(&GestureEventQueue::SendPacket,
33 base::Unretained(this))),
34 outstanding_tap_(false),
35 outstanding_fling_(false) {
36 DCHECK(client_);
37 }
38
39 GestureEventQueue::~GestureEventQueue() {}
40
41 void GestureEventQueue::OnGestureEventPacket(const GestureEventPacket& packet) {
42 switch (packet.gesture_source()) {
43 case GestureEventPacket::TOUCH_BEGIN:
44 sequences_.push_back(GestureSequence());
45 break;
46
47 case GestureEventPacket::TOUCH:
48 break;
49
50 case GestureEventPacket::TOUCH_TIMEOUT:
51 // Handle the timeout packet immediately if the packet preceding the
52 // timeout has already been dispatched.
53 if (Tail().IsEmpty()) {
54 if (!Tail().IsGesturePrevented())
55 SendPacket(packet);
56 return;
57 }
58 break;
59
60 case GestureEventPacket::SYNTHETIC:
tdresser 2014/01/23 16:32:43 If this is only for things like WebView's zoom con
jdduke (slow) 2014/01/23 22:52:34 Honestly I have no idea. I don't think it hurts t
61 // Handle the synthetic packet immediately if no other packets pending.
62 if (sequences_.empty() || Tail().IsEmpty()) {
63 SendPacket(packet);
64 return;
65 }
66 // Otherwise, queue the packet and process it in-order, irrespective
67 // of the touch sequence disposition.
68 break;
69 }
70
71 Tail().Push(packet);
72 }
73
74 void GestureEventQueue::OnTouchEventAck(InputEventAckState ack_state) {
tdresser 2014/01/23 16:32:43 A DCHECK(!sequences.empty()) might be good here.
jdduke (slow) 2014/01/23 22:52:34 Sure. The |Head()| call performs that check, but I
tdresser 2014/01/24 13:47:30 Oh, good point. In that case I have no strong feel
75 if (Head().IsEmpty()) {
76 CancelTapIfNecessary();
77 CancelFlingIfNecessary();
78 sequences_.pop_front();
79 }
80
tdresser 2014/01/23 16:32:43 A DCHECK(!sequences.empty()) might be good here to
jdduke (slow) 2014/01/24 05:34:40 Done.
81 Head().OnTouchEventAck(ack_state, packet_sender_);
82
83 // Immediately cancel a TapDown if TouchStart went unconsumed, but a
84 // subsequent TouchMove is consumed.
85 if (Head().IsGesturePrevented())
86 CancelTapIfNecessary();
87 }
88
89 void GestureEventQueue::SendPacket(const GestureEventPacket& packet) {
90 for (size_t i = 0; i < packet.gesture_count(); ++i)
91 SendGesture(packet.gesture(i));
92 }
93
94 void GestureEventQueue::SendGesture(const WebGestureEvent& event) {
95 switch (event.type) {
96 case WebInputEvent::GestureScrollBegin:
97 case WebInputEvent::GestureLongTap:
98 CancelTapIfNecessary();
99 break;
100 case WebInputEvent::GestureTapDown:
101 outstanding_tap_ = true;
102 break;
103 case WebInputEvent::GestureTapCancel:
104 case WebInputEvent::GestureTap:
105 case WebInputEvent::GestureTapUnconfirmed:
106 case WebInputEvent::GestureDoubleTap:
107 outstanding_tap_ = false;
108 break;
109 case WebInputEvent::GestureFlingStart:
110 CancelFlingIfNecessary();
111 outstanding_fling_ = true;
112 break;
113 case WebInputEvent::GestureFlingCancel:
114 outstanding_fling_ = false;
115 break;
116 default:
117 break;
118 }
119 client_->ForwardGestureEvent(event);
120 }
121
122 void GestureEventQueue::CancelTapIfNecessary() {
123 if (!outstanding_tap_)
124 return;
125
126 SendGesture(CreateGesture(WebInputEvent::GestureTapCancel));
127 DCHECK(!outstanding_tap_);
128 }
129
130 void GestureEventQueue::CancelFlingIfNecessary() {
131 if (!outstanding_fling_)
132 return;
133
134 SendGesture(CreateGesture(WebInputEvent::GestureFlingCancel));
135 DCHECK(!outstanding_fling_);
136 }
137
138 GestureEventQueue::GestureSequence& GestureEventQueue::Head() {
139 DCHECK(!sequences_.empty());
140 return sequences_.front();
141 }
142
143 GestureEventQueue::GestureSequence& GestureEventQueue::Tail() {
144 DCHECK(!sequences_.empty());
145 return sequences_.back();
146 }
147
148
tdresser 2014/01/23 16:32:43 Perhaps a comment separating GestureEventQueue met
jdduke (slow) 2014/01/23 22:52:34 Done.
149 GestureEventQueue::GestureSequence::GestureSequence()
150 : state_(PENDING) {}
151
152 GestureEventQueue::GestureSequence::~GestureSequence() {}
153
154 void GestureEventQueue::GestureSequence::Push(
155 const GestureEventPacket& packet) {
156 if (packet.gesture_source() == GestureEventPacket::TOUCH_TIMEOUT ||
157 packet.gesture_source() == GestureEventPacket::SYNTHETIC) {
158 // Timeout-derived gestures should have been forwarded or dropped
159 // immediately if the sequence was empty.
160 DCHECK(!IsEmpty());
161 }
162 sequence_.push_back(packet);
163 }
164
165 void GestureEventQueue::GestureSequence::OnTouchEventAck(
166 InputEventAckState ack_state,
167 const PacketSender& packet_sender) {
168 DCHECK_NE(INPUT_EVENT_ACK_STATE_UNKNOWN, ack_state);
169
170 if (state_ == PENDING || state_ == ALLOWED) {
171 // |NO_CONSUMER| should only be effective when the *first* touch is ack'ed.
tdresser 2014/01/23 16:32:43 If we get an INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXI
jdduke (slow) 2014/01/23 22:52:34 If the primary pointer press was NOT_CONSUMED, but
tdresser 2014/01/24 13:47:30 That's unfortunate. Looks good then.
172 if (state_ == PENDING &&
173 ack_state == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
174 state_ = ALWAYS_ALLOWED;
175 else if (ack_state == INPUT_EVENT_ACK_STATE_CONSUMED)
176 state_ = ALWAYS_PREVENTED;
177 else
178 state_ = ALLOWED;
179 }
180
181 bool packet_for_current_ack_handled = false;
182 while (!IsEmpty()) {
183 const GestureEventPacket& packet = sequence_.front();
184
185 switch (packet.gesture_source()) {
186 case GestureEventPacket::TOUCH_BEGIN:
187 case GestureEventPacket::TOUCH:
188 // We should handle at most one packet corresponding to a given ack.
189 if (packet_for_current_ack_handled)
190 return;
191 packet_for_current_ack_handled = true;
192
193 if (!IsGesturePrevented())
194 packet_sender.Run(packet);
195 break;
196
197 case GestureEventPacket::TOUCH_TIMEOUT:
198 if (!IsGesturePrevented())
199 packet_sender.Run(packet);
200 break;
201
202 case GestureEventPacket::SYNTHETIC:
203 // Synthetic gestures should be dispatched regardless of the touch
204 // sequence disposition.
205 packet_sender.Run(packet);
206 break;
207 };
208
209 sequence_.pop_front();
210 }
211 DCHECK(packet_for_current_ack_handled);
212 }
213
214 bool GestureEventQueue::GestureSequence::IsGesturePrevented() const {
215 return state_ == ALWAYS_PREVENTED;
216 }
217
218 bool GestureEventQueue::GestureSequence::IsEmpty() const {
219 return sequence_.empty();
220 }
221
222 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698