blob: 8fdfd54cce29809b2c8b1d557c2134dab84139ea [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "content/browser/renderer_host/input/touch_emulator.h"
#include "content/browser/renderer_host/input/touch_emulator_client.h"
#include "content/common/input/web_input_event_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/gesture_detection/gesture_config_helper.h"
#if defined(USE_AURA)
#include "ui/aura/env.h"
#include "ui/aura/test/test_screen.h"
#endif
using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebKeyboardEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
namespace content {
class TouchEmulatorTest : public testing::Test,
public TouchEmulatorClient {
public:
TouchEmulatorTest()
: shift_pressed_(false),
mouse_pressed_(false),
last_mouse_x_(-1),
last_mouse_y_(-1) {
last_event_time_seconds_ =
(base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
event_time_delta_seconds_ = 0.1;
}
virtual ~TouchEmulatorTest() {}
// testing::Test
virtual void SetUp() OVERRIDE {
#if defined(USE_AURA)
aura::Env::CreateInstance(true);
screen_.reset(aura::TestScreen::Create(gfx::Size()));
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
#endif
emulator_.reset(new TouchEmulator(this));
emulator_->Enable(true /* allow_pinch */);
}
virtual void TearDown() OVERRIDE {
emulator_->Disable();
EXPECT_EQ("", ExpectedEvents());
#if defined(USE_AURA)
aura::Env::DeleteInstance();
screen_.reset();
#endif
}
virtual void ForwardGestureEvent(
const blink::WebGestureEvent& event) OVERRIDE {
forwarded_events_.push_back(event.type);
}
virtual void ForwardTouchEvent(
const blink::WebTouchEvent& event) OVERRIDE {
forwarded_events_.push_back(event.type);
EXPECT_EQ(1U, event.touchesLength);
EXPECT_EQ(last_mouse_x_, event.touches[0].position.x);
EXPECT_EQ(last_mouse_y_, event.touches[0].position.y);
int expectedCancelable = event.type != WebInputEvent::TouchCancel;
EXPECT_EQ(expectedCancelable, event.cancelable);
emulator()->HandleTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
}
virtual void SetCursor(const WebCursor& cursor) OVERRIDE {}
protected:
TouchEmulator* emulator() const {
return emulator_.get();
}
int modifiers() const {
return shift_pressed_ ? WebInputEvent::ShiftKey : 0;
}
std::string ExpectedEvents() {
std::string result;
for (size_t i = 0; i < forwarded_events_.size(); ++i) {
if (i != 0)
result += " ";
result += WebInputEventTraits::GetName(forwarded_events_[i]);
}
forwarded_events_.clear();
return result;
}
double GetNextEventTimeSeconds() {
last_event_time_seconds_ += event_time_delta_seconds_;
return last_event_time_seconds_;
}
void set_event_time_delta_seconds_(double delta) {
event_time_delta_seconds_ = delta;
}
void SendKeyboardEvent(WebInputEvent::Type type) {
WebKeyboardEvent event;
event.timeStampSeconds = GetNextEventTimeSeconds();
event.type = type;
event.modifiers = modifiers();
emulator()->HandleKeyboardEvent(event);
}
void PressShift() {
DCHECK(!shift_pressed_);
shift_pressed_ = true;
SendKeyboardEvent(WebInputEvent::KeyDown);
}
void ReleaseShift() {
DCHECK(shift_pressed_);
shift_pressed_ = false;
SendKeyboardEvent(WebInputEvent::KeyUp);
}
void SendMouseEvent(WebInputEvent::Type type, int x, int y) {
WebMouseEvent event;
event.timeStampSeconds = GetNextEventTimeSeconds();
event.type = type;
event.button = mouse_pressed_ ? WebMouseEvent::ButtonLeft :
WebMouseEvent::ButtonNone;
event.modifiers = modifiers();
last_mouse_x_ = x;
last_mouse_y_ = y;
event.x = event.windowX = event.globalX = x;
event.y = event.windowY = event.globalY = y;
emulator()->HandleMouseEvent(event);
}
bool SendMouseWheelEvent() {
WebMouseWheelEvent event;
event.type = WebInputEvent::MouseWheel;
event.timeStampSeconds = GetNextEventTimeSeconds();
// Return whether mouse wheel is forwarded.
return !emulator()->HandleMouseWheelEvent(event);
}
void MouseDown(int x, int y) {
DCHECK(!mouse_pressed_);
if (x != last_mouse_x_ || y != last_mouse_y_)
SendMouseEvent(WebInputEvent::MouseMove, x, y);
mouse_pressed_ = true;
SendMouseEvent(WebInputEvent::MouseDown, x, y);
}
void MouseDrag(int x, int y) {
DCHECK(mouse_pressed_);
SendMouseEvent(WebInputEvent::MouseMove, x, y);
}
void MouseMove(int x, int y) {
DCHECK(!mouse_pressed_);
SendMouseEvent(WebInputEvent::MouseMove, x, y);
}
void MouseUp(int x, int y) {
DCHECK(mouse_pressed_);
if (x != last_mouse_x_ || y != last_mouse_y_)
SendMouseEvent(WebInputEvent::MouseMove, x, y);
SendMouseEvent(WebInputEvent::MouseUp, x, y);
mouse_pressed_ = false;
}
private:
scoped_ptr<TouchEmulator> emulator_;
std::vector<WebInputEvent::Type> forwarded_events_;
#if defined(USE_AURA)
scoped_ptr<gfx::Screen> screen_;
#endif
double last_event_time_seconds_;
double event_time_delta_seconds_;
bool shift_pressed_;
bool mouse_pressed_;
int last_mouse_x_;
int last_mouse_y_;
base::MessageLoopForUI message_loop_;
};
TEST_F(TouchEmulatorTest, NoTouches) {
MouseMove(100, 200);
MouseMove(300, 300);
EXPECT_EQ("", ExpectedEvents());
}
TEST_F(TouchEmulatorTest, Touch) {
MouseMove(100, 200);
EXPECT_EQ("", ExpectedEvents());
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseUp(200, 200);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
" TouchEnd GestureScrollEnd",
ExpectedEvents());
}
TEST_F(TouchEmulatorTest, MultipleTouches) {
MouseMove(100, 200);
EXPECT_EQ("", ExpectedEvents());
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseUp(200, 200);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
" TouchEnd GestureScrollEnd",
ExpectedEvents());
MouseMove(300, 200);
MouseMove(200, 200);
EXPECT_EQ("", ExpectedEvents());
MouseDown(300, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseDrag(300, 300);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
ExpectedEvents());
MouseDrag(300, 400);
EXPECT_EQ("TouchMove GestureScrollUpdate", ExpectedEvents());
MouseUp(300, 500);
EXPECT_EQ(
"TouchMove GestureScrollUpdate TouchEnd GestureScrollEnd",
ExpectedEvents());
}
TEST_F(TouchEmulatorTest, Pinch) {
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseDrag(200, 200);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
ExpectedEvents());
PressShift();
EXPECT_EQ("", ExpectedEvents());
MouseDrag(300, 200);
EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
ReleaseShift();
EXPECT_EQ("", ExpectedEvents());
MouseDrag(400, 200);
EXPECT_EQ(
"TouchMove GesturePinchEnd GestureScrollUpdate",
ExpectedEvents());
MouseUp(400, 200);
EXPECT_EQ("TouchEnd GestureScrollEnd", ExpectedEvents());
}
TEST_F(TouchEmulatorTest, DisableAndReenable) {
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseDrag(200, 200);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
ExpectedEvents());
PressShift();
MouseDrag(300, 200);
EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
// Disable while pinch is in progress.
emulator()->Disable();
EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
MouseUp(300, 200);
ReleaseShift();
MouseMove(300, 300);
EXPECT_EQ("", ExpectedEvents());
emulator()->Enable(true /* allow_pinch */);
MouseDown(300, 300);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseDrag(300, 400);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
ExpectedEvents());
// Disable while scroll is in progress.
emulator()->Disable();
EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
}
TEST_F(TouchEmulatorTest, MouseMovesDropped) {
MouseMove(100, 200);
EXPECT_EQ("", ExpectedEvents());
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
// Mouse move after mouse down is never dropped.
set_event_time_delta_seconds_(0.001);
MouseDrag(200, 200);
EXPECT_EQ(
"TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
ExpectedEvents());
// The following mouse moves are dropped.
MouseDrag(300, 200);
EXPECT_EQ("", ExpectedEvents());
MouseDrag(350, 200);
EXPECT_EQ("", ExpectedEvents());
// Dispatching again.
set_event_time_delta_seconds_(0.1);
MouseDrag(400, 200);
EXPECT_EQ(
"TouchMove GestureScrollUpdate",
ExpectedEvents());
MouseUp(400, 200);
EXPECT_EQ(
"TouchEnd GestureScrollEnd",
ExpectedEvents());
}
TEST_F(TouchEmulatorTest, MouseWheel) {
MouseMove(100, 200);
EXPECT_EQ("", ExpectedEvents());
EXPECT_TRUE(SendMouseWheelEvent());
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
EXPECT_FALSE(SendMouseWheelEvent());
MouseUp(100, 200);
EXPECT_EQ("TouchEnd GestureShowPress GestureTap", ExpectedEvents());
EXPECT_TRUE(SendMouseWheelEvent());
MouseDown(300, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
EXPECT_FALSE(SendMouseWheelEvent());
emulator()->Disable();
EXPECT_EQ("TouchCancel GestureTapCancel", ExpectedEvents());
EXPECT_TRUE(SendMouseWheelEvent());
emulator()->Enable(true /* allow_pinch */);
EXPECT_TRUE(SendMouseWheelEvent());
}
} // namespace content