Upstream version 9.38.198.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/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"
23
24 using blink::WebInputEvent;
25
26 namespace {
27
28 void GiveItSomeTime() {
29   base::RunLoop run_loop;
30   base::MessageLoop::current()->PostDelayedTask(
31       FROM_HERE,
32       run_loop.QuitClosure(),
33       base::TimeDelta::FromMilliseconds(10));
34   run_loop.Run();
35 }
36
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>"
41     "<style>"
42     "  #first {"
43     "    position: absolute;"
44     "    width: 100px;"
45     "    height: 100px;"
46     "    top: 0px;"
47     "    left: 0px;"
48     "    background-color: green;"
49     "    -webkit-transform: translate3d(0, 0, 0);"
50     "  }"
51     "  #second {"
52     "    position: absolute;"
53     "    width: 100px;"
54     "    height: 100px;"
55     "    top: 0px;"
56     "    left: 110px;"
57     "    background-color: blue;"
58     "    -webkit-transform: translate3d(0, 0, 0);"
59     "  }"
60     "  #third {"
61     "    position: absolute;"
62     "    width: 100px;"
63     "    height: 100px;"
64     "    top: 110px;"
65     "    left: 0px;"
66     "    background-color: yellow;"
67     "    -webkit-transform: translate3d(0, 0, 0);"
68     "  }"
69     "</style>"
70     "<script>"
71     "  function setup() {"
72     "    second.ontouchstart = function() {};"
73     "    third.ontouchstart = function(e) {"
74     "      e.preventDefault();"
75     "    };"
76     "  }"
77     "</script>";
78
79 }  // namespace
80
81 namespace content {
82
83 class InputEventMessageFilter : public BrowserMessageFilter {
84  public:
85   InputEventMessageFilter()
86       : BrowserMessageFilter(InputMsgStart),
87         type_(WebInputEvent::Undefined),
88         state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
89
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);
94     run_loop.Run();
95   }
96
97   InputEventAckState last_ack_state() const { return state_; }
98
99  protected:
100   virtual ~InputEventMessageFilter() {}
101
102  private:
103   void ReceivedEventAck(WebInputEvent::Type type, InputEventAckState state) {
104     if (type_ == type) {
105       state_ = state;
106       quit_.Run();
107     }
108   }
109
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, &params);
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,
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:
133   TouchInputBrowserTest() {}
134   virtual ~TouchInputBrowserTest() {}
135
136   RenderWidgetHostImpl* GetWidgetHost() {
137     return RenderWidgetHostImpl::From(shell()->web_contents()->
138                                           GetRenderViewHost());
139   }
140
141   InputEventMessageFilter* filter() { return filter_.get(); }
142
143  protected:
144   void LoadURLAndAddFilter() {
145     const GURL data_url(kTouchEventDataURL);
146     NavigateToURL(shell(), data_url);
147
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));
153
154     // The page is loaded in the renderer, wait for a new frame to arrive.
155     while (!host->ScheduleComposite())
156       GiveItSomeTime();
157
158     filter_ = new InputEventMessageFilter();
159     host->GetProcess()->AddFilter(filter_);
160   }
161
162   virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
163     cmd->AppendSwitchASCII(switches::kTouchEvents,
164                            switches::kTouchEventsEnabled);
165   }
166
167   scoped_refptr<InputEventMessageFilter> filter_;
168 };
169
170 #if defined(OS_MACOSX)
171 // TODO(ccameron): Failing on mac: crbug.com/346363
172 #define MAYBE_TouchNoHandler DISABLED_TouchNoHandler
173 #else
174 #define MAYBE_TouchNoHandler TouchNoHandler
175 #endif
176 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
177   LoadURLAndAddFilter();
178   SyntheticWebTouchEvent touch;
179
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);
185
186   EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
187             filter()->last_ack_state());
188
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());
193   touch.ResetPoints();
194 }
195
196 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, TouchHandlerNoConsume) {
197   LoadURLAndAddFilter();
198   SyntheticWebTouchEvent touch;
199
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());
206
207   touch.ReleasePoint(0);
208   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
209   filter()->WaitForAck(WebInputEvent::TouchEnd);
210   touch.ResetPoints();
211 }
212
213 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, TouchHandlerConsume) {
214   LoadURLAndAddFilter();
215   SyntheticWebTouchEvent touch;
216
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());
223
224   touch.ReleasePoint(0);
225   GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
226   filter()->WaitForAck(WebInputEvent::TouchEnd);
227 }
228
229 #if defined(OS_MACOSX)
230 // TODO(ccameron): Failing on mac: crbug.com/346363
231 #define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
232 #else
233 #define MAYBE_MultiPointTouchPress MultiPointTouchPress
234 #endif
235 IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_MultiPointTouchPress) {
236   LoadURLAndAddFilter();
237   SyntheticWebTouchEvent touch;
238
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());
246
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());
251 }
252
253 }  // namespace content