This source file includes following definitions.
- OnKeyboardEventAck
- OnWheelEventAck
- OnTouchEventAck
- OnGestureEventAck
- OnUnexpectedEventAck
- GetAndResetAckCount
- ack_count
- FilterInputEvent
- IncrementInFlightEventCount
- DecrementInFlightEventCount
- OnHasTouchEventHandlers
- GetOverscrollController
- DidFlush
- SetNeedsFlush
- Send
- GetAndResetSentEventCount
- HasMessages
- BuildScrollSequence
- BuildTouchSequence
- start_
- SetUp
- TearDown
- SendEvent
- SendEvent
- SendEventAck
- OnHasTouchEventHandlers
- GetAndResetSentEventCount
- GetAndResetAckCount
- AckCount
- NextLatencyID
- CreateLatencyInfo
- SimulateEventSequence
- SimulateTouchAndScrollEventSequence
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/renderer_host/input/input_ack_handler.h"
#include "content/browser/renderer_host/input/input_router_client.h"
#include "content/browser/renderer_host/input/input_router_impl.h"
#include "content/common/input/web_input_event_traits.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_sender.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
#include "ui/gfx/geometry/vector2d_f.h"
using base::TimeDelta;
using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
namespace content {
namespace {
class NullInputAckHandler : public InputAckHandler {
public:
NullInputAckHandler() : ack_count_(0) {}
virtual ~NullInputAckHandler() {}
virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
InputEventAckState ack_result) OVERRIDE {
++ack_count_;
}
virtual void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
InputEventAckState ack_result) OVERRIDE {
++ack_count_;
}
virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
InputEventAckState ack_result) OVERRIDE {
++ack_count_;
}
virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) OVERRIDE {
++ack_count_;
}
virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE {
++ack_count_;
}
size_t GetAndResetAckCount() {
size_t ack_count = ack_count_;
ack_count_ = 0;
return ack_count;
}
size_t ack_count() const { return ack_count_; }
private:
size_t ack_count_;
};
class NullInputRouterClient : public InputRouterClient {
public:
NullInputRouterClient() {}
virtual ~NullInputRouterClient() {}
virtual InputEventAckState FilterInputEvent(
const blink::WebInputEvent& input_event,
const ui::LatencyInfo& latency_info) OVERRIDE {
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
virtual void IncrementInFlightEventCount() OVERRIDE {}
virtual void DecrementInFlightEventCount() OVERRIDE {}
virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE {}
virtual OverscrollController* GetOverscrollController() const OVERRIDE {
return NULL;
}
virtual void DidFlush() OVERRIDE {}
virtual void SetNeedsFlush() OVERRIDE {}
};
class NullIPCSender : public IPC::Sender {
public:
NullIPCSender() : sent_count_(0) {}
virtual ~NullIPCSender() {}
virtual bool Send(IPC::Message* message) OVERRIDE {
delete message;
++sent_count_;
return true;
}
size_t GetAndResetSentEventCount() {
size_t message_count = sent_count_;
sent_count_ = 0;
return message_count;
}
bool HasMessages() const { return sent_count_ > 0; }
private:
size_t sent_count_;
};
typedef std::vector<WebGestureEvent> Gestures;
Gestures BuildScrollSequence(size_t steps,
gfx::Vector2dF origin,
gfx::Vector2dF distance) {
Gestures gestures;
const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
WebGestureEvent gesture;
gesture.type = WebInputEvent::GestureScrollBegin;
gesture.x = origin.x();
gesture.y = origin.y();
gestures.push_back(gesture);
gesture.type = WebInputEvent::GestureScrollUpdate;
gesture.data.scrollUpdate.deltaX = delta.x();
gesture.data.scrollUpdate.deltaY = delta.y();
for (size_t i = 0; i < steps; ++i) {
gesture.x += delta.x();
gesture.y += delta.y();
gestures.push_back(gesture);
}
gesture.type = WebInputEvent::GestureScrollEnd;
gestures.push_back(gesture);
return gestures;
}
typedef std::vector<WebTouchEvent> Touches;
Touches BuildTouchSequence(size_t steps,
gfx::Vector2dF origin,
gfx::Vector2dF distance) {
Touches touches;
const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
WebTouchEvent touch;
touch.touchesLength = 1;
touch.type = WebInputEvent::TouchStart;
touch.touches[0].id = 0;
touch.touches[0].state = WebTouchPoint::StatePressed;
touch.touches[0].position.x = origin.x();
touch.touches[0].position.y = origin.y();
touch.touches[0].screenPosition.x = origin.x();
touch.touches[0].screenPosition.y = origin.y();
touches.push_back(touch);
touch.type = WebInputEvent::TouchMove;
touch.touches[0].state = WebTouchPoint::StateMoved;
for (size_t i = 0; i < steps; ++i) {
touch.touches[0].position.x += delta.x();
touch.touches[0].position.y += delta.y();
touch.touches[0].screenPosition.x += delta.x();
touch.touches[0].screenPosition.y += delta.y();
touches.push_back(touch);
}
touch.type = WebInputEvent::TouchEnd;
touch.touches[0].state = WebTouchPoint::StateReleased;
touches.push_back(touch);
return touches;
}
class InputEventTimer {
public:
InputEventTimer(const char* test_name, int64 event_count)
: test_name_(test_name),
event_count_(event_count),
start_(base::TimeTicks::Now()) {}
~InputEventTimer() {
perf_test::PrintResult(
"avg_time_per_event",
"",
test_name_,
static_cast<size_t>(((base::TimeTicks::Now() - start_) / event_count_)
.InMicroseconds()),
"us",
true);
}
private:
const char* test_name_;
int64 event_count_;
base::TimeTicks start_;
DISALLOW_COPY_AND_ASSIGN(InputEventTimer);
};
}
class InputRouterImplPerfTest : public testing::Test {
public:
InputRouterImplPerfTest() : last_input_id_(0) {}
virtual ~InputRouterImplPerfTest() {}
protected:
virtual void SetUp() OVERRIDE {
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGestureDebounce)) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kDisableGestureDebounce);
}
sender_.reset(new NullIPCSender());
client_.reset(new NullInputRouterClient());
ack_handler_.reset(new NullInputAckHandler());
input_router_.reset(new InputRouterImpl(
sender_.get(), client_.get(), ack_handler_.get(), MSG_ROUTING_NONE));
}
virtual void TearDown() OVERRIDE {
base::MessageLoop::current()->RunUntilIdle();
input_router_.reset();
ack_handler_.reset();
client_.reset();
sender_.reset();
}
void SendEvent(const WebGestureEvent& gesture,
const ui::LatencyInfo& latency) {
input_router_->SendGestureEvent(
GestureEventWithLatencyInfo(gesture, latency));
}
void SendEvent(const WebTouchEvent& touch, const ui::LatencyInfo& latency) {
input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch, latency));
}
void SendEventAck(blink::WebInputEvent::Type type,
InputEventAckState ack_result) {
InputHostMsg_HandleInputEvent_ACK response(
0, type, ack_result, ui::LatencyInfo());
input_router_->OnMessageReceived(response);
}
void OnHasTouchEventHandlers(bool has_handlers) {
input_router_->OnMessageReceived(
ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
}
size_t GetAndResetSentEventCount() {
return sender_->GetAndResetSentEventCount();
}
size_t GetAndResetAckCount() { return ack_handler_->GetAndResetAckCount(); }
size_t AckCount() const { return ack_handler_->ack_count(); }
int64 NextLatencyID() { return ++last_input_id_; }
ui::LatencyInfo CreateLatencyInfo() {
ui::LatencyInfo latency;
latency.AddLatencyNumber(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
latency.AddLatencyNumber(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
1,
NextLatencyID());
return latency;
}
template <typename EventType>
void SimulateEventSequence(const char* test_name,
const std::vector<EventType>& events,
bool ack_delay,
size_t iterations) {
OnHasTouchEventHandlers(true);
const size_t event_count = events.size();
const size_t total_event_count = event_count * iterations;
InputEventTimer timer(test_name, total_event_count);
while (iterations--) {
size_t i = 0, ack_i = 0;
if (ack_delay)
SendEvent(events[i++], CreateLatencyInfo());
for (; i < event_count; ++i, ++ack_i) {
SendEvent(events[i], CreateLatencyInfo());
SendEventAck(events[ack_i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
}
if (ack_delay)
SendEventAck(events.back().type, INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(event_count, GetAndResetSentEventCount());
EXPECT_EQ(event_count, GetAndResetAckCount());
}
}
void SimulateTouchAndScrollEventSequence(const char* test_name,
size_t steps,
gfx::Vector2dF origin,
gfx::Vector2dF distance,
size_t iterations) {
OnHasTouchEventHandlers(true);
Gestures gestures = BuildScrollSequence(steps, origin, distance);
Touches touches = BuildTouchSequence(steps, origin, distance);
ASSERT_EQ(touches.size(), gestures.size());
const size_t event_count = gestures.size();
const size_t total_event_count = event_count * iterations * 2;
InputEventTimer timer(test_name, total_event_count);
while (iterations--) {
for (size_t i = 0; i < event_count; ++i) {
SendEvent(touches[i], CreateLatencyInfo());
if (!AckCount()) {
SendEventAck(touches[i].type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
}
SendEvent(gestures[i], CreateLatencyInfo());
SendEventAck(gestures[i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(2U, GetAndResetAckCount());
}
}
}
private:
int64 last_input_id_;
scoped_ptr<NullIPCSender> sender_;
scoped_ptr<NullInputRouterClient> client_;
scoped_ptr<NullInputAckHandler> ack_handler_;
scoped_ptr<InputRouterImpl> input_router_;
base::MessageLoopForUI message_loop_;
};
const size_t kDefaultSteps(100);
const size_t kDefaultIterations(100);
const gfx::Vector2dF kDefaultOrigin(100, 100);
const gfx::Vector2dF kDefaultDistance(500, 500);
TEST_F(InputRouterImplPerfTest, TouchSwipe) {
SimulateEventSequence(
"TouchSwipe ",
BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
false,
kDefaultIterations);
}
TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
SimulateEventSequence(
"TouchSwipeDelayedAck ",
BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
true,
kDefaultIterations);
}
TEST_F(InputRouterImplPerfTest, GestureScroll) {
SimulateEventSequence(
"GestureScroll ",
BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
false,
kDefaultIterations);
}
TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
SimulateEventSequence(
"GestureScrollDelayedAck ",
BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
true,
kDefaultIterations);
}
TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
SimulateTouchAndScrollEventSequence("TouchSwipeToGestureScroll ",
kDefaultSteps,
kDefaultOrigin,
kDefaultDistance,
kDefaultIterations);
}
}