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.
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/time/time.h"
11 #include "content/browser/renderer_host/input/touch_emulator.h"
12 #include "content/browser/renderer_host/input/touch_emulator_client.h"
13 #include "content/common/input/web_input_event_traits.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using blink::WebGestureEvent
;
17 using blink::WebInputEvent
;
18 using blink::WebKeyboardEvent
;
19 using blink::WebMouseEvent
;
20 using blink::WebMouseWheelEvent
;
21 using blink::WebTouchEvent
;
22 using blink::WebTouchPoint
;
26 class TouchEmulatorTest
: public testing::Test
,
27 public TouchEmulatorClient
{
30 : shift_pressed_(false),
31 mouse_pressed_(false),
32 ack_touches_synchronously_(true),
35 last_event_time_seconds_
=
36 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
37 event_time_delta_seconds_
= 0.1;
40 ~TouchEmulatorTest() override
{}
43 void SetUp() override
{
44 emulator_
.reset(new TouchEmulator(this, 1.0f
));
45 emulator_
->SetDoubleTapSupportForPageEnabled(false);
46 emulator_
->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
49 void TearDown() override
{
51 EXPECT_EQ("", ExpectedEvents());
54 void ForwardGestureEvent(const blink::WebGestureEvent
& event
) override
{
55 forwarded_events_
.push_back(event
.type
);
58 void ForwardEmulatedTouchEvent(const blink::WebTouchEvent
& event
) override
{
59 forwarded_events_
.push_back(event
.type
);
60 EXPECT_EQ(1U, event
.touchesLength
);
61 EXPECT_EQ(last_mouse_x_
, event
.touches
[0].position
.x
);
62 EXPECT_EQ(last_mouse_y_
, event
.touches
[0].position
.y
);
63 bool expected_cancelable
= event
.type
!= WebInputEvent::TouchCancel
;
64 EXPECT_EQ(expected_cancelable
, !!event
.cancelable
);
65 if (ack_touches_synchronously_
) {
66 emulator()->HandleTouchEventAck(
67 event
, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
);
71 void SetCursor(const WebCursor
& cursor
) override
{}
73 void ShowContextMenuAtPoint(const gfx::Point
& point
) override
{}
76 TouchEmulator
* emulator() const {
77 return emulator_
.get();
80 int modifiers() const {
81 return shift_pressed_
? WebInputEvent::ShiftKey
: 0;
84 std::string
ExpectedEvents() {
86 for (size_t i
= 0; i
< forwarded_events_
.size(); ++i
) {
89 result
+= WebInputEventTraits::GetName(forwarded_events_
[i
]);
91 forwarded_events_
.clear();
95 double GetNextEventTimeSeconds() {
96 last_event_time_seconds_
+= event_time_delta_seconds_
;
97 return last_event_time_seconds_
;
100 void set_event_time_delta_seconds_(double delta
) {
101 event_time_delta_seconds_
= delta
;
104 void SendKeyboardEvent(WebInputEvent::Type type
) {
105 WebKeyboardEvent event
;
106 event
.timeStampSeconds
= GetNextEventTimeSeconds();
108 event
.modifiers
= modifiers();
109 emulator()->HandleKeyboardEvent(event
);
113 DCHECK(!shift_pressed_
);
114 shift_pressed_
= true;
115 SendKeyboardEvent(WebInputEvent::KeyDown
);
118 void ReleaseShift() {
119 DCHECK(shift_pressed_
);
120 shift_pressed_
= false;
121 SendKeyboardEvent(WebInputEvent::KeyUp
);
124 void SendMouseEvent(WebInputEvent::Type type
, int x
, int y
) {
126 event
.timeStampSeconds
= GetNextEventTimeSeconds();
128 event
.button
= mouse_pressed_
? WebMouseEvent::ButtonLeft
:
129 WebMouseEvent::ButtonNone
;
130 event
.modifiers
= modifiers();
133 event
.x
= event
.windowX
= event
.globalX
= x
;
134 event
.y
= event
.windowY
= event
.globalY
= y
;
135 emulator()->HandleMouseEvent(event
);
138 bool SendMouseWheelEvent() {
139 WebMouseWheelEvent event
;
140 event
.type
= WebInputEvent::MouseWheel
;
141 event
.timeStampSeconds
= GetNextEventTimeSeconds();
142 // Return whether mouse wheel is forwarded.
143 return !emulator()->HandleMouseWheelEvent(event
);
146 void MouseDown(int x
, int y
) {
147 DCHECK(!mouse_pressed_
);
148 if (x
!= last_mouse_x_
|| y
!= last_mouse_y_
)
149 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
150 mouse_pressed_
= true;
151 SendMouseEvent(WebInputEvent::MouseDown
, x
, y
);
154 void MouseDrag(int x
, int y
) {
155 DCHECK(mouse_pressed_
);
156 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
159 void MouseMove(int x
, int y
) {
160 DCHECK(!mouse_pressed_
);
161 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
164 void MouseUp(int x
, int y
) {
165 DCHECK(mouse_pressed_
);
166 if (x
!= last_mouse_x_
|| y
!= last_mouse_y_
)
167 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
168 SendMouseEvent(WebInputEvent::MouseUp
, x
, y
);
169 mouse_pressed_
= false;
172 bool TouchStart(int x
, int y
, bool ack
) {
173 return SendTouchEvent(
174 WebInputEvent::TouchStart
, WebTouchPoint::StatePressed
, x
, y
, ack
);
177 bool TouchMove(int x
, int y
, bool ack
) {
178 return SendTouchEvent(
179 WebInputEvent::TouchMove
, WebTouchPoint::StateMoved
, x
, y
, ack
);
182 bool TouchEnd(int x
, int y
, bool ack
) {
183 return SendTouchEvent(
184 WebInputEvent::TouchEnd
, WebTouchPoint::StateReleased
, x
, y
, ack
);
187 WebTouchEvent
MakeTouchEvent(WebInputEvent::Type type
,
188 WebTouchPoint::State state
, int x
, int y
) {
191 event
.timeStampSeconds
= GetNextEventTimeSeconds();
192 event
.touchesLength
= 1;
193 event
.touches
[0].id
= 0;
194 event
.touches
[0].state
= state
;
195 event
.touches
[0].position
.x
= x
;
196 event
.touches
[0].position
.y
= y
;
197 event
.touches
[0].screenPosition
.x
= x
;
198 event
.touches
[0].screenPosition
.y
= y
;
202 bool SendTouchEvent(WebInputEvent::Type type
, WebTouchPoint::State state
,
203 int x
, int y
, bool ack
) {
204 WebTouchEvent event
= MakeTouchEvent(type
, state
, x
, y
);
205 if (emulator()->HandleTouchEvent(event
)) {
206 // Touch event is not forwarded.
211 // Can't send ack if there are some pending acks.
212 DCHECK(!touch_events_to_ack_
.size());
214 // Touch event is forwarded, ack should not be handled by emulator.
215 EXPECT_FALSE(emulator()->HandleTouchEventAck(
216 event
, INPUT_EVENT_ACK_STATE_CONSUMED
));
218 touch_events_to_ack_
.push_back(event
);
223 void AckOldestTouchEvent() {
224 DCHECK(touch_events_to_ack_
.size());
225 WebTouchEvent event
= touch_events_to_ack_
[0];
226 touch_events_to_ack_
.erase(touch_events_to_ack_
.begin());
227 // Emulator should not handle ack from native stream.
228 EXPECT_FALSE(emulator()->HandleTouchEventAck(
229 event
, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
));
232 void DisableSynchronousTouchAck() { ack_touches_synchronously_
= false; }
235 scoped_ptr
<TouchEmulator
> emulator_
;
236 std::vector
<WebInputEvent::Type
> forwarded_events_
;
237 double last_event_time_seconds_
;
238 double event_time_delta_seconds_
;
241 bool ack_touches_synchronously_
;
244 std::vector
<WebTouchEvent
> touch_events_to_ack_
;
245 base::MessageLoopForUI message_loop_
;
249 TEST_F(TouchEmulatorTest
, NoTouches
) {
252 EXPECT_EQ("", ExpectedEvents());
255 TEST_F(TouchEmulatorTest
, Touch
) {
257 EXPECT_EQ("", ExpectedEvents());
259 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
262 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
263 " TouchEnd GestureScrollEnd",
267 TEST_F(TouchEmulatorTest
, DoubleTapSupport
) {
268 emulator()->SetDoubleTapSupportForPageEnabled(true);
270 EXPECT_EQ("", ExpectedEvents());
272 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
274 EXPECT_EQ("TouchEnd GestureTapUnconfirmed", ExpectedEvents());
276 EXPECT_EQ("TouchStart GestureTapCancel GestureTapDown", ExpectedEvents());
278 EXPECT_EQ("TouchEnd GestureTapCancel GestureDoubleTap", ExpectedEvents());
281 TEST_F(TouchEmulatorTest
, MultipleTouches
) {
283 EXPECT_EQ("", ExpectedEvents());
285 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
288 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
289 " TouchEnd GestureScrollEnd",
293 EXPECT_EQ("", ExpectedEvents());
295 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
298 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
301 EXPECT_EQ("TouchMove GestureScrollUpdate", ExpectedEvents());
304 "TouchMove GestureScrollUpdate TouchEnd GestureScrollEnd",
308 TEST_F(TouchEmulatorTest
, Pinch
) {
310 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
313 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
316 EXPECT_EQ("", ExpectedEvents());
318 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
320 EXPECT_EQ("", ExpectedEvents());
323 "TouchMove GesturePinchEnd GestureScrollUpdate",
326 EXPECT_EQ("TouchEnd GestureScrollEnd", ExpectedEvents());
329 TEST_F(TouchEmulatorTest
, CancelWithDelayedAck
) {
330 DisableSynchronousTouchAck();
332 // Simulate a sequence that is interrupted by |CancelTouch()|.
334 EXPECT_EQ("TouchStart", ExpectedEvents());
336 EXPECT_EQ("TouchMove", ExpectedEvents());
337 emulator()->CancelTouch();
338 EXPECT_EQ("TouchCancel", ExpectedEvents());
339 // The mouse up should have no effect as the sequence was already cancelled.
341 EXPECT_EQ("", ExpectedEvents());
343 // Simulate a sequence that fully completes before |CancelTouch()|.
345 EXPECT_EQ("TouchStart", ExpectedEvents());
347 EXPECT_EQ("TouchEnd", ExpectedEvents());
348 // |CancelTouch| should have no effect as the sequence was already terminated.
349 emulator()->CancelTouch();
350 EXPECT_EQ("", ExpectedEvents());
353 TEST_F(TouchEmulatorTest
, DisableAndReenable
) {
355 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
358 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
362 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
364 // Disable while pinch is in progress.
365 emulator()->Disable();
366 EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
370 EXPECT_EQ("", ExpectedEvents());
372 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
374 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
377 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
380 // Disable while scroll is in progress.
381 emulator()->Disable();
382 EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
385 TEST_F(TouchEmulatorTest
, DisableAndReenableDifferentConfig
) {
387 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
390 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
394 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
396 // Disable while pinch is in progress.
397 emulator()->Disable();
398 EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
402 EXPECT_EQ("", ExpectedEvents());
404 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_DESKTOP
);
406 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
409 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
412 // Disable while scroll is in progress.
413 emulator()->Disable();
414 EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
417 TEST_F(TouchEmulatorTest
, MouseMovesDropped
) {
419 EXPECT_EQ("", ExpectedEvents());
421 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
423 // Mouse move after mouse down is never dropped.
424 set_event_time_delta_seconds_(0.001);
427 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
430 // The following mouse moves are dropped.
432 EXPECT_EQ("", ExpectedEvents());
434 EXPECT_EQ("", ExpectedEvents());
436 // Dispatching again.
437 set_event_time_delta_seconds_(0.1);
440 "TouchMove GestureScrollUpdate",
444 "TouchEnd GestureScrollEnd",
448 TEST_F(TouchEmulatorTest
, MouseWheel
) {
450 EXPECT_EQ("", ExpectedEvents());
451 EXPECT_TRUE(SendMouseWheelEvent());
453 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
454 EXPECT_FALSE(SendMouseWheelEvent());
456 EXPECT_EQ("TouchEnd GestureShowPress GestureTap", ExpectedEvents());
457 EXPECT_TRUE(SendMouseWheelEvent());
459 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
460 EXPECT_FALSE(SendMouseWheelEvent());
461 emulator()->Disable();
462 EXPECT_EQ("TouchCancel GestureTapCancel", ExpectedEvents());
463 EXPECT_TRUE(SendMouseWheelEvent());
464 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
465 EXPECT_TRUE(SendMouseWheelEvent());
468 TEST_F(TouchEmulatorTest
, MultipleTouchStreams
) {
469 // Native stream should be blocked while emulated is active.
471 EXPECT_EQ("", ExpectedEvents());
473 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
474 EXPECT_FALSE(TouchStart(10, 10, true));
475 EXPECT_FALSE(TouchMove(20, 20, true));
478 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
479 " TouchEnd GestureScrollEnd",
481 EXPECT_FALSE(TouchEnd(20, 20, true));
483 // Emulated stream should be blocked while native is active.
484 EXPECT_TRUE(TouchStart(10, 10, true));
485 EXPECT_TRUE(TouchMove(20, 20, true));
487 EXPECT_EQ("", ExpectedEvents());
488 // Re-enabling in the middle of a touch sequence should not affect this.
489 emulator()->Disable();
490 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
492 EXPECT_EQ("", ExpectedEvents());
494 EXPECT_EQ("", ExpectedEvents());
495 EXPECT_TRUE(TouchEnd(20, 20, true));
496 EXPECT_EQ("", ExpectedEvents());
498 // Late ack for TouchEnd should not mess things up.
499 EXPECT_TRUE(TouchStart(10, 10, false));
500 EXPECT_TRUE(TouchMove(20, 20, false));
501 emulator()->Disable();
502 EXPECT_TRUE(TouchEnd(20, 20, false));
503 EXPECT_TRUE(TouchStart(30, 30, false));
504 AckOldestTouchEvent(); // TouchStart.
505 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
506 AckOldestTouchEvent(); // TouchMove.
507 AckOldestTouchEvent(); // TouchEnd.
509 EXPECT_EQ("", ExpectedEvents());
511 EXPECT_EQ("", ExpectedEvents());
513 EXPECT_EQ("", ExpectedEvents());
514 AckOldestTouchEvent(); // TouchStart.
516 EXPECT_EQ("", ExpectedEvents());
517 EXPECT_TRUE(TouchMove(30, 40, true));
518 EXPECT_TRUE(TouchEnd(30, 40, true));
520 EXPECT_EQ("", ExpectedEvents());
522 // Emulation should be back to normal.
524 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
527 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
528 " TouchEnd GestureScrollEnd",
532 TEST_F(TouchEmulatorTest
, MultipleTouchStreamsLateEnable
) {
533 // Enabling in the middle of native touch sequence should be handled.
534 // Send artificial late TouchEnd ack, like it is the first thing emulator
536 WebTouchEvent event
= MakeTouchEvent(
537 WebInputEvent::TouchEnd
, WebTouchPoint::StateReleased
, 10, 10);
538 EXPECT_FALSE(emulator()->HandleTouchEventAck(
539 event
, INPUT_EVENT_ACK_STATE_CONSUMED
));
542 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
545 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
546 " TouchEnd GestureScrollEnd",
550 TEST_F(TouchEmulatorTest
, CancelAfterDisableDoesNotCrash
) {
551 DisableSynchronousTouchAck();
553 emulator()->Disable();
554 EXPECT_EQ("TouchStart TouchCancel", ExpectedEvents());
555 emulator()->CancelTouch();
558 TEST_F(TouchEmulatorTest
, ConstructorWithHighDeviceScaleDoesNotCrash
) {
559 TouchEmulator(this, 4.0f
);
562 } // namespace content