Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(902)

Side by Side Diff: chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc

Issue 2856093003: Update TextSelection for non-user initiated events (Closed)
Patch Set: Update TextSelection for non-user initiated events Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « AUTHORS ('k') | content/browser/frame_host/render_frame_host_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <vector> 5 #include <vector>
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/chrome_content_browser_client.h" 9 #include "chrome/browser/chrome_content_browser_client.h"
10 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h" 11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/test/base/in_process_browser_test.h" 12 #include "chrome/test/base/in_process_browser_test.h"
13 #include "chrome/test/base/interactive_test_utils.h" 13 #include "chrome/test/base/interactive_test_utils.h"
14 #include "chrome/test/base/ui_test_utils.h" 14 #include "chrome/test/base/ui_test_utils.h"
15 #include "content/public/browser/content_browser_client.h" 15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/browser/render_frame_host.h" 16 #include "content/public/browser/render_frame_host.h"
17 #include "content/public/browser/render_process_host.h" 17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_widget_host_view.h" 18 #include "content/public/browser/render_widget_host_view.h"
19 #include "content/public/browser/web_contents.h" 19 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/content_client.h" 20 #include "content/public/common/content_client.h"
21 #include "content/public/test/browser_test_utils.h" 21 #include "content/public/test/browser_test_utils.h"
22 #include "content/public/test/content_browser_test_utils.h" 22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/public/test/test_utils.h" 23 #include "content/public/test/test_utils.h"
24 #include "content/public/test/text_input_test_utils.h" 24 #include "content/public/test/text_input_test_utils.h"
25 #include "net/dns/mock_host_resolver.h" 25 #include "net/dns/mock_host_resolver.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h" 26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "ui/base/clipboard/clipboard.h"
27 #include "ui/base/ime/composition_underline.h" 28 #include "ui/base/ime/composition_underline.h"
28 #include "ui/base/ime/text_edit_commands.h" 29 #include "ui/base/ime/text_edit_commands.h"
29 #include "ui/base/ime/text_input_client.h" 30 #include "ui/base/ime/text_input_client.h"
30 #include "ui/base/ime/text_input_mode.h" 31 #include "ui/base/ime/text_input_mode.h"
31 #include "ui/base/ime/text_input_type.h" 32 #include "ui/base/ime/text_input_type.h"
33 #include "ui/base/test/ui_controls.h"
32 #include "url/gurl.h" 34 #include "url/gurl.h"
33 35
34 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) 36 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
35 #include "ui/base/ime/linux/text_edit_command_auralinux.h" 37 #include "ui/base/ime/linux/text_edit_command_auralinux.h"
36 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h" 38 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
37 #endif 39 #endif
38 40
39 /////////////////////////////////////////////////////////////////////////////// 41 ///////////////////////////////////////////////////////////////////////////////
40 // TextInputManager and IME Tests 42 // TextInputManager and IME Tests
41 // 43 //
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 const content::RenderWidgetHostView* const expected_view_; 269 const content::RenderWidgetHostView* const expected_view_;
268 const size_t expected_length_; 270 const size_t expected_length_;
269 271
270 DISALLOW_COPY_AND_ASSIGN(ViewTextSelectionObserver); 272 DISALLOW_COPY_AND_ASSIGN(ViewTextSelectionObserver);
271 }; 273 };
272 274
273 // This class observes all the text selection updates within a WebContents. 275 // This class observes all the text selection updates within a WebContents.
274 class TextSelectionObserver : public TextInputManagerObserverBase { 276 class TextSelectionObserver : public TextInputManagerObserverBase {
275 public: 277 public:
276 explicit TextSelectionObserver(content::WebContents* web_contents) 278 explicit TextSelectionObserver(content::WebContents* web_contents)
277 : TextInputManagerObserverBase(web_contents) { 279 : TextInputManagerObserverBase(web_contents), callback_called_(false) {
278 tester()->SetOnTextSelectionChangedCallback(base::Bind( 280 tester()->SetOnTextSelectionChangedCallback(base::Bind(
279 &TextSelectionObserver::VerifyChange, base::Unretained(this))); 281 &TextSelectionObserver::VerifyChange, base::Unretained(this)));
280 } 282 }
281 283
282 void WaitForSelectedText(const std::string& text) { 284 void WaitForSelectedText(const std::string& text,
283 selected_text_ = text; 285 bool user_initiated = true) {
284 Wait(); 286 expected_text_ = text;
287 expected_user_initiated_ = user_initiated;
288 if (callback_called_ && last_selected_text_ == expected_text_ &&
289 last_user_initiated_ == expected_user_initiated_) {
290 OnSuccess();
291 } else {
292 Wait();
293 }
285 } 294 }
286 295
287 private: 296 private:
288 void VerifyChange() { 297 void VerifyChange() {
289 if (base::UTF16ToUTF8(tester()->GetUpdatedView()->GetSelectedText()) == 298 callback_called_ = true;
290 selected_text_) { 299
300 last_selected_text_ =
301 base::UTF16ToUTF8(tester()->GetUpdatedView()->GetSelectedText());
302 EXPECT_TRUE(tester()->GetTextSelectionUserInitiatedForView(
303 tester()->GetUpdatedView(), &last_user_initiated_));
304
305 if (last_selected_text_ == expected_text_ &&
306 last_user_initiated_ == expected_user_initiated_) {
291 OnSuccess(); 307 OnSuccess();
292 } 308 }
293 } 309 }
294 310
295 std::string selected_text_; 311 bool callback_called_;
312
313 std::string last_selected_text_;
314 std::string expected_text_;
315 bool last_user_initiated_;
316 bool expected_user_initiated_;
296 317
297 DISALLOW_COPY_AND_ASSIGN(TextSelectionObserver); 318 DISALLOW_COPY_AND_ASSIGN(TextSelectionObserver);
298 }; 319 };
299 320
300 // This class monitors all the changes in TextInputState and keeps a record of 321 // This class monitors all the changes in TextInputState and keeps a record of
301 // the active views. There is no waiting and the recording process is 322 // the active views. There is no waiting and the recording process is
302 // continuous. 323 // continuous.
303 class RecordActiveViewsObserver { 324 class RecordActiveViewsObserver {
304 public: 325 public:
305 explicit RecordActiveViewsObserver(content::WebContents* web_contents) 326 explicit RecordActiveViewsObserver(content::WebContents* web_contents)
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 // Iteratively uses ChildFrameAt(frame, i) to get the i-th child frame 434 // Iteratively uses ChildFrameAt(frame, i) to get the i-th child frame
414 // inside frame. For example, for 'a(b(c, d(e)))', [0] returns b, and 435 // inside frame. For example, for 'a(b(c, d(e)))', [0] returns b, and
415 // [0, 1, 0] returns e; 436 // [0, 1, 0] returns e;
416 content::RenderFrameHost* GetFrame(const IndexVector& indices) { 437 content::RenderFrameHost* GetFrame(const IndexVector& indices) {
417 content::RenderFrameHost* current = active_contents()->GetMainFrame(); 438 content::RenderFrameHost* current = active_contents()->GetMainFrame();
418 for (size_t index : indices) 439 for (size_t index : indices)
419 current = ChildFrameAt(current, index); 440 current = ChildFrameAt(current, index);
420 return current; 441 return current;
421 } 442 }
422 443
444 // Simulates a click on the middle of the first DOM element
445 // with the given |selector| in the given frame |rfh|. The |frame_index|
446 // parameter is used to find the child frame in the main frame and
447 // use its offset to calculate the click position.
448 void ClickFirstElementWithSelector(content::RenderFrameHost* rfh,
449 int frame_index,
450 const std::string& selector) {
451 int frame_x = 0;
452 int frame_y = 0;
453
454 if (rfh != active_contents()->GetMainFrame()) {
455 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
456 active_contents()->GetMainFrame(),
457 "var frames = document.querySelectorAll('iframe');"
458 "var frame = frames[" +
459 std::to_string(frame_index) +
460 "];"
461 "domAutomationController.send(Math.floor(frame.offsetLeft));",
462 &frame_x));
463 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
464 active_contents()->GetMainFrame(),
465 "var frames = document.querySelectorAll('iframe');"
466 "var frame = frames[" +
467 std::to_string(frame_index) +
468 "];"
469 "domAutomationController.send(Math.floor(frame.offsetTop));",
470 &frame_y));
471 }
472
473 int x;
474 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
475 rfh,
476 "var bounds = document.querySelector('" + selector +
477 "').getBoundingClientRect();"
478 "domAutomationController.send("
479 " Math.floor(bounds.left + bounds.width / 2));",
480 &x));
481 int y;
482 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
483 rfh,
484 "var bounds = document.querySelector('" + selector +
485 "').getBoundingClientRect();"
486 "domAutomationController.send("
487 " Math.floor(bounds.top + bounds.height / 2));",
488 &y));
489
490 auto content_bounds = active_contents()->GetContainerBounds();
491 ui_controls::SendMouseMove(x + frame_x + content_bounds.x(),
492 y + frame_y + content_bounds.y());
493 ui_controls::SendMouseClick(ui_controls::LEFT);
494 }
495
423 private: 496 private:
424 DISALLOW_COPY_AND_ASSIGN(SitePerProcessTextInputManagerTest); 497 DISALLOW_COPY_AND_ASSIGN(SitePerProcessTextInputManagerTest);
425 }; 498 };
426 499
427 // The following test loads a page with multiple nested <iframe> elements which 500 // The following test loads a page with multiple nested <iframe> elements which
428 // are in or out of process with the main frame. Then an <input> field with 501 // are in or out of process with the main frame. Then an <input> field with
429 // unique value is added to every single frame on the frame tree. The test then 502 // unique value is added to every single frame on the frame tree. The test then
430 // creates a sequence of tab presses and verifies that after each key press, the 503 // creates a sequence of tab presses and verifies that after each key press, the
431 // TextInputState.value reflects that of the focused input, i.e., the 504 // TextInputState.value reflects that of the focused input, i.e., the
432 // TextInputManager is correctly tracking TextInputState across frames. 505 // TextInputManager is correctly tracking TextInputState across frames.
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 }; 1046 };
974 1047
975 for (auto* frame : frames) { 1048 for (auto* frame : frames) {
976 focus_frame_and_input(frame); 1049 focus_frame_and_input(frame);
977 EXPECT_TRUE(active_contents()->IsFocusedElementEditable()); 1050 EXPECT_TRUE(active_contents()->IsFocusedElementEditable());
978 active_contents()->ClearFocusedElement(); 1051 active_contents()->ClearFocusedElement();
979 EXPECT_FALSE(active_contents()->IsFocusedElementEditable()); 1052 EXPECT_FALSE(active_contents()->IsFocusedElementEditable());
980 } 1053 }
981 } 1054 }
982 1055
1056 // This test verifies that the TextInputManager notifies about a
1057 // text selection change event for both user and non-user (eg. JavaScript)
1058 // initiated cases. It is also tested whether TextSelection::user_initiated
1059 // is properly set. The content of the selection clipboard is also tested on
1060 // platforms where it is supported.
1061 // See: https://crbug.com/671986
1062 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
1063 NonUserInitiatedTextSelection) {
1064 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
1065 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1066 EXPECT_TRUE(!!clipboard);
Lei Zhang 2017/05/10 21:06:03 ASSERT_TRUE() because if this fails, the test exec
Peter Varga 2017/05/10 21:12:36 I copied this from another clipboard test. I will
1067 clipboard->Clear(ui::CLIPBOARD_TYPE_SELECTION);
1068 #endif
1069
1070 CreateIframePage("a(b, c)");
1071 std::vector<std::string> values{"node_a", "node_b", "node_c"};
1072 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}),
1073 GetFrame(IndexVector{0}),
1074 GetFrame(IndexVector{1})};
1075
1076 for (size_t i = 0; i < frames.size(); ++i)
1077 AddInputFieldToFrame(frames[i], "text", values[i], true);
1078
1079 // Test text selection from JavaScript across frames (non-user initiated).
1080 for (size_t i = 0; i < frames.size(); ++i) {
1081 // Trigger text selection.
1082 TextSelectionObserver trigger_observer(active_contents());
1083 EXPECT_TRUE(
1084 ExecuteScript(frames[i], "document.querySelector('input').select();"));
1085 trigger_observer.WaitForSelectedText(values[i], false);
1086
1087 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
1088 // Non-user initiated text selection should not update the selection
1089 // clipboard. See: https://crbug.com/12392
1090 base::string16 result_text;
1091 clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &result_text);
1092 EXPECT_TRUE(result_text.empty());
1093 #endif
1094
1095 // Clear text selection.
1096 TextSelectionObserver clear_observer(active_contents());
1097 EXPECT_TRUE(ExecuteScript(frames[i], "document.getSelection().empty();"));
1098 clear_observer.WaitForSelectedText("", false);
1099 }
1100
1101 // Test text selection by user input across frames (user initiated).
1102 for (size_t i = 0; i < frames.size(); ++i) {
1103 // Click on element to have keyboard focus.
1104 TextInputManagerChangeObserver input_observer(active_contents());
1105 // Index of the main frame is 0. Thus align child frame index to it (i-1).
1106 ASSERT_NO_FATAL_FAILURE(
1107 ClickFirstElementWithSelector(frames[i], i - 1, "input"));
1108 input_observer.Wait();
1109
1110 // Press ctrl+a to select text in the input field.
1111 TextSelectionObserver trigger_observer(active_contents());
1112 SimulateKeyPress(active_contents(), ui::DomKey::FromCharacter('A'),
1113 ui::DomCode::US_A, ui::VKEY_A, true, false, false, false);
1114 trigger_observer.WaitForSelectedText(values[i], true);
1115
1116 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
1117 // User initiated text selection should update the selection clipboard.
1118 base::string16 result_text;
1119 clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &result_text);
1120 EXPECT_EQ(base::ASCIIToUTF16(values[i]), result_text);
1121 #endif
1122
1123 // Click on element to clear text selection.
1124 TextSelectionObserver clear_observer(active_contents());
1125 // Index of the main frame is 0. Thus align child frame index to it (i-1).
1126 ASSERT_NO_FATAL_FAILURE(
1127 ClickFirstElementWithSelector(frames[i], i - 1, "input"));
1128 clear_observer.WaitForSelectedText("", true);
1129 }
1130 }
1131
983 // TODO(ekaramad): The following tests are specifically written for Aura and are 1132 // TODO(ekaramad): The following tests are specifically written for Aura and are
984 // based on InputMethodObserver. Write similar tests for Mac/Android/Mus 1133 // based on InputMethodObserver. Write similar tests for Mac/Android/Mus
985 // (crbug.com/602723). 1134 // (crbug.com/602723).
986 #if defined(USE_AURA) 1135 #if defined(USE_AURA)
987 // ----------------------------------------------------------------------------- 1136 // -----------------------------------------------------------------------------
988 // Input Method Observer Tests 1137 // Input Method Observer Tests
989 // 1138 //
990 // The following tests will make use of the InputMethodObserver to verify that 1139 // The following tests will make use of the InputMethodObserver to verify that
991 // OOPIF pages interact properly with the InputMethod through the tab's view. 1140 // OOPIF pages interact properly with the InputMethod through the tab's view.
992 1141
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
1367 1516
1368 // Closing this WebContents while we still hold on to our TestBrowserClient. 1517 // Closing this WebContents while we still hold on to our TestBrowserClient.
1369 EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt( 1518 EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
1370 1, TabStripModel::CLOSE_USER_GESTURE)); 1519 1, TabStripModel::CLOSE_USER_GESTURE));
1371 1520
1372 // For the cleanup of the original WebContents in tab index 0. 1521 // For the cleanup of the original WebContents in tab index 0.
1373 content::SetBrowserClientForTesting(old_browser_client); 1522 content::SetBrowserClientForTesting(old_browser_client);
1374 } 1523 }
1375 #endif // defined(MAC_OSX) 1524 #endif // defined(MAC_OSX)
1376 #endif // !defined(OS_ANDROID) 1525 #endif // !defined(OS_ANDROID)
OLDNEW
« no previous file with comments | « AUTHORS ('k') | content/browser/frame_host/render_frame_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698