Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / web_contents / touch_editable_impl_aura_browsertest.cc
blob32c03ef60b1ed3a8eaad31667bf440cc01c38e77
1 // Copyright (c) 2012 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 "content/browser/web_contents/touch_editable_impl_aura.h"
7 #include "base/command_line.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/test_timeouts.h"
11 #include "base/values.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/browser/web_contents/web_contents_view_aura.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "content/public/test/content_browser_test_utils.h"
19 #include "content/public/test/test_utils.h"
20 #include "content/shell/browser/shell.h"
21 #include "third_party/WebKit/public/web/WebInputEvent.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_tree_host.h"
24 #include "ui/base/ui_base_switches.h"
25 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
26 #include "ui/events/event_utils.h"
27 #include "ui/events/test/event_generator.h"
28 #include "ui/wm/core/default_screen_position_client.h"
30 using blink::WebInputEvent;
32 namespace content {
34 class TestTouchEditableImplAura : public TouchEditableImplAura {
35 public:
36 TestTouchEditableImplAura()
37 : selection_changed_callback_arrived_(false),
38 waiting_for_selection_changed_callback_(false),
39 waiting_for_gesture_ack_type_(WebInputEvent::Undefined),
40 last_gesture_ack_type_(WebInputEvent::Undefined),
41 fling_stop_callback_arrived_(false),
42 waiting_for_fling_stop_callback_(false) {}
44 virtual void Reset() {
45 selection_changed_callback_arrived_ = false;
46 waiting_for_selection_changed_callback_ = false;
47 waiting_for_gesture_ack_type_ = WebInputEvent::Undefined;
48 last_gesture_ack_type_ = WebInputEvent::Undefined;
49 fling_stop_callback_arrived_ = false;
50 waiting_for_fling_stop_callback_ = false;
53 void OnSelectionOrCursorChanged(const ui::SelectionBound& anchor,
54 const ui::SelectionBound& focus) override {
55 selection_changed_callback_arrived_ = true;
56 TouchEditableImplAura::OnSelectionOrCursorChanged(anchor, focus);
57 if (waiting_for_selection_changed_callback_)
58 selection_changed_wait_run_loop_->Quit();
61 void GestureEventAck(int gesture_event_type) override {
62 last_gesture_ack_type_ =
63 static_cast<WebInputEvent::Type>(gesture_event_type);
64 TouchEditableImplAura::GestureEventAck(gesture_event_type);
65 if (waiting_for_gesture_ack_type_ == gesture_event_type)
66 gesture_ack_wait_run_loop_->Quit();
69 void DidStopFlinging() override {
70 fling_stop_callback_arrived_ = true;
71 TouchEditableImplAura::DidStopFlinging();
72 if (waiting_for_fling_stop_callback_)
73 fling_stop_wait_run_loop_->Quit();
76 virtual void WaitForSelectionChangeCallback() {
77 if (selection_changed_callback_arrived_)
78 return;
79 waiting_for_selection_changed_callback_ = true;
80 selection_changed_wait_run_loop_.reset(new base::RunLoop());
81 selection_changed_wait_run_loop_->Run();
84 virtual void WaitForGestureAck(WebInputEvent::Type gesture_event_type) {
85 if (last_gesture_ack_type_ == gesture_event_type)
86 return;
87 waiting_for_gesture_ack_type_ = gesture_event_type;
88 gesture_ack_wait_run_loop_.reset(new base::RunLoop());
89 gesture_ack_wait_run_loop_->Run();
92 virtual void WaitForFlingStopCallback() {
93 if (fling_stop_callback_arrived_)
94 return;
95 waiting_for_fling_stop_callback_ = true;
96 fling_stop_wait_run_loop_.reset(new base::RunLoop());
97 fling_stop_wait_run_loop_->Run();
100 protected:
101 ~TestTouchEditableImplAura() override {}
103 private:
104 bool selection_changed_callback_arrived_;
105 bool waiting_for_selection_changed_callback_;
106 WebInputEvent::Type waiting_for_gesture_ack_type_;
107 WebInputEvent::Type last_gesture_ack_type_;
108 bool fling_stop_callback_arrived_;
109 bool waiting_for_fling_stop_callback_;
110 scoped_ptr<base::RunLoop> selection_changed_wait_run_loop_;
111 scoped_ptr<base::RunLoop> gesture_ack_wait_run_loop_;
112 scoped_ptr<base::RunLoop> fling_stop_wait_run_loop_;
114 DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura);
117 class TouchEditableImplAuraTest : public ContentBrowserTest {
118 public:
119 TouchEditableImplAuraTest() {}
121 protected:
122 void SetUpOnMainThread() override {
123 ContentBrowserTest::SetUpOnMainThread();
124 aura::client::SetScreenPositionClient(shell()->window()->GetRootWindow(),
125 &screen_position_client_);
128 void SetUpCommandLine(base::CommandLine* command_line) override {
129 command_line->AppendSwitch(switches::kEnableTouchEditing);
132 // Executes the javascript synchronously and makes sure the returned value is
133 // freed properly.
134 void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) {
135 scoped_ptr<base::Value> value =
136 content::ExecuteScriptAndGetValue(rfh, jscript);
139 // Starts the test server and navigates to the given url. Sets a large enough
140 // size to the root window. Returns after the navigation to the url is
141 // complete.
142 void StartTestWithPage(const std::string& url) {
143 ASSERT_TRUE(test_server()->Start());
144 GURL test_url(test_server()->GetURL(url));
145 NavigateToURL(shell(), test_url);
146 aura::Window* content = shell()->web_contents()->GetContentNativeView();
147 content->GetHost()->SetBounds(gfx::Rect(800, 600));
150 RenderWidgetHostViewAura* GetRenderWidgetHostViewAura(
151 TouchEditableImplAura* touch_editable) {
152 return touch_editable->rwhva_;
155 ui::TouchEditingControllerDeprecated* GetTouchSelectionController(
156 TouchEditableImplAura* touch_editable) {
157 return touch_editable->touch_selection_controller_.get();
160 ui::TextInputType GetTextInputType(TouchEditableImplAura* touch_editable) {
161 return touch_editable->text_input_type_;
164 private:
165 wm::DefaultScreenPositionClient screen_position_client_;
167 DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAuraTest);
170 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
171 TouchSelectionOriginatingFromWebpageTest) {
172 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
173 WebContentsImpl* web_contents =
174 static_cast<WebContentsImpl*>(shell()->web_contents());
175 RenderFrameHost* main_frame = web_contents->GetMainFrame();
176 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
177 web_contents->GetView());
178 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
179 view_aura->SetTouchEditableForTest(touch_editable);
180 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
181 web_contents->GetRenderWidgetHostView());
182 aura::Window* content = web_contents->GetContentNativeView();
183 ui::test::EventGenerator generator(content->GetRootWindow(), content);
184 gfx::Rect bounds = content->GetBoundsInRootWindow();
186 touch_editable->Reset();
187 ExecuteSyncJSFunction(main_frame, "select_all_text()");
188 touch_editable->WaitForSelectionChangeCallback();
190 // Tap inside selection to bring up selection handles.
191 generator.GestureTapAt(gfx::Point(bounds.x() + 10, bounds.y() + 10));
192 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
194 scoped_ptr<base::Value> value =
195 content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
196 std::string selection;
197 value->GetAsString(&selection);
199 // Check if selection handles are showing.
200 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
201 EXPECT_STREQ("Some text we can select", selection.c_str());
203 // Lets move the handles a bit to modify the selection
204 touch_editable->Reset();
205 ui::SelectionBound anchor, focus;
206 touch_editable->GetSelectionEndPoints(&anchor, &focus);
207 // The distance by which a handle image is offset from the bottom of the
208 // selection/text baseline.
209 const int kSelectionHandleVerticalVisualOffset = 2;
210 int handle_grab_x = bounds.x() + anchor.edge_bottom_rounded().x();
211 int handle_grab_y = bounds.y() + anchor.edge_bottom_rounded().y() +
212 kSelectionHandleVerticalVisualOffset + 1;
213 generator.GestureScrollSequence(
214 gfx::Point(handle_grab_x, handle_grab_y),
215 gfx::Point(handle_grab_x + 20, handle_grab_y),
216 base::TimeDelta::FromMilliseconds(20),
218 touch_editable->WaitForSelectionChangeCallback();
220 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
221 value = content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
222 value->GetAsString(&selection);
224 // It is hard to tell what exactly the selection would be now. But it would
225 // definitely be less than whatever was selected before.
226 EXPECT_GT(std::strlen("Some text we can select"), selection.size());
229 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
230 TestTouchSelectionHiddenWhenScrolling) {
231 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
232 WebContentsImpl* web_contents =
233 static_cast<WebContentsImpl*>(shell()->web_contents());
234 RenderFrameHost* main_frame = web_contents->GetMainFrame();
235 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
236 web_contents->GetView());
237 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
238 view_aura->SetTouchEditableForTest(touch_editable);
239 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
240 web_contents->GetRenderWidgetHostView());
241 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
243 // Long press to select word.
244 ui::GestureEvent long_press(
248 ui::EventTimeForNow(),
249 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
250 touch_editable->Reset();
251 rwhva->OnGestureEvent(&long_press);
252 touch_editable->WaitForSelectionChangeCallback();
254 // Check if selection handles are showing.
255 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
257 scoped_ptr<base::Value> value =
258 content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
259 std::string selection;
260 value->GetAsString(&selection);
261 EXPECT_STREQ("Some", selection.c_str());
263 // Start scrolling. Handles should get hidden.
264 ui::GestureEvent scroll_begin(
268 ui::EventTimeForNow(),
269 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
270 rwhva->OnGestureEvent(&scroll_begin);
271 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
273 // Handles should come back after scroll ends.
274 ui::GestureEvent scroll_end(
278 ui::EventTimeForNow(),
279 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
280 rwhva->OnGestureEvent(&scroll_end);
281 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
284 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
285 TestTouchSelectionReshownAfterFling) {
286 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
287 WebContentsImpl* web_contents =
288 static_cast<WebContentsImpl*>(shell()->web_contents());
289 RenderFrameHost* main_frame = web_contents->GetMainFrame();
290 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
291 web_contents->GetView());
292 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
293 view_aura->SetTouchEditableForTest(touch_editable);
294 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
295 web_contents->GetRenderWidgetHostView());
296 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
298 // Long press to select word.
299 ui::GestureEvent long_press(
303 ui::EventTimeForNow(),
304 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
305 touch_editable->Reset();
306 rwhva->OnGestureEvent(&long_press);
307 touch_editable->WaitForSelectionChangeCallback();
309 // Check if selection handles are showing.
310 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
312 scoped_ptr<base::Value> value =
313 content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
314 std::string selection;
315 value->GetAsString(&selection);
316 EXPECT_STREQ("Some", selection.c_str());
318 // Start scrolling. Handles should get hidden.
319 ui::GestureEvent scroll_begin(
323 ui::EventTimeForNow(),
324 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
325 rwhva->OnGestureEvent(&scroll_begin);
326 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
328 // Start a fling. Handles should come back after fling stops.
329 ui::GestureEvent fling_start(
333 ui::EventTimeForNow(),
334 ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 1, 0));
335 rwhva->OnGestureEvent(&fling_start);
336 touch_editable->WaitForFlingStopCallback();
337 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
340 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
341 TestTouchSelectionWhenOverscrolling) {
342 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
343 WebContentsImpl* web_contents =
344 static_cast<WebContentsImpl*>(shell()->web_contents());
345 RenderFrameHost* main_frame = web_contents->GetMainFrame();
346 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
347 web_contents->GetView());
348 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
349 view_aura->SetTouchEditableForTest(touch_editable);
350 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
351 web_contents->GetRenderWidgetHostView());
352 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
354 // Long press to select word.
355 ui::GestureEvent long_press(
359 ui::EventTimeForNow(),
360 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
361 touch_editable->Reset();
362 rwhva->OnGestureEvent(&long_press);
363 touch_editable->WaitForSelectionChangeCallback();
365 // Check if selection handles are showing.
366 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
368 scoped_ptr<base::Value> value =
369 content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
370 std::string selection;
371 value->GetAsString(&selection);
372 EXPECT_STREQ("Some", selection.c_str());
374 // Overscroll is preceded with a scroll. Handles should get hidden.
375 ui::GestureEvent scroll_begin(
379 ui::EventTimeForNow(),
380 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
381 rwhva->OnGestureEvent(&scroll_begin);
382 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
384 // Then overscroll itself starts. Handles should remain hidden.
385 touch_editable->OverscrollStarted();
386 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
388 // We might have multiple overscroll-starts in one overscroll session. Handles
389 // should still remain hidden.
390 touch_editable->OverscrollStarted();
391 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
393 // An overscroll session ends with a single overscroll-complete. Handles
394 // should still remain hidden as the scroll is still in progress.
395 touch_editable->OverscrollCompleted();
396 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
398 // And, finally an scroll-end. Handles should come back.
399 ui::GestureEvent scroll_end(
403 ui::EventTimeForNow(),
404 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
405 rwhva->OnGestureEvent(&scroll_end);
406 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
409 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
410 TouchSelectionOnLongPressTest) {
411 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
412 WebContentsImpl* web_contents =
413 static_cast<WebContentsImpl*>(shell()->web_contents());
414 RenderFrameHost* main_frame = web_contents->GetMainFrame();
415 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
416 web_contents->GetView());
417 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
418 view_aura->SetTouchEditableForTest(touch_editable);
419 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
420 web_contents->GetRenderWidgetHostView());
421 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
423 // Long press to select word.
424 ui::GestureEvent long_press(
428 ui::EventTimeForNow(),
429 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
430 touch_editable->Reset();
431 rwhva->OnGestureEvent(&long_press);
432 touch_editable->WaitForSelectionChangeCallback();
434 // Check if selection handles are showing.
435 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
437 scoped_ptr<base::Value> value =
438 content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
439 std::string selection;
440 value->GetAsString(&selection);
441 EXPECT_STREQ("Some", selection.c_str());
444 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
445 NoTouchSelectionOnDoubleTapTest) {
446 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
447 WebContentsImpl* web_contents =
448 static_cast<WebContentsImpl*>(shell()->web_contents());
449 RenderFrameHost* main_frame = web_contents->GetMainFrame();
450 WebContentsViewAura* view_aura =
451 static_cast<WebContentsViewAura*>(web_contents->GetView());
452 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
453 view_aura->SetTouchEditableForTest(touch_editable);
454 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
455 web_contents->GetRenderWidgetHostView());
456 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
458 // Double-tap to select word.
459 ui::GestureEventDetails details(ui::ET_GESTURE_TAP);
460 details.set_tap_count(2);
461 ui::GestureEvent double_tap(10, 10, 0, ui::EventTimeForNow(), details);
462 touch_editable->Reset();
463 rwhva->OnGestureEvent(&double_tap);
464 touch_editable->WaitForSelectionChangeCallback();
466 // Make sure touch selection handles are not showing.
467 EXPECT_FALSE(GetTouchSelectionController(touch_editable));
469 scoped_ptr<base::Value> value =
470 content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
471 std::string selection;
472 value->GetAsString(&selection);
473 EXPECT_STREQ("Some", selection.c_str());
476 #if defined(OS_CHROMEOS)
477 // http://crbug.com/396509
478 #define MAYBE_TouchCursorInTextfieldTest DISABLED_TouchCursorInTextfieldTest
479 #else
480 #define MAYBE_TouchCursorInTextfieldTest TouchCursorInTextfieldTest
481 #endif
482 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
483 MAYBE_TouchCursorInTextfieldTest) {
484 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
485 WebContentsImpl* web_contents =
486 static_cast<WebContentsImpl*>(shell()->web_contents());
487 RenderFrameHost* main_frame = web_contents->GetMainFrame();
488 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
489 web_contents->GetView());
490 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
491 view_aura->SetTouchEditableForTest(touch_editable);
492 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
493 web_contents->GetRenderWidgetHostView());
494 aura::Window* content = web_contents->GetContentNativeView();
495 ui::test::EventGenerator generator(content->GetRootWindow(), content);
496 gfx::Rect bounds = content->GetBoundsInRootWindow();
497 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
499 ExecuteSyncJSFunction(main_frame, "focus_textfield()");
500 touch_editable->WaitForSelectionChangeCallback();
502 // Tap textfield
503 touch_editable->Reset();
504 generator.GestureTapAt(gfx::Point(bounds.x() + 50, bounds.y() + 40));
505 // Tap Down acks are sent synchronously, while Tap acks are asynchronous.
506 touch_editable->WaitForGestureAck(WebInputEvent::GestureTap);
507 touch_editable->WaitForSelectionChangeCallback();
508 touch_editable->Reset();
510 // Check if cursor handle is showing.
511 EXPECT_NE(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType(touch_editable));
512 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
514 scoped_ptr<base::Value> value =
515 content::ExecuteScriptAndGetValue(main_frame, "get_cursor_position()");
516 int cursor_pos = -1;
517 value->GetAsInteger(&cursor_pos);
518 EXPECT_NE(-1, cursor_pos);
520 // Move the cursor handle.
521 generator.GestureScrollSequence(
522 gfx::Point(50, 59),
523 gfx::Point(10, 59),
524 base::TimeDelta::FromMilliseconds(20),
526 touch_editable->WaitForSelectionChangeCallback();
527 EXPECT_TRUE(GetTouchSelectionController(touch_editable));
528 value = content::ExecuteScriptAndGetValue(main_frame,
529 "get_cursor_position()");
530 int new_cursor_pos = -1;
531 value->GetAsInteger(&new_cursor_pos);
532 EXPECT_NE(-1, new_cursor_pos);
533 // Cursor should have moved.
534 EXPECT_NE(new_cursor_pos, cursor_pos);
537 } // namespace content