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.
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/shell/browser/shell.h"
17 #include "content/test/content_browser_test.h"
18 #include "content/test/content_browser_test_utils.h"
19 #include "third_party/WebKit/public/web/WebInputEvent.h"
20 #include "ui/events/event_switches.h"
21 #include "ui/events/latency_info.h"
23 using blink::WebInputEvent
;
27 void GiveItSomeTime() {
28 base::RunLoop run_loop
;
29 base::MessageLoop::current()->PostDelayedTask(
31 run_loop
.QuitClosure(),
32 base::TimeDelta::FromMilliseconds(10));
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>"
42 " position: absolute;"
47 " background-color: green;"
48 " -webkit-transform: translate3d(0, 0, 0);"
51 " position: absolute;"
56 " background-color: blue;"
57 " -webkit-transform: translate3d(0, 0, 0);"
60 " position: absolute;"
65 " background-color: yellow;"
66 " -webkit-transform: translate3d(0, 0, 0);"
71 " second.ontouchstart = function() {};"
72 " third.ontouchstart = function(e) {"
73 " e.preventDefault();"
82 class InputEventMessageFilter
: public BrowserMessageFilter
{
84 InputEventMessageFilter()
85 : type_(WebInputEvent::Undefined
),
86 state_(INPUT_EVENT_ACK_STATE_UNKNOWN
) {}
88 void WaitForAck(WebInputEvent::Type type
) {
89 base::RunLoop run_loop
;
90 base::AutoReset
<base::Closure
> reset_quit(&quit_
, run_loop
.QuitClosure());
91 base::AutoReset
<WebInputEvent::Type
> reset_type(&type_
, type
);
95 InputEventAckState
last_ack_state() const { return state_
; }
98 virtual ~InputEventMessageFilter() {}
101 void ReceivedEventAck(WebInputEvent::Type type
, InputEventAckState state
) {
108 // BrowserMessageFilter:
109 virtual bool OnMessageReceived(const IPC::Message
& message
,
110 bool* message_was_ok
) OVERRIDE
{
111 if (message
.type() == InputHostMsg_HandleInputEvent_ACK::ID
) {
112 ui::LatencyInfo latency
;
113 WebInputEvent::Type type
= WebInputEvent::Undefined
;
114 InputEventAckState ack
= INPUT_EVENT_ACK_STATE_UNKNOWN
;
115 InputHostMsg_HandleInputEvent_ACK::Read(&message
, &type
, &ack
, &latency
);
116 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
117 base::Bind(&InputEventMessageFilter::ReceivedEventAck
,
124 WebInputEvent::Type type_
;
125 InputEventAckState state_
;
127 DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilter
);
130 class TouchInputBrowserTest
: public ContentBrowserTest
,
131 public testing::WithParamInterface
<std::string
> {
133 TouchInputBrowserTest() {}
134 virtual ~TouchInputBrowserTest() {}
136 RenderWidgetHostImpl
* GetWidgetHost() {
137 return RenderWidgetHostImpl::From(shell()->web_contents()->
138 GetRenderViewHost());
141 InputEventMessageFilter
* filter() { return filter_
.get(); }
144 void LoadURLAndAddFilter() {
145 const GURL
data_url(kTouchEventDataURL
);
146 NavigateToURL(shell(), data_url
);
148 WebContentsImpl
* web_contents
=
149 static_cast<WebContentsImpl
*>(shell()->web_contents());
150 RenderWidgetHostImpl
* host
=
151 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
152 host
->GetView()->SetSize(gfx::Size(400, 400));
154 // The page is loaded in the renderer, wait for a new frame to arrive.
155 while (!host
->ScheduleComposite())
158 filter_
= new InputEventMessageFilter();
159 host
->GetProcess()->AddFilter(filter_
);
162 // ContentBrowserTest:
163 virtual void SetUp() OVERRIDE
{
164 // We expect real pixel output for these tests.
167 // On legacy windows, these tests need real GL bindings to pass.
168 #if defined(OS_WIN) && !defined(USE_AURA)
172 ContentBrowserTest::SetUp();
175 virtual void SetUpCommandLine(CommandLine
* cmd
) OVERRIDE
{
176 cmd
->AppendSwitchASCII(switches::kTouchEvents
,
177 switches::kTouchEventsEnabled
);
178 cmd
->AppendSwitch(GetParam());
181 scoped_refptr
<InputEventMessageFilter
> filter_
;
184 // Touch input event tests don't work on Mac with the legacy software renderer.
185 // These can be enabled when software compositing is enabled.
186 // http://crbug.com/268038
187 #if defined(OS_MACOSX)
188 #define MAYBE_TouchNoHandler DISABLED_TouchNoHandler
190 #define MAYBE_TouchNoHandler TouchNoHandler
192 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest
, MAYBE_TouchNoHandler
) {
193 LoadURLAndAddFilter();
194 SyntheticWebTouchEvent touch
;
196 // A press on |first| should be acked with NO_CONSUMER_EXISTS since there is
197 // no touch-handler on it.
198 touch
.PressPoint(25, 25);
199 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
200 filter()->WaitForAck(WebInputEvent::TouchStart
);
202 if (GetParam() == std::string(switches::kEnableThreadedCompositing
)) {
203 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
,
204 filter()->last_ack_state());
206 // http://crbug.com/326232: This should be NO_CONSUMER_EXISTS once
207 // WebViewImpl::hasTouchEventHandlersAt() is implemented.
208 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
211 // If a touch-press is acked with NO_CONSUMER_EXISTS, then subsequent
212 // touch-points don't need to be dispatched until the touch point is released.
213 touch
.ReleasePoint(0);
214 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
218 // Touch input event tests don't work on Mac with the legacy software renderer.
219 // These can be enabled when software compositing is enabled.
220 // http://crbug.com/268038
221 #if defined(OS_MACOSX)
222 #define MAYBE_TouchHandlerNoConsume DISABLED_TouchHandlerNoConsume
224 #define MAYBE_TouchHandlerNoConsume TouchHandlerNoConsume
226 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest
, MAYBE_TouchHandlerNoConsume
) {
227 LoadURLAndAddFilter();
228 SyntheticWebTouchEvent touch
;
230 // Press on |second| should be acked with NOT_CONSUMED since there is a
231 // touch-handler on |second|, but it doesn't consume the event.
232 touch
.PressPoint(125, 25);
233 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
234 filter()->WaitForAck(WebInputEvent::TouchStart
);
235 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
237 touch
.ReleasePoint(0);
238 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
239 filter()->WaitForAck(WebInputEvent::TouchEnd
);
243 // Touch input event tests don't work on Mac with the legacy software renderer.
244 // These can be enabled when software compositing is enabled.
245 // http://crbug.com/268038
246 #if defined(OS_MACOSX)
247 #define MAYBE_TouchHandlerConsume DISABLED_TouchHandlerConsume
249 #define MAYBE_TouchHandlerConsume TouchHandlerConsume
251 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest
, MAYBE_TouchHandlerConsume
) {
252 LoadURLAndAddFilter();
253 SyntheticWebTouchEvent touch
;
255 // Press on |third| should be acked with CONSUMED since the touch-handler on
256 // |third| consimes the event.
257 touch
.PressPoint(25, 125);
258 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
259 filter()->WaitForAck(WebInputEvent::TouchStart
);
260 EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED
, filter()->last_ack_state());
262 touch
.ReleasePoint(0);
263 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
264 filter()->WaitForAck(WebInputEvent::TouchEnd
);
267 // Touch input event tests don't work on Mac with the legacy software renderer.
268 // These can be enabled when software compositing is enabled.
269 // http://crbug.com/268038
270 #if defined(OS_MACOSX)
271 #define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
273 #define MAYBE_MultiPointTouchPress MultiPointTouchPress
275 IN_PROC_BROWSER_TEST_P(TouchInputBrowserTest
, MAYBE_MultiPointTouchPress
) {
276 LoadURLAndAddFilter();
277 SyntheticWebTouchEvent touch
;
279 // Press on |first|, which sould be acked with NO_CONSUMER_EXISTS. Then press
280 // on |third|. That point should be acked with CONSUMED.
281 touch
.PressPoint(25, 25);
282 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
283 filter()->WaitForAck(WebInputEvent::TouchStart
);
284 if (GetParam() == std::string(switches::kEnableThreadedCompositing
)) {
285 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
,
286 filter()->last_ack_state());
288 // http://crbug.com/326232: This should be NO_CONSUMER_EXISTS once
289 // WebViewImpl::hasTouchEventHandlersAt() is implemented.
290 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
293 touch
.PressPoint(25, 125);
294 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
295 filter()->WaitForAck(WebInputEvent::TouchStart
);
296 EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED
, filter()->last_ack_state());
299 INSTANTIATE_TEST_CASE_P(WithoutInputHandlerProxy
, TouchInputBrowserTest
,
300 ::testing::Values(std::string(switches::kDisableThreadedCompositing
)));
302 #if !defined(OS_MACOSX)
303 INSTANTIATE_TEST_CASE_P(WithInputHandlerProxy
, TouchInputBrowserTest
,
304 ::testing::Values(std::string(switches::kEnableThreadedCompositing
)));
307 } // namespace content