Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / touch_input_browsertest.cc
1 // Copyright 2013 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/auto_reset.h"
6 #include "base/command_line.h"
7 #include "base/run_loop.h"
8 #include "content/browser/renderer_host/render_widget_host_impl.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/common/input/synthetic_web_input_event_builders.h"
11 #include "content/common/input_messages.h"
12 #include "content/public/browser/browser_message_filter.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/render_widget_host_view.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/public/test/content_browser_test_utils.h"
18 #include "content/shell/browser/shell.h"
19 #include "third_party/WebKit/public/web/WebInputEvent.h"
20 #include "ui/events/event_switches.h"
21 #include "ui/events/latency_info.h"
22
23 using blink::WebInputEvent;
24
25 namespace {
26
27 void GiveItSomeTime() {
28   base::RunLoop run_loop;
29   base::MessageLoop::current()->PostDelayedTask(
30       FROM_HERE,
31       run_loop.QuitClosure(),
32       base::TimeDelta::FromMilliseconds(10));
33   run_loop.Run();
34 }
35
36 const char kTouchEventDataURL[] =
37     "data:text/html;charset=utf-8,"
38     "<body onload='setup();'>"
39     "<div id='first'></div><div id='second'></div><div id='third'></div>"
40     "<style>"
41     "  #first {"
42     "    position: absolute;"
43     "    width: 100px;"
44     "    height: 100px;"
45     "    top: 0px;"
46     "    left: 0px;"
47     "    background-color: green;"
48     "    -webkit-transform: translate3d(0, 0, 0);"
49     "  }"
50     "  #second {"
51     "    position: absolute;"
52     "    width: 100px;"
53     "    height: 100px;"
54     "    top: 0px;"
55     "    left: 110px;"
56     "    background-color: blue;"
57     "    -webkit-transform: translate3d(0, 0, 0);"
58     "  }"
59     "  #third {"
60     "    position: absolute;"
61     "    width: 100px;"
62     "    height: 100px;"
63     "    top: 110px;"
64     "    left: 0px;"
65     "    background-color: yellow;"
66     "    -webkit-transform: translate3d(0, 0, 0);"
67     "  }"
68     "</style>"
69     "<script>"
70     "  function setup() {"
71     "    second.ontouchstart = function() {};"
72     "    third.ontouchstart = function(e) {"
73     "      e.preventDefault();"
74     "    };"
75     "  }"
76     "</script>";
77
78 }  // namespace
79
80 namespace content {
81
82 class InputEventMessageFilter : public BrowserMessageFilter {
83  public:
84   InputEventMessageFilter()
85       : BrowserMessageFilter(InputMsgStart),
86         type_(WebInputEvent::Undefined),
87         state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
88
89   void WaitForAck(WebInputEvent::Type type) {
90     base::RunLoop run_loop;
91     base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
92     base::AutoReset<WebInputEvent::Type> reset_type(&type_, type);
93     run_loop.Run();
94   }
95
96   InputEventAckState last_ack_state() const { return state_; }
97
98  protected:
99   virtual ~InputEventMessageFilter() {}
100
101  private:
102   void ReceivedEventAck(WebInputEvent::Type type, InputEventAckState state) {
103     if (type_ == type) {
104       state_ = state;
105       quit_.Run();
106     }
107   }
108
109   // BrowserMessageFilter:
110   virtual bool OnMessageReceived(const IPC::Message& message,
111                                  bool* message_was_ok) OVERRIDE {
112     if (message.type() == InputHostMsg_HandleInputEvent_ACK::ID) {
113       ui::LatencyInfo latency;
114       WebInputEvent::Type type = WebInputEvent::Undefined;
115       InputEventAckState ack = INPUT_EVENT_ACK_STATE_UNKNOWN;
116       InputHostMsg_HandleInputEvent_ACK::Read(&message, &type, &ack, &latency);
117       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
118           base::Bind(&InputEventMessageFilter::ReceivedEventAck,
119                      this, type, ack));
120     }
121     return false;
122   }
123
124   base::Closure quit_;
125   WebInputEvent::Type type_;
126   InputEventAckState state_;
127
128   DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilter);
129 };
130
131 class TouchInputBrowserTest : public ContentBrowserTest,
132                               public testing::WithParamInterface<std::string> {
133  public:
134   TouchInputBrowserTest() {}
135   virtual ~TouchInputBrowserTest() {}
136
137   RenderWidgetHostImpl* GetWidgetHost() {
138     return RenderWidgetHostImpl::From(shell()->web_contents()->
139                                           GetRenderViewHost());
140   }
141
142   InputEventMessageFilter* filter() { return filter_.get(); }
143
144  protected:
145   void LoadURLAndAddFilter() {
146     const GURL data_url(kTouchEventDataURL);
147     NavigateToURL(shell(), data_url);
148
149     WebContentsImpl* web_contents =
150         static_cast<WebContentsImpl*>(shell()->web_contents());
151     RenderWidgetHostImpl* host =
152         RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
153     host->GetView()->SetSize(gfx::Size(400, 400));
154
155     // The page is loaded in the renderer, wait for a new frame to arrive.
156     while (!host->ScheduleComposite())
157       GiveItSomeTime();
158
159     filter_ = new InputEventMessageFilter();
160     host->GetProcess()->AddFilter(filter_);
161   }
162
163   virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
164     cmd->AppendSwitchASCII(switches::kTouchEvents,
165                            switches::kTouchEventsEnabled);
166     cmd->AppendSwitch(GetParam());
167   }
168
169   scoped_refptr<InputEventMessageFilter> filter_;
170 };
171
172 #if defined(OS_MACOSX)
173 // TODO(ccameron): Failing on mac: crbug.com/346363
174 #define MAYBE_TouchNoHandler DISABLED_TouchNoHandler
175 #else
176 #define MAYBE_TouchNoHandler TouchNoHandler
177 #endif
178 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
179   LoadURLAndAddFilter();
180   SyntheticWebTouchEvent touch;
181
182   // A press on |first| should be acked with NO_CONSUMER_EXISTS since there is
183   // no touch-handler on it.
184   touch.PressPoint(25, 25);
185   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
186   filter()->WaitForAck(WebInputEvent::TouchStart);
187
188   if (GetParam() == std::string(switches::kEnableThreadedCompositing)) {
189     EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
190               filter()->last_ack_state());
191   } else {
192     // http://crbug.com/326232: This should be NO_CONSUMER_EXISTS once
193     // WebViewImpl::hasTouchEventHandlersAt() is implemented.
194     EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
195   }
196
197   // If a touch-press is acked with NO_CONSUMER_EXISTS, then subsequent
198   // touch-points don't need to be dispatched until the touch point is released.
199   touch.ReleasePoint(0);
200   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
201   touch.ResetPoints();
202 }
203
204 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest, TouchHandlerNoConsume) {
205   LoadURLAndAddFilter();
206   SyntheticWebTouchEvent touch;
207
208   // Press on |second| should be acked with NOT_CONSUMED since there is a
209   // touch-handler on |second|, but it doesn't consume the event.
210   touch.PressPoint(125, 25);
211   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
212   filter()->WaitForAck(WebInputEvent::TouchStart);
213   EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
214
215   touch.ReleasePoint(0);
216   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
217   filter()->WaitForAck(WebInputEvent::TouchEnd);
218   touch.ResetPoints();
219 }
220
221 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest, TouchHandlerConsume) {
222   LoadURLAndAddFilter();
223   SyntheticWebTouchEvent touch;
224
225   // Press on |third| should be acked with CONSUMED since the touch-handler on
226   // |third| consimes the event.
227   touch.PressPoint(25, 125);
228   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
229   filter()->WaitForAck(WebInputEvent::TouchStart);
230   EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, filter()->last_ack_state());
231
232   touch.ReleasePoint(0);
233   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
234   filter()->WaitForAck(WebInputEvent::TouchEnd);
235 }
236
237 #if defined(OS_MACOSX)
238 // TODO(ccameron): Failing on mac: crbug.com/346363
239 #define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
240 #else
241 #define MAYBE_MultiPointTouchPress MultiPointTouchPress
242 #endif
243 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest, MAYBE_MultiPointTouchPress) {
244   LoadURLAndAddFilter();
245   SyntheticWebTouchEvent touch;
246
247   // Press on |first|, which sould be acked with NO_CONSUMER_EXISTS. Then press
248   // on |third|. That point should be acked with CONSUMED.
249   touch.PressPoint(25, 25);
250   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
251   filter()->WaitForAck(WebInputEvent::TouchStart);
252   if (GetParam() == std::string(switches::kEnableThreadedCompositing)) {
253     EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
254               filter()->last_ack_state());
255   } else {
256     // http://crbug.com/326232: This should be NO_CONSUMER_EXISTS once
257     // WebViewImpl::hasTouchEventHandlersAt() is implemented.
258     EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
259   }
260
261   touch.PressPoint(25, 125);
262   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
263   filter()->WaitForAck(WebInputEvent::TouchStart);
264   EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, filter()->last_ack_state());
265 }
266
267 // Threaded compositing is always enabled on Aura and Mac.
268 #if !defined(USE_AURA) && !defined(OS_MACOSX)
269 INSTANTIATE_TEST_CASE_P(WithoutInputHandlerProxy, TouchInputBrowserTest,
270     ::testing::Values(std::string(switches::kDisableThreadedCompositing)));
271 #endif
272
273 #if defined(USE_AURA) || defined(OS_MACOSX)
274 INSTANTIATE_TEST_CASE_P(WithInputHandlerProxy, TouchInputBrowserTest,
275     ::testing::Values(std::string(switches::kEnableThreadedCompositing)));
276 #endif
277
278 }  // namespace content