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/gpu/compositor_util.h"
9 #include "content/browser/renderer_host/render_widget_host_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/common/input/synthetic_web_input_event_builders.h"
12 #include "content/common/input_messages.h"
13 #include "content/public/browser/browser_message_filter.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/render_widget_host_view.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "content/public/test/content_browser_test_utils.h"
19 #include "content/shell/browser/shell.h"
20 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 #include "ui/events/event_switches.h"
22 #include "ui/events/latency_info.h"
24 using blink::WebInputEvent
;
28 void GiveItSomeTime() {
29 base::RunLoop run_loop
;
30 base::MessageLoop::current()->PostDelayedTask(
32 run_loop
.QuitClosure(),
33 base::TimeDelta::FromMilliseconds(10));
37 const char kTouchEventDataURL
[] =
38 "data:text/html;charset=utf-8,"
39 "<body onload='setup();'>"
40 "<div id='first'></div><div id='second'></div><div id='third'></div>"
43 " position: absolute;"
48 " background-color: green;"
49 " -webkit-transform: translate3d(0, 0, 0);"
52 " position: absolute;"
57 " background-color: blue;"
58 " -webkit-transform: translate3d(0, 0, 0);"
61 " position: absolute;"
66 " background-color: yellow;"
67 " -webkit-transform: translate3d(0, 0, 0);"
72 " second.ontouchstart = function() {};"
73 " third.ontouchstart = function(e) {"
74 " e.preventDefault();"
83 class InputEventMessageFilter
: public BrowserMessageFilter
{
85 InputEventMessageFilter()
86 : BrowserMessageFilter(InputMsgStart
),
87 type_(WebInputEvent::Undefined
),
88 state_(INPUT_EVENT_ACK_STATE_UNKNOWN
) {}
90 void WaitForAck(WebInputEvent::Type type
) {
91 base::RunLoop run_loop
;
92 base::AutoReset
<base::Closure
> reset_quit(&quit_
, run_loop
.QuitClosure());
93 base::AutoReset
<WebInputEvent::Type
> reset_type(&type_
, type
);
97 InputEventAckState
last_ack_state() const { return state_
; }
100 virtual ~InputEventMessageFilter() {}
103 void ReceivedEventAck(WebInputEvent::Type type
, InputEventAckState state
) {
110 // BrowserMessageFilter:
111 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
112 if (message
.type() == InputHostMsg_HandleInputEvent_ACK::ID
) {
113 InputHostMsg_HandleInputEvent_ACK::Param params
;
114 InputHostMsg_HandleInputEvent_ACK::Read(&message
, ¶ms
);
115 WebInputEvent::Type type
= params
.a
.type
;
116 InputEventAckState ack
= params
.a
.state
;
117 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
118 base::Bind(&InputEventMessageFilter::ReceivedEventAck
,
125 WebInputEvent::Type type_
;
126 InputEventAckState state_
;
128 DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilter
);
131 class TouchInputBrowserTest
: public ContentBrowserTest
{
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_
.get());
162 virtual void SetUpCommandLine(CommandLine
* cmd
) OVERRIDE
{
163 cmd
->AppendSwitchASCII(switches::kTouchEvents
,
164 switches::kTouchEventsEnabled
);
167 scoped_refptr
<InputEventMessageFilter
> filter_
;
170 #if defined(OS_MACOSX)
171 // TODO(ccameron): Failing on mac: crbug.com/346363
172 #define MAYBE_TouchNoHandler DISABLED_TouchNoHandler
174 #define MAYBE_TouchNoHandler TouchNoHandler
176 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, MAYBE_TouchNoHandler
) {
177 LoadURLAndAddFilter();
178 SyntheticWebTouchEvent touch
;
180 // A press on |first| should be acked with NO_CONSUMER_EXISTS since there is
181 // no touch-handler on it.
182 touch
.PressPoint(25, 25);
183 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
184 filter()->WaitForAck(WebInputEvent::TouchStart
);
186 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
,
187 filter()->last_ack_state());
189 // If a touch-press is acked with NO_CONSUMER_EXISTS, then subsequent
190 // touch-points don't need to be dispatched until the touch point is released.
191 touch
.ReleasePoint(0);
192 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
196 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, TouchHandlerNoConsume
) {
197 LoadURLAndAddFilter();
198 SyntheticWebTouchEvent touch
;
200 // Press on |second| should be acked with NOT_CONSUMED since there is a
201 // touch-handler on |second|, but it doesn't consume the event.
202 touch
.PressPoint(125, 25);
203 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
204 filter()->WaitForAck(WebInputEvent::TouchStart
);
205 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
207 touch
.ReleasePoint(0);
208 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
209 filter()->WaitForAck(WebInputEvent::TouchEnd
);
213 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, TouchHandlerConsume
) {
214 LoadURLAndAddFilter();
215 SyntheticWebTouchEvent touch
;
217 // Press on |third| should be acked with CONSUMED since the touch-handler on
218 // |third| consimes the event.
219 touch
.PressPoint(25, 125);
220 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
221 filter()->WaitForAck(WebInputEvent::TouchStart
);
222 EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED
, filter()->last_ack_state());
224 touch
.ReleasePoint(0);
225 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
226 filter()->WaitForAck(WebInputEvent::TouchEnd
);
229 #if defined(OS_MACOSX)
230 // TODO(ccameron): Failing on mac: crbug.com/346363
231 #define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
233 #define MAYBE_MultiPointTouchPress MultiPointTouchPress
235 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest
, MAYBE_MultiPointTouchPress
) {
236 LoadURLAndAddFilter();
237 SyntheticWebTouchEvent touch
;
239 // Press on |first|, which sould be acked with NO_CONSUMER_EXISTS. Then press
240 // on |third|. That point should be acked with CONSUMED.
241 touch
.PressPoint(25, 25);
242 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
243 filter()->WaitForAck(WebInputEvent::TouchStart
);
244 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
,
245 filter()->last_ack_state());
247 touch
.PressPoint(25, 125);
248 GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
249 filter()->WaitForAck(WebInputEvent::TouchStart
);
250 EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED
, filter()->last_ack_state());
253 } // namespace content