OLD | NEW |
---|---|
(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 "base/basictypes.h" | |
6 #include "base/memory/scoped_ptr.h" | |
7 #include "content/browser/renderer_host/input/gesture_event_queue.h" | |
8 #include "content/common/input/synthetic_web_input_event_builders.h" | |
9 #include "content/common/input/web_input_event_traits.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
12 | |
13 using blink::WebGestureEvent; | |
14 using blink::WebInputEvent; | |
15 using blink::WebTouchEvent; | |
16 using blink::WebTouchPoint; | |
17 | |
18 namespace content { | |
19 | |
20 class GestureEventQueueTest : public testing::Test, | |
21 public GestureEventQueueClient { | |
22 public: | |
23 GestureEventQueueTest() : sent_gesture_count_(0) {} | |
24 | |
25 virtual ~GestureEventQueueTest() {} | |
26 | |
27 // testing::Test | |
28 virtual void SetUp() OVERRIDE { | |
29 queue_.reset(new GestureEventQueue(this)); | |
30 } | |
31 | |
32 virtual void TearDown() OVERRIDE { | |
33 queue_.reset(); | |
34 } | |
35 | |
36 // GestureEventQueueClient | |
37 virtual void ForwardGestureEvent(const WebGestureEvent& event) OVERRIDE { | |
38 ++sent_gesture_count_; | |
39 sent_gestures_.push_back(event.type); | |
40 } | |
41 | |
42 protected: | |
43 typedef std::vector<WebInputEvent::Type> GestureList; | |
44 | |
45 ::testing::AssertionResult GesturesMatch(const GestureList& expected, | |
46 const GestureList& actual) { | |
47 if (expected.size() != actual.size()) { | |
48 return ::testing::AssertionFailure() | |
49 << "actual.size(" << actual.size() | |
50 << ") != expected.size(" << expected.size() << ")"; | |
51 } | |
52 | |
53 for (size_t i = 0; i < expected.size(); ++i) { | |
54 if (expected[i] != actual[i]) { | |
55 return ::testing::AssertionFailure() | |
56 << "actual[" << i << "] (" | |
57 << WebInputEventTraits::GetName(actual[i]) | |
58 << ") != expected[" << i << "] (" | |
59 << WebInputEventTraits::GetName(expected[i]) << ")"; | |
60 } | |
61 } | |
62 | |
63 return ::testing::AssertionSuccess(); | |
64 } | |
65 | |
66 GestureList Gestures(WebInputEvent::Type type) { | |
67 return GestureList(1, type); | |
68 } | |
69 | |
70 GestureList Gestures(WebInputEvent::Type type0, WebInputEvent::Type type1) { | |
71 GestureList gestures(2); | |
72 gestures[0] = type0; | |
73 gestures[1] = type1; | |
74 return gestures; | |
75 } | |
76 | |
77 GestureList Gestures(WebInputEvent::Type type0, | |
78 WebInputEvent::Type type1, | |
79 WebInputEvent::Type type2) { | |
80 GestureList gestures(3); | |
81 gestures[0] = type0; | |
82 gestures[1] = type1; | |
83 gestures[2] = type2; | |
84 return gestures; | |
85 } | |
86 | |
87 GestureList Gestures(WebInputEvent::Type type0, | |
88 WebInputEvent::Type type1, | |
89 WebInputEvent::Type type2, | |
90 WebInputEvent::Type type3) { | |
91 GestureList gestures(4); | |
92 gestures[0] = type0; | |
93 gestures[1] = type1; | |
94 gestures[2] = type2; | |
95 gestures[3] = type3; | |
96 return gestures; | |
97 } | |
98 | |
99 void SendTouchGestures() { | |
100 GestureEventPacket gesture_packet; | |
101 std::swap(gesture_packet, pending_gesture_packet_); | |
102 SendTouchGestures(touch_event_, gesture_packet); | |
103 touch_event_.ResetPoints(); | |
104 } | |
105 | |
106 void SendTouchGestures(const WebTouchEvent& touch, | |
107 const GestureEventPacket& packet) { | |
108 GestureEventPacket touch_packet = GestureEventPacket::FromTouch(touch); | |
109 for (size_t i = 0; i < packet.gesture_count(); ++i) | |
110 touch_packet.Push(packet.gesture(i)); | |
111 queue_->OnGestureEventPacket(touch_packet); | |
112 } | |
113 | |
114 void SendTimeoutGesture(WebInputEvent::Type type) { | |
115 queue_->OnGestureEventPacket( | |
116 GestureEventPacket::FromTouchTimeout(CreateGesture(type))); | |
117 } | |
118 | |
119 void SendTouchEventACK(InputEventAckState ack_result) { | |
120 queue_->OnTouchEventAck(ack_result); | |
121 } | |
122 | |
123 void PushGesture(WebInputEvent::Type type) { | |
124 pending_gesture_packet_.Push(CreateGesture(type)); | |
125 } | |
126 | |
127 void PressTouchPoint(int x, int y) { | |
128 touch_event_.PressPoint(x, y); | |
129 SendTouchGestures(); | |
130 } | |
131 | |
132 void MoveTouchPoint(int index, int x, int y) { | |
133 touch_event_.MovePoint(index, x, y); | |
134 SendTouchGestures(); | |
135 } | |
136 | |
137 void ReleaseTouchPoint(int index) { | |
138 touch_event_.ReleasePoint(index); | |
139 SendTouchGestures(); | |
140 } | |
141 | |
142 void CancelTouchPoint(int index) { | |
143 touch_event_.CancelPoint(index); | |
144 SendTouchGestures(); | |
145 } | |
146 | |
147 bool GesturesSent() const { | |
148 return !sent_gestures_.empty(); | |
149 } | |
150 | |
151 GestureList GetAndResetSentGestures() { | |
152 GestureList sent_gestures; | |
153 sent_gestures.swap(sent_gestures_); | |
154 return sent_gestures; | |
155 } | |
156 | |
157 static WebGestureEvent CreateGesture(WebInputEvent::Type type) { | |
158 return SyntheticWebGestureEventBuilder::Build( | |
159 type, WebGestureEvent::Touchscreen); | |
160 } | |
161 | |
162 private: | |
163 scoped_ptr<GestureEventQueue> queue_; | |
164 SyntheticWebTouchEvent touch_event_; | |
165 GestureEventPacket pending_gesture_packet_; | |
166 size_t sent_gesture_count_; | |
167 GestureList sent_gestures_; | |
168 }; | |
169 | |
170 TEST_F(GestureEventQueueTest, BasicNoGestures) { | |
171 PressTouchPoint(1, 1); | |
172 EXPECT_FALSE(GesturesSent()); | |
173 | |
174 MoveTouchPoint(0, 2, 2); | |
175 EXPECT_FALSE(GesturesSent()); | |
176 | |
177 // No gestures should be dispatched by the ack, as the queued packets | |
178 // contained no gestures. | |
179 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
180 EXPECT_FALSE(GesturesSent()); | |
181 | |
182 // Release the touch gesture. | |
183 ReleaseTouchPoint(0); | |
184 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
185 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
186 EXPECT_FALSE(GesturesSent()); | |
187 } | |
188 | |
189 TEST_F(GestureEventQueueTest, BasicGestures) { | |
190 // An unconsumed touch's gesture should be sent. | |
191 PushGesture(WebInputEvent::GestureScrollBegin); | |
192 PressTouchPoint(1, 1); | |
193 EXPECT_FALSE(GesturesSent()); | |
194 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
195 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureScrollBegin), | |
196 GetAndResetSentGestures())); | |
197 | |
198 // Multiple gestures can be queued for a single event. | |
199 PushGesture(WebInputEvent::GestureFlingStart); | |
200 PushGesture(WebInputEvent::GestureFlingCancel); | |
201 MoveTouchPoint(0, 1, 1); | |
202 EXPECT_FALSE(GesturesSent()); | |
203 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
204 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart, | |
205 WebInputEvent::GestureFlingCancel), | |
206 GetAndResetSentGestures())); | |
207 | |
208 // A consumed touch's gesture should not be sent. | |
209 PushGesture(WebInputEvent::GestureFlingStart); | |
210 PushGesture(WebInputEvent::GestureFlingCancel); | |
211 ReleaseTouchPoint(0); | |
212 EXPECT_FALSE(GesturesSent()); | |
213 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
214 EXPECT_FALSE(GesturesSent()); | |
215 } | |
216 | |
217 TEST_F(GestureEventQueueTest, ConsumedThenNotConsumed) { | |
218 // A consumed touch's gesture should not be sent. | |
219 PushGesture(WebInputEvent::GestureScrollBegin); | |
220 PressTouchPoint(1, 1); | |
221 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
222 EXPECT_FALSE(GesturesSent()); | |
223 | |
224 // Even if the subsequent touch is not consumed, continue dropping gestures. | |
225 PushGesture(WebInputEvent::GestureScrollUpdate); | |
226 MoveTouchPoint(0, 2, 2); | |
227 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
228 EXPECT_FALSE(GesturesSent()); | |
229 | |
230 // Even if the subsequent touch had no consumer, continue dropping gestures. | |
231 PushGesture(WebInputEvent::GestureFlingStart); | |
232 ReleaseTouchPoint(0); | |
233 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
234 EXPECT_FALSE(GesturesSent()); | |
235 } | |
236 | |
237 TEST_F(GestureEventQueueTest, NotConsumedThenNoConsumer) { | |
238 // An unconsumed touch's gesture should be sent. | |
239 PushGesture(WebInputEvent::GestureScrollBegin); | |
240 PressTouchPoint(1, 1); | |
241 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
242 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureScrollBegin), | |
243 GetAndResetSentGestures())); | |
244 | |
245 // If the subsequent touch has no consumer (e.g., a secondary pointer is | |
246 // pressed but not on a touch handling rect), send the gesture. | |
247 PushGesture(WebInputEvent::GesturePinchBegin); | |
248 PressTouchPoint(2, 2); | |
249 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | |
250 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GesturePinchBegin), | |
251 GetAndResetSentGestures())); | |
252 | |
253 // If the subsequent touch is consumed, then the remaining gesture sequence | |
254 // should be dropped, regardless of subsequent touch ack disposition. | |
255 PushGesture(WebInputEvent::GestureScrollUpdate); | |
256 PushGesture(WebInputEvent::GesturePinchUpdate); | |
257 MoveTouchPoint(0, 2, 2); | |
258 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
259 EXPECT_FALSE(GesturesSent()); | |
260 | |
261 PushGesture(WebInputEvent::GesturePinchEnd); | |
262 ReleaseTouchPoint(1); | |
263 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
264 EXPECT_FALSE(GesturesSent()); | |
265 | |
266 PushGesture(WebInputEvent::GestureScrollEnd); | |
267 ReleaseTouchPoint(0); | |
268 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | |
269 EXPECT_FALSE(GesturesSent()); | |
270 } | |
271 | |
272 TEST_F(GestureEventQueueTest, MultipleTouchSequences) { | |
273 // Queue two touch-to-gestures sequences. | |
274 PushGesture(WebInputEvent::GestureFlingStart); | |
275 PressTouchPoint(1, 1); | |
276 PushGesture(WebInputEvent::GestureFlingCancel); | |
277 ReleaseTouchPoint(0); | |
278 PushGesture(WebInputEvent::GestureFlingStart); | |
279 PressTouchPoint(1, 1); | |
280 PushGesture(WebInputEvent::GestureFlingCancel); | |
281 ReleaseTouchPoint(0); | |
282 | |
283 // The first gesture sequence should not be allowed. | |
284 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
285 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
286 EXPECT_FALSE(GesturesSent()); | |
287 | |
288 // The subsequent sequence should "reset" allowance. | |
289 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
290 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
291 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart, | |
292 WebInputEvent::GestureFlingCancel), | |
293 GetAndResetSentGestures())); | |
294 } | |
295 | |
296 TEST_F(GestureEventQueueTest, FlingCancelledOnNewTouchSequence) { | |
297 // Simulate a fling. | |
298 PressTouchPoint(1, 1); | |
299 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | |
300 PushGesture(WebInputEvent::GestureFlingStart); | |
301 ReleaseTouchPoint(0); | |
302 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
303 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart), | |
304 GetAndResetSentGestures())); | |
305 | |
306 // A new touch seqeuence should cancel the outstanding fling. | |
307 PressTouchPoint(1, 1); | |
308 ReleaseTouchPoint(0); | |
309 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | |
310 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingCancel), | |
311 GetAndResetSentGestures())); | |
312 } | |
313 | |
314 TEST_F(GestureEventQueueTest, FlingCancelledOnScrollBegin) { | |
315 // Simulate a fling sequence. | |
316 PushGesture(WebInputEvent::GestureScrollBegin); | |
317 PushGesture(WebInputEvent::GestureFlingStart); | |
318 PressTouchPoint(1, 1); | |
319 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
320 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureScrollBegin, | |
321 WebInputEvent::GestureFlingStart), | |
322 GetAndResetSentGestures())); | |
323 | |
324 // The new fling should cancel the preceding one. | |
325 PushGesture(WebInputEvent::GestureScrollBegin); | |
326 PushGesture(WebInputEvent::GestureFlingStart); | |
327 ReleaseTouchPoint(0); | |
328 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
329 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingCancel, | |
330 WebInputEvent::GestureScrollBegin, | |
331 WebInputEvent::GestureFlingStart), | |
332 GetAndResetSentGestures())); | |
333 } | |
334 | |
335 TEST_F(GestureEventQueueTest, FlingNotCancelledIfGFCEventReceived) { | |
336 // Simulate a fling that is started then cancelled. | |
337 PushGesture(WebInputEvent::GestureFlingStart); | |
338 PressTouchPoint(1, 1); | |
339 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | |
340 PushGesture(WebInputEvent::GestureFlingCancel); | |
341 ReleaseTouchPoint(0); | |
342 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
343 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart, | |
344 WebInputEvent::GestureFlingCancel), | |
345 GetAndResetSentGestures())); | |
346 | |
347 // A new touch sequence will not inject a GestureFlingCancel, as the fling | |
348 // has already been cancelled. | |
349 PressTouchPoint(1, 1); | |
350 ReleaseTouchPoint(0); | |
351 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | |
352 EXPECT_FALSE(GesturesSent()); | |
353 } | |
354 | |
355 TEST_F(GestureEventQueueTest, TapCancelledWhenScrollBegins) { | |
356 PushGesture(WebInputEvent::GestureTapDown); | |
357 PressTouchPoint(1, 1); | |
358 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
359 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapDown), | |
360 GetAndResetSentGestures())); | |
361 | |
362 // If the subsequent touch turns into a scroll, the tap should be cancelled. | |
363 PushGesture(WebInputEvent::GestureScrollBegin); | |
364 MoveTouchPoint(0, 2, 2); | |
365 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
366 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapCancel, | |
367 WebInputEvent::GestureScrollBegin), | |
368 GetAndResetSentGestures())); | |
369 } | |
370 | |
371 TEST_F(GestureEventQueueTest, TapCancelledWhenTouchConsumed) { | |
372 PushGesture(WebInputEvent::GestureTapDown); | |
373 PressTouchPoint(1, 1); | |
374 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
375 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapDown), | |
376 GetAndResetSentGestures())); | |
377 | |
378 // If the subsequent touch is consumed, the tap should be cancelled. | |
379 PushGesture(WebInputEvent::GestureScrollBegin); | |
380 MoveTouchPoint(0, 2, 2); | |
381 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
382 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapCancel), | |
383 GetAndResetSentGestures())); | |
384 } | |
385 | |
386 TEST_F(GestureEventQueueTest, TapNotCancelledIfTapEndingEventReceived) { | |
387 PushGesture(WebInputEvent::GestureTapDown); | |
388 PressTouchPoint(1, 1); | |
389 PressTouchPoint(2, 2); | |
390 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
391 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
392 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapDown), | |
393 GetAndResetSentGestures())); | |
394 | |
395 PushGesture(WebInputEvent::GestureTap); | |
396 ReleaseTouchPoint(1); | |
397 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
398 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTap), | |
399 GetAndResetSentGestures())); | |
400 | |
401 // The tap should not be cancelled as it was terminated by a |GestureTap|. | |
402 ReleaseTouchPoint(0); | |
403 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
404 EXPECT_FALSE(GesturesSent()); | |
405 } | |
406 | |
407 TEST_F(GestureEventQueueTest, TimeoutGestures) { | |
408 // If the sequence is allowed, and there are no preceding gestures, the | |
409 // timeout gestures should be forwarded immediately. | |
410 PressTouchPoint(1, 1); | |
411 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
412 EXPECT_FALSE(GesturesSent()); | |
413 | |
414 SendTimeoutGesture(WebInputEvent::GestureShowPress); | |
415 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureShowPress), | |
416 GetAndResetSentGestures())); | |
417 | |
418 SendTimeoutGesture(WebInputEvent::GestureLongPress); | |
419 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureLongPress), | |
420 GetAndResetSentGestures())); | |
421 | |
422 ReleaseTouchPoint(0); | |
423 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
424 | |
425 // If the sequence is disallowed, and there are no preceding gestures, the | |
426 // timeout gestures should be dropped immediately. | |
427 PressTouchPoint(1, 1); | |
428 SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); | |
429 EXPECT_FALSE(GesturesSent()); | |
430 | |
431 SendTimeoutGesture(WebInputEvent::GestureShowPress); | |
432 EXPECT_FALSE(GesturesSent()); | |
433 ReleaseTouchPoint(0); | |
434 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
435 | |
436 // If the sequence has a pending ack, the timeout gestures should | |
437 // remain queued until the ack is received. | |
438 PressTouchPoint(1, 1); | |
439 EXPECT_FALSE(GesturesSent()); | |
440 | |
441 SendTimeoutGesture(WebInputEvent::GestureLongPress); | |
442 EXPECT_FALSE(GesturesSent()); | |
443 | |
444 SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
445 EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureLongPress), | |
446 GetAndResetSentGestures())); | |
447 } | |
tdresser
2014/01/24 19:30:15
I'd like to see a test for the scroll after longpr
jdduke (slow)
2014/01/24 23:00:56
Sure. I added a specific test for this case in Co
| |
448 | |
449 } // namespace content | |
OLD | NEW |