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/location.h"
8 #include "base/run_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "content/browser/gpu/compositor_util.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/common/input/synthetic_web_input_event_builders.h"
15 #include "content/common/input_messages.h"
16 #include "content/public/browser/browser_message_filter.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/render_widget_host_view.h"
19 #include "content/public/common/content_switches.h"
20 #include "content/public/test/content_browser_test.h"
21 #include "content/public/test/content_browser_test_utils.h"
22 #include "content/shell/browser/shell.h"
23 #include "third_party/WebKit/public/web/WebInputEvent.h"
24 #include "ui/events/event_switches.h"
25 #include "ui/events/latency_info.h"
27 using blink::WebInputEvent
;
31 void GiveItSomeTime() {
32 base::RunLoop run_loop
;
33 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
34 FROM_HERE
, run_loop
.QuitClosure(), base::TimeDelta::FromMilliseconds(10));
38 const char kTouchEventDataURL
[] =
39 "data:text/html;charset=utf-8,"
40 #if defined(OS_ANDROID)
42 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
45 "<body onload='setup();'>"
46 "<div id='first'></div><div id='second'></div><div id='third'></div>"
49 " position: absolute;"
54 " background-color: green;"
55 " -webkit-transform: translate3d(0, 0, 0);"
58 " position: absolute;"
63 " background-color: blue;"
64 " -webkit-transform: translate3d(0, 0, 0);"
67 " position: absolute;"
72 " background-color: yellow;"
73 " -webkit-transform: translate3d(0, 0, 0);"
78 " second.ontouchstart = function() {};"
79 " third.ontouchstart = function(e) {"
80 " e.preventDefault();"
89 class InputEventMessageFilter
: public BrowserMessageFilter
{
91 InputEventMessageFilter()
92 : BrowserMessageFilter(InputMsgStart
),
93 type_(WebInputEvent::Undefined
),
94 state_(INPUT_EVENT_ACK_STATE_UNKNOWN
) {}
96 void WaitForAck(WebInputEvent::Type type
) {
97 base::RunLoop run_loop
;
98 base::AutoReset
<base::Closure
> reset_quit(&quit_
, run_loop
.QuitClosure());
99 base::AutoReset
<WebInputEvent::Type
> reset_type(&type_
, type
);
103 InputEventAckState
last_ack_state() const { return state_
; }
106 ~InputEventMessageFilter() override
{}
109 void ReceivedEventAck(WebInputEvent::Type type
, InputEventAckState state
) {
116 // BrowserMessageFilter:
117 bool OnMessageReceived(const IPC::Message
& message
) override
{
118 if (message
.type() == InputHostMsg_HandleInputEvent_ACK::ID
) {
119 InputHostMsg_HandleInputEvent_ACK::Param params
;
120 InputHostMsg_HandleInputEvent_ACK::Read(&message
, ¶ms
);
121 WebInputEvent::Type type
= base::get
<0>(params
).type
;
122 InputEventAckState ack
= base::get
<0>(params
).state
;
123 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
124 base::Bind(&InputEventMessageFilter::ReceivedEventAck
,
131 WebInputEvent::Type type_
;
132 InputEventAckState state_
;
134 DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilter
);
137 class TouchInputBrowserTest
: public ContentBrowserTest
{
139 TouchInputBrowserTest() {}
140 ~TouchInputBrowserTest() override
{}
142 RenderWidgetHostImpl
* GetWidgetHost() {
143 return RenderWidgetHostImpl::From(shell()->web_contents()->
144 GetRenderViewHost());
147 InputEventMessageFilter
* filter() { return filter_
.get(); }
150 void LoadURLAndAddFilter() {
151 const GURL
data_url(kTouchEventDataURL
);
152 NavigateToURL(shell(), data_url
);
154 WebContentsImpl
* web_contents
=
155 static_cast<WebContentsImpl
*>(shell()->web_contents());
156 RenderWidgetHostImpl
* host
=
157 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
158 host
->GetView()->SetSize(gfx::Size(400, 400));
160 // The page is loaded in the renderer, wait for a new frame to arrive.
161 while (!host
->ScheduleComposite())
164 filter_
= new InputEventMessageFilter();
165 host
->GetProcess()->AddFilter(filter_
.get());
168 void SetUpCommandLine(base::CommandLine
* cmd
) override
{
169 cmd
->AppendSwitchASCII(switches::kTouchEvents
,
170 switches::kTouchEventsEnabled
);
173 scoped_refptr
<InputEventMessageFilter
> filter_
;
176 #if defined(OS_MACOSX)
177 // TODO(ccameron): Failing on mac: crbug.com/346363
178 #define MAYBE_TouchNoHandler DISABLED_TouchNoHandler
180 #define MAYBE_TouchNoHandler TouchNoHandler
182 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, MAYBE_TouchNoHandler
) {
183 LoadURLAndAddFilter();
184 SyntheticWebTouchEvent touch
;
186 // A press on |first| should be acked with NO_CONSUMER_EXISTS since there is
187 // no touch-handler on it.
188 touch
.PressPoint(25, 25);
189 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
190 filter()->WaitForAck(WebInputEvent::TouchStart
);
192 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
,
193 filter()->last_ack_state());
195 // If a touch-press is acked with NO_CONSUMER_EXISTS, then subsequent
196 // touch-points don't need to be dispatched until the touch point is released.
197 touch
.ReleasePoint(0);
198 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
202 #if defined(OS_CHROMEOS)
204 #define MAYBE_TouchHandlerNoConsume DISABLED_TouchHandlerNoConsume
206 #define MAYBE_TouchHandlerNoConsume TouchHandlerNoConsume
208 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, MAYBE_TouchHandlerNoConsume
) {
209 LoadURLAndAddFilter();
210 SyntheticWebTouchEvent touch
;
212 // Press on |second| should be acked with NOT_CONSUMED since there is a
213 // touch-handler on |second|, but it doesn't consume the event.
214 touch
.PressPoint(125, 25);
215 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
216 filter()->WaitForAck(WebInputEvent::TouchStart
);
217 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
219 touch
.ReleasePoint(0);
220 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
221 filter()->WaitForAck(WebInputEvent::TouchEnd
);
225 #if defined(OS_CHROMEOS)
227 #define MAYBE_TouchHandlerConsume DISABLED_TouchHandlerConsume
229 #define MAYBE_TouchHandlerConsume TouchHandlerConsume
231 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, MAYBE_TouchHandlerConsume
) {
232 LoadURLAndAddFilter();
233 SyntheticWebTouchEvent touch
;
235 // Press on |third| should be acked with CONSUMED since the touch-handler on
236 // |third| consimes the event.
237 touch
.PressPoint(25, 125);
238 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
239 filter()->WaitForAck(WebInputEvent::TouchStart
);
240 EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED
, filter()->last_ack_state());
242 touch
.ReleasePoint(0);
243 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
244 filter()->WaitForAck(WebInputEvent::TouchEnd
);
247 #if defined(OS_CHROMEOS)
249 #define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
250 #elif defined(OS_MACOSX)
251 // TODO(ccameron): Failing on mac: crbug.com/346363
252 #define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
254 #define MAYBE_MultiPointTouchPress MultiPointTouchPress
256 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, MAYBE_MultiPointTouchPress
) {
257 LoadURLAndAddFilter();
258 SyntheticWebTouchEvent touch
;
260 // Press on |first|, which sould be acked with NO_CONSUMER_EXISTS. Then press
261 // on |third|. That point should be acked with CONSUMED.
262 touch
.PressPoint(25, 25);
263 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
264 filter()->WaitForAck(WebInputEvent::TouchStart
);
265 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
,
266 filter()->last_ack_state());
268 touch
.PressPoint(25, 125);
269 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
270 filter()->WaitForAck(WebInputEvent::TouchStart
);
271 EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED
, filter()->last_ack_state());
274 } // namespace content