OLD | NEW |
| (Empty) |
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 "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 | |
11 using blink::WebGestureEvent; | |
12 using blink::WebInputEvent; | |
13 using blink::WebTouchEvent; | |
14 using blink::WebTouchPoint; | |
15 | |
16 namespace content { | |
17 namespace { | |
18 | |
19 WebGestureEvent CreateGesture(WebInputEvent::Type type) { | |
20 DCHECK(WebInputEvent::isGestureEventType(type)); | |
21 WebGestureEvent event; | |
22 event.type = type; | |
23 event.sourceDevice = WebGestureEvent::Touchscreen; | |
24 return event; | |
25 } | |
26 | |
27 } // namespace | |
28 | |
29 // GestureEventQueue | |
30 | |
31 GestureEventQueue::GestureEventQueue(GestureEventQueueClient* client) | |
32 : client_(client), | |
33 needs_tap_ending_event_(false), | |
34 needs_fling_ending_event_(false) { | |
35 DCHECK(client_); | |
36 } | |
37 | |
38 GestureEventQueue::~GestureEventQueue() {} | |
39 | |
40 void GestureEventQueue::OnGestureEventPacket(const GestureEventPacket& packet) { | |
41 switch (packet.gesture_source()) { | |
42 case GestureEventPacket::TOUCH_BEGIN: | |
43 sequences_.push(GestureSequence()); | |
44 break; | |
45 | |
46 case GestureEventPacket::TOUCH: | |
47 break; | |
48 | |
49 case GestureEventPacket::TOUCH_TIMEOUT: | |
50 // Handle the timeout packet immediately if the packet preceding the | |
51 // timeout has already been dispatched. | |
52 if (Tail().IsEmpty()) { | |
53 if (!Tail().IsGesturePrevented()) | |
54 SendPacket(packet); | |
55 return; | |
56 } | |
57 break; | |
58 | |
59 case GestureEventPacket::INVALID: | |
60 NOTREACHED() << "Invalid gesture packet detected."; | |
61 break; | |
62 } | |
63 | |
64 Tail().Push(packet); | |
65 } | |
66 | |
67 void GestureEventQueue::OnTouchEventAck(InputEventAckState ack_state) { | |
68 if (Head().IsEmpty()) { | |
69 CancelTapIfNecessary(); | |
70 CancelFlingIfNecessary(); | |
71 sequences_.pop(); | |
72 } | |
73 | |
74 GestureSequence& sequence = Head(); | |
75 sequence.UpdateState(ack_state); | |
76 | |
77 // Dispatch the packet corresponding to the ack'ed touch, as well as any | |
78 // additional timeout-based packets queued before the ack was received. | |
79 bool touch_packet_for_current_ack_handled = false; | |
80 while (!sequence.IsEmpty()) { | |
81 const GestureEventPacket& packet = sequence.Front(); | |
82 | |
83 if (packet.gesture_source() == GestureEventPacket::TOUCH_BEGIN || | |
84 packet.gesture_source() == GestureEventPacket::TOUCH) { | |
85 // We should handle at most one touch-based packet corresponding to a | |
86 // given ack. | |
87 if (touch_packet_for_current_ack_handled) | |
88 break; | |
89 touch_packet_for_current_ack_handled = true; | |
90 } | |
91 | |
92 if (!sequence.IsGesturePrevented()) | |
93 SendPacket(packet); | |
94 | |
95 sequence.Pop(); | |
96 } | |
97 DCHECK(touch_packet_for_current_ack_handled); | |
98 | |
99 // Immediately cancel a TapDown if TouchStart went unconsumed, but a | |
100 // subsequent TouchMove is consumed. | |
101 if (sequence.IsGesturePrevented()) | |
102 CancelTapIfNecessary(); | |
103 } | |
104 | |
105 void GestureEventQueue::SendPacket(const GestureEventPacket& packet) { | |
106 for (size_t i = 0; i < packet.gesture_count(); ++i) | |
107 SendGesture(packet.gesture(i)); | |
108 } | |
109 | |
110 void GestureEventQueue::SendGesture(const WebGestureEvent& event) { | |
111 switch (event.type) { | |
112 case WebInputEvent::GestureLongTap: | |
113 CancelTapIfNecessary(); | |
114 CancelFlingIfNecessary(); | |
115 break; | |
116 case WebInputEvent::GestureTapDown: | |
117 needs_tap_ending_event_ = true; | |
118 break; | |
119 case WebInputEvent::GestureTapCancel: | |
120 case WebInputEvent::GestureTap: | |
121 case WebInputEvent::GestureTapUnconfirmed: | |
122 case WebInputEvent::GestureDoubleTap: | |
123 needs_tap_ending_event_ = false; | |
124 break; | |
125 case WebInputEvent::GestureScrollBegin: | |
126 CancelTapIfNecessary(); | |
127 CancelFlingIfNecessary(); | |
128 break; | |
129 case WebInputEvent::GestureFlingStart: | |
130 CancelFlingIfNecessary(); | |
131 needs_fling_ending_event_ = true; | |
132 break; | |
133 case WebInputEvent::GestureFlingCancel: | |
134 needs_fling_ending_event_ = false; | |
135 break; | |
136 default: | |
137 break; | |
138 } | |
139 client_->ForwardGestureEvent(event); | |
140 } | |
141 | |
142 void GestureEventQueue::CancelTapIfNecessary() { | |
143 if (!needs_tap_ending_event_) | |
144 return; | |
145 | |
146 SendGesture(CreateGesture(WebInputEvent::GestureTapCancel)); | |
147 DCHECK(!needs_tap_ending_event_); | |
148 } | |
149 | |
150 void GestureEventQueue::CancelFlingIfNecessary() { | |
151 if (!needs_fling_ending_event_) | |
152 return; | |
153 | |
154 SendGesture(CreateGesture(WebInputEvent::GestureFlingCancel)); | |
155 DCHECK(!needs_fling_ending_event_); | |
156 } | |
157 | |
158 GestureEventQueue::GestureSequence& GestureEventQueue::Head() { | |
159 DCHECK(!sequences_.empty()); | |
160 return sequences_.front(); | |
161 } | |
162 | |
163 GestureEventQueue::GestureSequence& GestureEventQueue::Tail() { | |
164 DCHECK(!sequences_.empty()); | |
165 return sequences_.back(); | |
166 } | |
167 | |
168 | |
169 // GestureEventQueue::GestureSequence | |
170 | |
171 GestureEventQueue::GestureSequence::GestureSequence() | |
172 : state_(PENDING) {} | |
173 | |
174 GestureEventQueue::GestureSequence::~GestureSequence() {} | |
175 | |
176 void GestureEventQueue::GestureSequence::Push( | |
177 const GestureEventPacket& packet) { | |
178 packets_.push(packet); | |
179 } | |
180 | |
181 void GestureEventQueue::GestureSequence::Pop() { | |
182 DCHECK(!IsEmpty()); | |
183 packets_.pop(); | |
184 } | |
185 | |
186 const GestureEventPacket& GestureEventQueue::GestureSequence::Front() const { | |
187 DCHECK(!IsEmpty()); | |
188 return packets_.front(); | |
189 } | |
190 | |
191 void GestureEventQueue::GestureSequence::UpdateState( | |
192 InputEventAckState ack_state) { | |
193 DCHECK_NE(INPUT_EVENT_ACK_STATE_UNKNOWN, ack_state); | |
194 // Permanent states will not be affected by subsequent ack's. | |
195 if (state_ != PENDING && state_ != ALLOWED_UNTIL_PREVENTED) | |
196 return; | |
197 | |
198 // |NO_CONSUMER| should only be effective when the *first* touch is ack'ed. | |
199 if (state_ == PENDING && | |
200 ack_state == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | |
201 state_ = ALWAYS_ALLOWED; | |
202 else if (ack_state == INPUT_EVENT_ACK_STATE_CONSUMED) | |
203 state_ = ALWAYS_PREVENTED; | |
204 else | |
205 state_ = ALLOWED_UNTIL_PREVENTED; | |
206 } | |
207 | |
208 bool GestureEventQueue::GestureSequence::IsGesturePrevented() const { | |
209 return state_ == ALWAYS_PREVENTED; | |
210 } | |
211 | |
212 bool GestureEventQueue::GestureSequence::IsEmpty() const { | |
213 return packets_.empty(); | |
214 } | |
215 | |
216 } // namespace content | |
OLD | NEW |