blob: 69f52025f44e519df0f388ef2f5051fe921be991 [file] [log] [blame]
// Copyright 2013 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 "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "content/browser/renderer_host/input/synthetic_gesture_controller_new.h"
#include "content/browser/renderer_host/input/synthetic_gesture_new.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/test_render_view_host.h"
#include "content/common/input/input_event.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
namespace content {
namespace {
const int kSyntheticGestureUpdateRate = 1;
class MockSyntheticGesture : public SyntheticGestureNew {
public:
MockSyntheticGesture(bool *finished, int num_steps)
: finished_(finished),
num_steps_(num_steps),
step_count_(0) {
*finished_ = false;
}
virtual ~MockSyntheticGesture() {}
virtual Result ForwardInputEvents(const base::TimeDelta& interval,
SyntheticGestureTarget* target) OVERRIDE {
step_count_++;
if (step_count_ == num_steps_) {
*finished_ = true;
return SyntheticGestureNew::GESTURE_FINISHED;
}
else if (step_count_ > num_steps_) {
*finished_ = true;
// Return arbitrary failure.
return SyntheticGestureNew::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
}
else
return SyntheticGestureNew::GESTURE_RUNNING;
}
protected:
bool* finished_;
int num_steps_;
int step_count_;
};
class MockSyntheticGestureTarget : public SyntheticGestureTarget {
public:
MockSyntheticGestureTarget() : num_success_(0), num_failure_(0) {}
virtual ~MockSyntheticGestureTarget() {}
virtual void QueueInputEventToPlatform(const InputEvent& event) OVERRIDE {}
virtual void OnSyntheticGestureCompleted(
SyntheticGestureNew::Result result) OVERRIDE {
DCHECK_NE(result, SyntheticGestureNew::GESTURE_RUNNING);
if (result == SyntheticGestureNew::GESTURE_FINISHED)
num_success_++;
else
num_failure_++;
}
virtual base::TimeDelta GetSyntheticGestureUpdateRate() const OVERRIDE {
return base::TimeDelta::FromMilliseconds(kSyntheticGestureUpdateRate);
}
virtual SyntheticGestureParams::GestureSourceType
GetDefaultSyntheticGestureSourceType() const OVERRIDE {
return SyntheticGestureParams::TOUCH_INPUT;
}
virtual bool SupportsSyntheticGestureSourceType(
SyntheticGestureParams::GestureSourceType gesture_source_type)
const OVERRIDE {
return true;
}
int num_success() const { return num_success_; }
int num_failure() const { return num_failure_; }
private:
int num_success_;
int num_failure_;
};
class MockSyntheticSmoothScrollMouseTarget : public MockSyntheticGestureTarget {
public:
MockSyntheticSmoothScrollMouseTarget() : scroll_distance_(0) {}
virtual ~MockSyntheticSmoothScrollMouseTarget() {}
virtual void QueueInputEventToPlatform(const InputEvent& event) OVERRIDE {
const WebKit::WebInputEvent* web_event = event.web_event.get();
DCHECK_EQ(web_event->type, WebKit::WebInputEvent::MouseWheel);
const WebKit::WebMouseWheelEvent* mouse_wheel_event =
static_cast<const WebKit::WebMouseWheelEvent*>(web_event);
DCHECK_EQ(mouse_wheel_event->deltaX, 0);
scroll_distance_ += mouse_wheel_event->deltaY;
}
float scroll_distance() const { return scroll_distance_; }
private:
float scroll_distance_;
};
class MockSyntheticSmoothScrollTouchTarget : public MockSyntheticGestureTarget {
public:
MockSyntheticSmoothScrollTouchTarget()
: scroll_distance_(0), anchor_y_(0), started_(false) {}
virtual ~MockSyntheticSmoothScrollTouchTarget() {}
virtual void QueueInputEventToPlatform(const InputEvent& event) OVERRIDE {
const WebKit::WebInputEvent* web_event = event.web_event.get();
DCHECK(WebKit::WebInputEvent::isTouchEventType(web_event->type));
const WebKit::WebTouchEvent* touch_event =
static_cast<const WebKit::WebTouchEvent*>(web_event);
DCHECK_EQ(touch_event->touchesLength, (unsigned int)1);
if (!started_) {
DCHECK_EQ(touch_event->type, WebKit::WebInputEvent::TouchStart);
anchor_y_ = touch_event->touches[0].position.y;
started_ = true;
}
else {
DCHECK_NE(touch_event->type, WebKit::WebInputEvent::TouchStart);
DCHECK_NE(touch_event->type, WebKit::WebInputEvent::TouchCancel);
// Ignore move events.
if (touch_event->type == WebKit::WebInputEvent::TouchEnd)
scroll_distance_ = touch_event->touches[0].position.y - anchor_y_;
}
}
float scroll_distance() const { return scroll_distance_; }
private:
float scroll_distance_;
float anchor_y_;
bool started_;
};
class SyntheticGestureControllerNewTest : public testing::Test {
public:
SyntheticGestureControllerNewTest() {}
virtual ~SyntheticGestureControllerNewTest() {}
protected:
virtual void SetUp() OVERRIDE {
target_.reset(new MockSyntheticGestureTarget());
target_ptr_ = target_.get();
controller_.reset(new SyntheticGestureControllerNew(
target_.PassAs<SyntheticGestureTarget>()));
}
virtual void TearDown() OVERRIDE {
controller_.reset();
target_.reset();
// Process all pending tasks to avoid leaks.
base::MessageLoop::current()->RunUntilIdle();
}
void PostQuitMessageAndRun(int num_steps) {
// Allow the message loop to process pending synthetic scrolls, then quit.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE, base::MessageLoop::QuitClosure(),
base::TimeDelta::FromMilliseconds(
kSyntheticGestureUpdateRate * num_steps));
base::MessageLoop::current()->Run();
}
base::MessageLoopForUI message_loop_;
scoped_ptr<SyntheticGestureControllerNew> controller_;
scoped_ptr<MockSyntheticGestureTarget> target_;
const MockSyntheticGestureTarget* target_ptr_;
};
TEST_F(SyntheticGestureControllerNewTest, SingleGesture) {
bool finished;
scoped_ptr<MockSyntheticGesture> gesture(
new MockSyntheticGesture(&finished, 3));
controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(30);
EXPECT_TRUE(finished);
EXPECT_EQ(1, target_ptr_->num_success());
EXPECT_EQ(0, target_ptr_->num_failure());
}
TEST_F(SyntheticGestureControllerNewTest, GestureFailed) {
bool finished;
scoped_ptr<MockSyntheticGesture> gesture(
new MockSyntheticGesture(&finished, 0));
controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(10);
EXPECT_TRUE(finished);
EXPECT_EQ(1, target_ptr_->num_failure());
EXPECT_EQ(0, target_ptr_->num_success());
}
TEST_F(SyntheticGestureControllerNewTest, SuccessiveGestures) {
bool finished_1, finished_2;
scoped_ptr<MockSyntheticGesture> gesture_1(
new MockSyntheticGesture(&finished_1, 2));
scoped_ptr<MockSyntheticGesture> gesture_2(
new MockSyntheticGesture(&finished_2, 4));
// Queue first gesture and wait for it to finish
controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(30);
EXPECT_TRUE(finished_1);
EXPECT_EQ(1, target_ptr_->num_success());
EXPECT_EQ(0, target_ptr_->num_failure());
// Queue second gesture.
controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(30);
EXPECT_TRUE(finished_2);
EXPECT_EQ(2, target_ptr_->num_success());
EXPECT_EQ(0, target_ptr_->num_failure());
}
// TODO(dominikg): Started flaking around r231819 http://crbug.com/314272
TEST_F(SyntheticGestureControllerNewTest, DISABLED_TwoGesturesInFlight) {
bool finished_1, finished_2;
scoped_ptr<MockSyntheticGesture> gesture_1(
new MockSyntheticGesture(&finished_1, 2));
scoped_ptr<MockSyntheticGesture> gesture_2(
new MockSyntheticGesture(&finished_2, 4));
controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGestureNew>());
controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(30);
EXPECT_TRUE(finished_1);
EXPECT_TRUE(finished_2);
EXPECT_EQ(2, target_ptr_->num_success());
EXPECT_EQ(0, target_ptr_->num_failure());
}
TEST_F(SyntheticGestureControllerNewTest, SmoothScrollGestureTouch) {
scoped_ptr<MockSyntheticSmoothScrollTouchTarget> smooth_scroll_touch_target(
new MockSyntheticSmoothScrollTouchTarget);
const MockSyntheticSmoothScrollTouchTarget* smooth_scroll_touch_target_ptr =
smooth_scroll_touch_target.get();
controller_.reset(new SyntheticGestureControllerNew(
smooth_scroll_touch_target.PassAs<SyntheticGestureTarget>()));
SyntheticSmoothScrollGestureParams params;
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
params.distance = 6;
scoped_ptr<SyntheticSmoothScrollGestureNew> gesture(
new SyntheticSmoothScrollGestureNew(params));
controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(30);
EXPECT_EQ(1, smooth_scroll_touch_target_ptr->num_success());
EXPECT_EQ(0, smooth_scroll_touch_target_ptr->num_failure());
EXPECT_LE(params.distance, smooth_scroll_touch_target_ptr->scroll_distance());
}
TEST_F(SyntheticGestureControllerNewTest, SmoothScrollGestureMouse) {
scoped_ptr<MockSyntheticSmoothScrollMouseTarget> smooth_scroll_mouse_target(
new MockSyntheticSmoothScrollMouseTarget);
const MockSyntheticSmoothScrollMouseTarget* smooth_scroll_mouse_target_ptr =
smooth_scroll_mouse_target.get();
controller_.reset(new SyntheticGestureControllerNew(
smooth_scroll_mouse_target.PassAs<SyntheticGestureTarget>()));
SyntheticSmoothScrollGestureParams params;
params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
params.distance = -6;
scoped_ptr<SyntheticSmoothScrollGestureNew> gesture(
new SyntheticSmoothScrollGestureNew(params));
controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
PostQuitMessageAndRun(30);
EXPECT_EQ(1, smooth_scroll_mouse_target_ptr->num_success());
EXPECT_EQ(0, smooth_scroll_mouse_target_ptr->num_failure());
EXPECT_GE(params.distance, smooth_scroll_mouse_target_ptr->scroll_distance());
}
} // namespace
} // namespace content