Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / input_router_impl_perftest.cc
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.
4
5 #include "base/basictypes.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "content/browser/renderer_host/input/input_ack_handler.h"
8 #include "content/browser/renderer_host/input/input_router_client.h"
9 #include "content/browser/renderer_host/input/input_router_impl.h"
10 #include "content/common/input/web_input_event_traits.h"
11 #include "content/common/input_messages.h"
12 #include "content/common/view_messages.h"
13 #include "ipc/ipc_sender.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/perf/perf_test.h"
16 #include "ui/gfx/geometry/vector2d_f.h"
17
18 using base::TimeDelta;
19 using blink::WebGestureEvent;
20 using blink::WebInputEvent;
21 using blink::WebTouchEvent;
22 using blink::WebTouchPoint;
23
24 namespace content {
25
26 namespace {
27
28 class NullInputAckHandler : public InputAckHandler {
29  public:
30   NullInputAckHandler() : ack_count_(0) {}
31   ~NullInputAckHandler() override {}
32
33   // InputAckHandler
34   void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
35                           InputEventAckState ack_result) override {
36     ++ack_count_;
37   }
38   void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
39                        InputEventAckState ack_result) override {
40     ++ack_count_;
41   }
42   void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
43                        InputEventAckState ack_result) override {
44     ++ack_count_;
45   }
46   void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
47                          InputEventAckState ack_result) override {
48     ++ack_count_;
49   }
50   void OnUnexpectedEventAck(UnexpectedEventAckType type) override {
51     ++ack_count_;
52   }
53
54   size_t GetAndResetAckCount() {
55     size_t ack_count = ack_count_;
56     ack_count_ = 0;
57     return ack_count;
58   }
59
60   size_t ack_count() const { return ack_count_; }
61
62  private:
63   size_t ack_count_;
64 };
65
66 class NullInputRouterClient : public InputRouterClient {
67  public:
68   NullInputRouterClient() {}
69   ~NullInputRouterClient() override {}
70
71   // InputRouterClient
72   InputEventAckState FilterInputEvent(
73       const blink::WebInputEvent& input_event,
74       const ui::LatencyInfo& latency_info) override {
75     return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
76   }
77   void IncrementInFlightEventCount() override {}
78   void DecrementInFlightEventCount() override {}
79   void OnHasTouchEventHandlers(bool has_handlers) override {}
80   void DidFlush() override {}
81   void SetNeedsFlush() override {}
82   void DidOverscroll(const DidOverscrollParams& params) override {}
83 };
84
85 class NullIPCSender : public IPC::Sender {
86  public:
87   NullIPCSender() : sent_count_(0) {}
88   ~NullIPCSender() override {}
89
90   bool Send(IPC::Message* message) override {
91     delete message;
92     ++sent_count_;
93     return true;
94   }
95
96   size_t GetAndResetSentEventCount() {
97     size_t message_count = sent_count_;
98     sent_count_ = 0;
99     return message_count;
100   }
101
102   bool HasMessages() const { return sent_count_ > 0; }
103
104  private:
105   size_t sent_count_;
106 };
107
108 // TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
109 typedef std::vector<WebGestureEvent> Gestures;
110 Gestures BuildScrollSequence(size_t steps,
111                              gfx::Vector2dF origin,
112                              gfx::Vector2dF distance) {
113   Gestures gestures;
114   const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
115
116   WebGestureEvent gesture;
117   gesture.type = WebInputEvent::GestureScrollBegin;
118   gesture.x = origin.x();
119   gesture.y = origin.y();
120   gestures.push_back(gesture);
121
122   gesture.type = WebInputEvent::GestureScrollUpdate;
123   gesture.data.scrollUpdate.deltaX = delta.x();
124   gesture.data.scrollUpdate.deltaY = delta.y();
125   for (size_t i = 0; i < steps; ++i) {
126     gesture.x += delta.x();
127     gesture.y += delta.y();
128     gestures.push_back(gesture);
129   }
130
131   gesture.type = WebInputEvent::GestureScrollEnd;
132   gestures.push_back(gesture);
133   return gestures;
134 }
135
136 typedef std::vector<WebTouchEvent> Touches;
137 Touches BuildTouchSequence(size_t steps,
138                            gfx::Vector2dF origin,
139                            gfx::Vector2dF distance) {
140   Touches touches;
141   const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
142
143   WebTouchEvent touch;
144   touch.touchesLength = 1;
145   touch.type = WebInputEvent::TouchStart;
146   touch.touches[0].id = 0;
147   touch.touches[0].state = WebTouchPoint::StatePressed;
148   touch.touches[0].position.x = origin.x();
149   touch.touches[0].position.y = origin.y();
150   touch.touches[0].screenPosition.x = origin.x();
151   touch.touches[0].screenPosition.y = origin.y();
152   touches.push_back(touch);
153
154   touch.type = WebInputEvent::TouchMove;
155   touch.touches[0].state = WebTouchPoint::StateMoved;
156   for (size_t i = 0; i < steps; ++i) {
157     touch.touches[0].position.x += delta.x();
158     touch.touches[0].position.y += delta.y();
159     touch.touches[0].screenPosition.x += delta.x();
160     touch.touches[0].screenPosition.y += delta.y();
161     touches.push_back(touch);
162   }
163
164   touch.type = WebInputEvent::TouchEnd;
165   touch.touches[0].state = WebTouchPoint::StateReleased;
166   touches.push_back(touch);
167   return touches;
168 }
169
170 class InputEventTimer {
171  public:
172   InputEventTimer(const char* test_name, int64 event_count)
173       : test_name_(test_name),
174         event_count_(event_count),
175         start_(base::TimeTicks::Now()) {}
176
177   ~InputEventTimer() {
178     perf_test::PrintResult(
179         "avg_time_per_event",
180         "",
181         test_name_,
182         static_cast<size_t>(((base::TimeTicks::Now() - start_) / event_count_)
183                                 .InMicroseconds()),
184         "us",
185         true);
186   }
187
188  private:
189   const char* test_name_;
190   int64 event_count_;
191   base::TimeTicks start_;
192   DISALLOW_COPY_AND_ASSIGN(InputEventTimer);
193 };
194
195 }  // namespace
196
197 class InputRouterImplPerfTest : public testing::Test {
198  public:
199   InputRouterImplPerfTest() : last_input_id_(0) {}
200   ~InputRouterImplPerfTest() override {}
201
202  protected:
203   // testing::Test
204   void SetUp() override {
205     sender_.reset(new NullIPCSender());
206     client_.reset(new NullInputRouterClient());
207     ack_handler_.reset(new NullInputAckHandler());
208     input_router_.reset(new InputRouterImpl(sender_.get(),
209                                             client_.get(),
210                                             ack_handler_.get(),
211                                             MSG_ROUTING_NONE,
212                                             InputRouterImpl::Config()));
213   }
214
215   void TearDown() override {
216     base::MessageLoop::current()->RunUntilIdle();
217
218     input_router_.reset();
219     ack_handler_.reset();
220     client_.reset();
221     sender_.reset();
222   }
223
224   void SendEvent(const WebGestureEvent& gesture,
225                  const ui::LatencyInfo& latency) {
226     input_router_->SendGestureEvent(
227         GestureEventWithLatencyInfo(gesture, latency));
228   }
229
230   void SendEvent(const WebTouchEvent& touch, const ui::LatencyInfo& latency) {
231     input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch, latency));
232   }
233
234   void SendEventAckIfNecessary(const blink::WebInputEvent& event,
235                                InputEventAckState ack_result) {
236     if (WebInputEventTraits::IgnoresAckDisposition(event))
237       return;
238     InputHostMsg_HandleInputEvent_ACK_Params ack;
239     ack.type = event.type;
240     ack.state = ack_result;
241     InputHostMsg_HandleInputEvent_ACK response(0, ack);
242     input_router_->OnMessageReceived(response);
243   }
244
245   void OnHasTouchEventHandlers(bool has_handlers) {
246     input_router_->OnMessageReceived(
247         ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
248   }
249
250   size_t GetAndResetSentEventCount() {
251     return sender_->GetAndResetSentEventCount();
252   }
253
254   size_t GetAndResetAckCount() { return ack_handler_->GetAndResetAckCount(); }
255
256   size_t AckCount() const { return ack_handler_->ack_count(); }
257
258   int64 NextLatencyID() { return ++last_input_id_; }
259
260   ui::LatencyInfo CreateLatencyInfo() {
261     ui::LatencyInfo latency;
262     latency.AddLatencyNumber(
263         ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
264     latency.AddLatencyNumber(
265         ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
266         1,
267         NextLatencyID());
268     return latency;
269   }
270
271   // TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
272   template <typename EventType>
273   void SimulateEventSequence(const char* test_name,
274                              const std::vector<EventType>& events,
275                              bool ack_delay,
276                              size_t iterations) {
277     OnHasTouchEventHandlers(true);
278
279     const size_t event_count = events.size();
280     const size_t total_event_count = event_count * iterations;
281
282     InputEventTimer timer(test_name, total_event_count);
283     while (iterations--) {
284       size_t i = 0, ack_i = 0;
285       if (ack_delay)
286         SendEvent(events[i++], CreateLatencyInfo());
287
288       for (; i < event_count; ++i, ++ack_i) {
289         SendEvent(events[i], CreateLatencyInfo());
290         SendEventAckIfNecessary(events[ack_i], INPUT_EVENT_ACK_STATE_CONSUMED);
291       }
292
293       if (ack_delay)
294         SendEventAckIfNecessary(events.back(), INPUT_EVENT_ACK_STATE_CONSUMED);
295
296       EXPECT_EQ(event_count, GetAndResetSentEventCount());
297       EXPECT_EQ(event_count, GetAndResetAckCount());
298     }
299   }
300
301   void SimulateTouchAndScrollEventSequence(const char* test_name,
302                                            size_t steps,
303                                            gfx::Vector2dF origin,
304                                            gfx::Vector2dF distance,
305                                            size_t iterations) {
306     OnHasTouchEventHandlers(true);
307
308     Gestures gestures = BuildScrollSequence(steps, origin, distance);
309     Touches touches = BuildTouchSequence(steps, origin, distance);
310     ASSERT_EQ(touches.size(), gestures.size());
311
312     const size_t event_count = gestures.size();
313     const size_t total_event_count = event_count * iterations * 2;
314
315     InputEventTimer timer(test_name, total_event_count);
316     while (iterations--) {
317       for (size_t i = 0; i < event_count; ++i) {
318         SendEvent(touches[i], CreateLatencyInfo());
319         // Touches may not be forwarded after the scroll sequence has begun, so
320         // only ack if necessary.
321         if (!AckCount()) {
322           SendEventAckIfNecessary(touches[i],
323                                   INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
324         }
325
326         SendEvent(gestures[i], CreateLatencyInfo());
327         SendEventAckIfNecessary(gestures[i], INPUT_EVENT_ACK_STATE_CONSUMED);
328         EXPECT_EQ(2U, GetAndResetAckCount());
329       }
330     }
331   }
332
333  private:
334   int64 last_input_id_;
335   scoped_ptr<NullIPCSender> sender_;
336   scoped_ptr<NullInputRouterClient> client_;
337   scoped_ptr<NullInputAckHandler> ack_handler_;
338   scoped_ptr<InputRouterImpl> input_router_;
339   base::MessageLoopForUI message_loop_;
340 };
341
342 const size_t kDefaultSteps(100);
343 const size_t kDefaultIterations(100);
344 const gfx::Vector2dF kDefaultOrigin(100, 100);
345 const gfx::Vector2dF kDefaultDistance(500, 500);
346
347 TEST_F(InputRouterImplPerfTest, TouchSwipe) {
348   SimulateEventSequence(
349       "TouchSwipe ",
350       BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
351       false,
352       kDefaultIterations);
353 }
354
355 TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
356   SimulateEventSequence(
357       "TouchSwipeDelayedAck ",
358       BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
359       true,
360       kDefaultIterations);
361 }
362
363 TEST_F(InputRouterImplPerfTest, GestureScroll) {
364   SimulateEventSequence(
365       "GestureScroll ",
366       BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
367       false,
368       kDefaultIterations);
369 }
370
371 TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
372   SimulateEventSequence(
373       "GestureScrollDelayedAck ",
374       BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
375       true,
376       kDefaultIterations);
377 }
378
379 TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
380   SimulateTouchAndScrollEventSequence("TouchSwipeToGestureScroll ",
381                                       kDefaultSteps,
382                                       kDefaultOrigin,
383                                       kDefaultDistance,
384                                       kDefaultIterations);
385 }
386
387 }  // namespace content