OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/browser/web_contents/touch_editable_impl_aura.h" | |
6 | |
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" | |
29 | |
30 using blink::WebInputEvent; | |
31 | |
32 namespace content { | |
33 | |
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) {} | |
43 | |
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; | |
51 } | |
52 | |
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(); | |
59 } | |
60 | |
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(); | |
67 } | |
68 | |
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(); | |
74 } | |
75 | |
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(); | |
82 } | |
83 | |
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(); | |
90 } | |
91 | |
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(); | |
98 } | |
99 | |
100 protected: | |
101 ~TestTouchEditableImplAura() override {} | |
102 | |
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_; | |
113 | |
114 DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura); | |
115 }; | |
116 | |
117 class TouchEditableImplAuraTest : public ContentBrowserTest { | |
118 public: | |
119 TouchEditableImplAuraTest() {} | |
120 | |
121 protected: | |
122 void SetUpOnMainThread() override { | |
123 ContentBrowserTest::SetUpOnMainThread(); | |
124 aura::client::SetScreenPositionClient(shell()->window()->GetRootWindow(), | |
125 &screen_position_client_); | |
126 } | |
127 | |
128 void SetUpCommandLine(base::CommandLine* command_line) override { | |
129 command_line->AppendSwitch(switches::kEnableTouchEditing); | |
130 } | |
131 | |
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); | |
137 } | |
138 | |
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)); | |
148 } | |
149 | |
150 RenderWidgetHostViewAura* GetRenderWidgetHostViewAura( | |
151 TouchEditableImplAura* touch_editable) { | |
152 return touch_editable->rwhva_; | |
153 } | |
154 | |
155 ui::TouchEditingControllerDeprecated* GetTouchSelectionController( | |
156 TouchEditableImplAura* touch_editable) { | |
157 return touch_editable->touch_selection_controller_.get(); | |
158 } | |
159 | |
160 ui::TextInputType GetTextInputType(TouchEditableImplAura* touch_editable) { | |
161 return touch_editable->text_input_type_; | |
162 } | |
163 | |
164 private: | |
165 wm::DefaultScreenPositionClient screen_position_client_; | |
166 | |
167 DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAuraTest); | |
168 }; | |
169 | |
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(); | |
185 | |
186 touch_editable->Reset(); | |
187 ExecuteSyncJSFunction(main_frame, "select_all_text()"); | |
188 touch_editable->WaitForSelectionChangeCallback(); | |
189 | |
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); | |
193 | |
194 scoped_ptr<base::Value> value = | |
195 content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); | |
196 std::string selection; | |
197 value->GetAsString(&selection); | |
198 | |
199 // Check if selection handles are showing. | |
200 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
201 EXPECT_STREQ("Some text we can select", selection.c_str()); | |
202 | |
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), | |
217 5); | |
218 touch_editable->WaitForSelectionChangeCallback(); | |
219 | |
220 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
221 value = content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); | |
222 value->GetAsString(&selection); | |
223 | |
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()); | |
227 } | |
228 | |
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); | |
242 | |
243 // Long press to select word. | |
244 ui::GestureEvent long_press( | |
245 10, | |
246 10, | |
247 0, | |
248 ui::EventTimeForNow(), | |
249 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
250 touch_editable->Reset(); | |
251 rwhva->OnGestureEvent(&long_press); | |
252 touch_editable->WaitForSelectionChangeCallback(); | |
253 | |
254 // Check if selection handles are showing. | |
255 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
256 | |
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()); | |
262 | |
263 // Start scrolling. Handles should get hidden. | |
264 ui::GestureEvent scroll_begin( | |
265 10, | |
266 10, | |
267 0, | |
268 ui::EventTimeForNow(), | |
269 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); | |
270 rwhva->OnGestureEvent(&scroll_begin); | |
271 EXPECT_FALSE(GetTouchSelectionController(touch_editable)); | |
272 | |
273 // Handles should come back after scroll ends. | |
274 ui::GestureEvent scroll_end( | |
275 10, | |
276 10, | |
277 0, | |
278 ui::EventTimeForNow(), | |
279 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); | |
280 rwhva->OnGestureEvent(&scroll_end); | |
281 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
282 } | |
283 | |
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); | |
297 | |
298 // Long press to select word. | |
299 ui::GestureEvent long_press( | |
300 10, | |
301 10, | |
302 0, | |
303 ui::EventTimeForNow(), | |
304 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
305 touch_editable->Reset(); | |
306 rwhva->OnGestureEvent(&long_press); | |
307 touch_editable->WaitForSelectionChangeCallback(); | |
308 | |
309 // Check if selection handles are showing. | |
310 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
311 | |
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()); | |
317 | |
318 // Start scrolling. Handles should get hidden. | |
319 ui::GestureEvent scroll_begin( | |
320 10, | |
321 10, | |
322 0, | |
323 ui::EventTimeForNow(), | |
324 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0)); | |
325 rwhva->OnGestureEvent(&scroll_begin); | |
326 EXPECT_FALSE(GetTouchSelectionController(touch_editable)); | |
327 | |
328 // Start a fling. Handles should come back after fling stops. | |
329 ui::GestureEvent fling_start( | |
330 10, | |
331 10, | |
332 0, | |
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)); | |
338 } | |
339 | |
340 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, | |
341 TouchSelectionOnLongPressTest) { | |
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); | |
353 | |
354 // Long press to select word. | |
355 ui::GestureEvent long_press( | |
356 10, | |
357 10, | |
358 0, | |
359 ui::EventTimeForNow(), | |
360 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
361 touch_editable->Reset(); | |
362 rwhva->OnGestureEvent(&long_press); | |
363 touch_editable->WaitForSelectionChangeCallback(); | |
364 | |
365 // Check if selection handles are showing. | |
366 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
367 | |
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()); | |
373 } | |
374 | |
375 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, | |
376 NoTouchSelectionOnDoubleTapTest) { | |
377 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
378 WebContentsImpl* web_contents = | |
379 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
380 RenderFrameHost* main_frame = web_contents->GetMainFrame(); | |
381 WebContentsViewAura* view_aura = | |
382 static_cast<WebContentsViewAura*>(web_contents->GetView()); | |
383 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura; | |
384 view_aura->SetTouchEditableForTest(touch_editable); | |
385 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
386 web_contents->GetRenderWidgetHostView()); | |
387 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); | |
388 | |
389 // Double-tap to select word. | |
390 ui::GestureEventDetails details(ui::ET_GESTURE_TAP); | |
391 details.set_tap_count(2); | |
392 ui::GestureEvent double_tap(10, 10, 0, ui::EventTimeForNow(), details); | |
393 touch_editable->Reset(); | |
394 rwhva->OnGestureEvent(&double_tap); | |
395 touch_editable->WaitForSelectionChangeCallback(); | |
396 | |
397 // Make sure touch selection handles are not showing. | |
398 EXPECT_FALSE(GetTouchSelectionController(touch_editable)); | |
399 | |
400 scoped_ptr<base::Value> value = | |
401 content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); | |
402 std::string selection; | |
403 value->GetAsString(&selection); | |
404 EXPECT_STREQ("Some", selection.c_str()); | |
405 } | |
406 | |
407 #if defined(OS_CHROMEOS) | |
408 // http://crbug.com/396509 | |
409 #define MAYBE_TouchCursorInTextfieldTest DISABLED_TouchCursorInTextfieldTest | |
410 #else | |
411 #define MAYBE_TouchCursorInTextfieldTest TouchCursorInTextfieldTest | |
412 #endif | |
413 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, | |
414 MAYBE_TouchCursorInTextfieldTest) { | |
415 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
416 WebContentsImpl* web_contents = | |
417 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
418 RenderFrameHost* main_frame = web_contents->GetMainFrame(); | |
419 WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>( | |
420 web_contents->GetView()); | |
421 TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura; | |
422 view_aura->SetTouchEditableForTest(touch_editable); | |
423 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
424 web_contents->GetRenderWidgetHostView()); | |
425 aura::Window* content = web_contents->GetContentNativeView(); | |
426 ui::test::EventGenerator generator(content->GetRootWindow(), content); | |
427 gfx::Rect bounds = content->GetBoundsInRootWindow(); | |
428 EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); | |
429 | |
430 ExecuteSyncJSFunction(main_frame, "focus_textfield()"); | |
431 touch_editable->WaitForSelectionChangeCallback(); | |
432 | |
433 // Tap textfield | |
434 touch_editable->Reset(); | |
435 generator.GestureTapAt(gfx::Point(bounds.x() + 50, bounds.y() + 40)); | |
436 // Tap Down acks are sent synchronously, while Tap acks are asynchronous. | |
437 touch_editable->WaitForGestureAck(WebInputEvent::GestureTap); | |
438 touch_editable->WaitForSelectionChangeCallback(); | |
439 touch_editable->Reset(); | |
440 | |
441 // Check if cursor handle is showing. | |
442 EXPECT_NE(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType(touch_editable)); | |
443 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
444 | |
445 scoped_ptr<base::Value> value = | |
446 content::ExecuteScriptAndGetValue(main_frame, "get_cursor_position()"); | |
447 int cursor_pos = -1; | |
448 value->GetAsInteger(&cursor_pos); | |
449 EXPECT_NE(-1, cursor_pos); | |
450 | |
451 // Move the cursor handle. | |
452 generator.GestureScrollSequence( | |
453 gfx::Point(50, 59), | |
454 gfx::Point(10, 59), | |
455 base::TimeDelta::FromMilliseconds(20), | |
456 1); | |
457 touch_editable->WaitForSelectionChangeCallback(); | |
458 EXPECT_TRUE(GetTouchSelectionController(touch_editable)); | |
459 value = content::ExecuteScriptAndGetValue(main_frame, | |
460 "get_cursor_position()"); | |
461 int new_cursor_pos = -1; | |
462 value->GetAsInteger(&new_cursor_pos); | |
463 EXPECT_NE(-1, new_cursor_pos); | |
464 // Cursor should have moved. | |
465 EXPECT_NE(new_cursor_pos, cursor_pos); | |
466 } | |
467 | |
468 } // namespace content | |
OLD | NEW |