| OLD | NEW |
| 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/run_loop.h" | 8 #include "base/run_loop.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "chrome/browser/chrome_content_browser_client.h" | 10 #include "chrome/browser/chrome_content_browser_client.h" |
| 11 #include "chrome/browser/ui/browser.h" | 11 #include "chrome/browser/ui/browser.h" |
| 12 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 12 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 13 #include "chrome/test/base/in_process_browser_test.h" | 13 #include "chrome/test/base/in_process_browser_test.h" |
| 14 #include "chrome/test/base/interactive_test_utils.h" | 14 #include "chrome/test/base/interactive_test_utils.h" |
| 15 #include "chrome/test/base/ui_test_utils.h" | 15 #include "chrome/test/base/ui_test_utils.h" |
| 16 #include "content/public/browser/content_browser_client.h" | 16 #include "content/public/browser/content_browser_client.h" |
| 17 #include "content/public/browser/render_frame_host.h" | 17 #include "content/public/browser/render_frame_host.h" |
| 18 #include "content/public/browser/render_process_host.h" | 18 #include "content/public/browser/render_process_host.h" |
| 19 #include "content/public/browser/render_widget_host.h" | 19 #include "content/public/browser/render_widget_host.h" |
| 20 #include "content/public/browser/render_widget_host_view.h" | 20 #include "content/public/browser/render_widget_host_view.h" |
| 21 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
| 22 #include "content/public/common/content_client.h" | 22 #include "content/public/common/content_client.h" |
| 23 #include "content/public/test/browser_test_utils.h" | 23 #include "content/public/test/browser_test_utils.h" |
| 24 #include "content/public/test/content_browser_test_utils.h" | 24 #include "content/public/test/content_browser_test_utils.h" |
| 25 #include "content/public/test/test_utils.h" | 25 #include "content/public/test/test_utils.h" |
| 26 #include "content/public/test/text_input_test_utils.h" | 26 #include "content/public/test/text_input_test_utils.h" |
| 27 #include "net/dns/mock_host_resolver.h" | 27 #include "net/dns/mock_host_resolver.h" |
| 28 #include "net/test/embedded_test_server/embedded_test_server.h" | 28 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 29 #include "ui/base/clipboard/clipboard.h" |
| 29 #include "ui/base/ime/composition_underline.h" | 30 #include "ui/base/ime/composition_underline.h" |
| 30 #include "ui/base/ime/text_edit_commands.h" | 31 #include "ui/base/ime/text_edit_commands.h" |
| 31 #include "ui/base/ime/text_input_client.h" | 32 #include "ui/base/ime/text_input_client.h" |
| 32 #include "ui/base/ime/text_input_mode.h" | 33 #include "ui/base/ime/text_input_mode.h" |
| 33 #include "ui/base/ime/text_input_type.h" | 34 #include "ui/base/ime/text_input_type.h" |
| 34 #include "url/gurl.h" | 35 #include "url/gurl.h" |
| 35 | 36 |
| 36 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | 37 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 37 #include "ui/base/ime/linux/text_edit_command_auralinux.h" | 38 #include "ui/base/ime/linux/text_edit_command_auralinux.h" |
| 38 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h" | 39 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 tester()->GetTextInputType(&type) ? type : ui::TEXT_INPUT_TYPE_NONE; | 138 tester()->GetTextInputType(&type) ? type : ui::TEXT_INPUT_TYPE_NONE; |
| 138 if (expected_type_ == type) | 139 if (expected_type_ == type) |
| 139 OnSuccess(); | 140 OnSuccess(); |
| 140 } | 141 } |
| 141 | 142 |
| 142 const ui::TextInputType expected_type_; | 143 const ui::TextInputType expected_type_; |
| 143 | 144 |
| 144 DISALLOW_COPY_AND_ASSIGN(TextInputManagerTypeObserver); | 145 DISALLOW_COPY_AND_ASSIGN(TextInputManagerTypeObserver); |
| 145 }; | 146 }; |
| 146 | 147 |
| 147 // This class observes TextInputManager for the first change in TextInputState. | 148 // This class observes TextInputManager for changes in |
| 148 class TextInputManagerChangeObserver : public TextInputManagerObserverBase { | 149 // |TextInputState.selection_start|. |
| 150 class TextInputManagerCursorPositionObserver |
| 151 : public TextInputManagerObserverBase { |
| 149 public: | 152 public: |
| 150 explicit TextInputManagerChangeObserver(content::WebContents* web_contents) | 153 TextInputManagerCursorPositionObserver(content::WebContents* web_contents, |
| 151 : TextInputManagerObserverBase(web_contents) { | 154 int expected_position) |
| 152 tester()->SetUpdateTextInputStateCalledCallback(base::Bind( | 155 : TextInputManagerObserverBase(web_contents), |
| 153 &TextInputManagerChangeObserver::VerifyChange, base::Unretained(this))); | 156 expected_position_(expected_position) { |
| 157 tester()->SetUpdateTextInputStateCalledCallback( |
| 158 base::Bind(&TextInputManagerCursorPositionObserver::VerifyPosition, |
| 159 base::Unretained(this))); |
| 154 } | 160 } |
| 155 | 161 |
| 156 private: | 162 private: |
| 157 void VerifyChange() { | 163 void VerifyPosition() { |
| 158 if (tester()->IsTextInputStateChanged()) | 164 int position = |
| 165 tester()->GetTextInputCursorPosition(&position) ? position : -1; |
| 166 if (expected_position_ == position) |
| 159 OnSuccess(); | 167 OnSuccess(); |
| 160 } | 168 } |
| 161 | 169 |
| 162 DISALLOW_COPY_AND_ASSIGN(TextInputManagerChangeObserver); | 170 const int expected_position_; |
| 171 |
| 172 DISALLOW_COPY_AND_ASSIGN(TextInputManagerCursorPositionObserver); |
| 163 }; | 173 }; |
| 164 | 174 |
| 165 // This class observes |TextInputState.type| for a specific RWHV. | 175 // This class observes |TextInputState.type| for a specific RWHV. |
| 166 class ViewTextInputTypeObserver : public TextInputManagerObserverBase { | 176 class ViewTextInputTypeObserver : public TextInputManagerObserverBase { |
| 167 public: | 177 public: |
| 168 explicit ViewTextInputTypeObserver(content::WebContents* web_contents, | 178 explicit ViewTextInputTypeObserver(content::WebContents* web_contents, |
| 169 content::RenderWidgetHostView* rwhv, | 179 content::RenderWidgetHostView* rwhv, |
| 170 ui::TextInputType expected_type) | 180 ui::TextInputType expected_type) |
| 171 : TextInputManagerObserverBase(web_contents), | 181 : TextInputManagerObserverBase(web_contents), |
| 172 web_contents_(web_contents), | 182 web_contents_(web_contents), |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 const content::RenderWidgetHostView* const expected_view_; | 279 const content::RenderWidgetHostView* const expected_view_; |
| 270 const size_t expected_length_; | 280 const size_t expected_length_; |
| 271 | 281 |
| 272 DISALLOW_COPY_AND_ASSIGN(ViewTextSelectionObserver); | 282 DISALLOW_COPY_AND_ASSIGN(ViewTextSelectionObserver); |
| 273 }; | 283 }; |
| 274 | 284 |
| 275 // This class observes all the text selection updates within a WebContents. | 285 // This class observes all the text selection updates within a WebContents. |
| 276 class TextSelectionObserver : public TextInputManagerObserverBase { | 286 class TextSelectionObserver : public TextInputManagerObserverBase { |
| 277 public: | 287 public: |
| 278 explicit TextSelectionObserver(content::WebContents* web_contents) | 288 explicit TextSelectionObserver(content::WebContents* web_contents) |
| 279 : TextInputManagerObserverBase(web_contents) { | 289 : TextInputManagerObserverBase(web_contents), |
| 290 selection_changed_count_(0) { |
| 280 tester()->SetOnTextSelectionChangedCallback(base::Bind( | 291 tester()->SetOnTextSelectionChangedCallback(base::Bind( |
| 281 &TextSelectionObserver::VerifyChange, base::Unretained(this))); | 292 &TextSelectionObserver::VerifyChange, base::Unretained(this))); |
| 282 } | 293 } |
| 283 | 294 |
| 284 void WaitForSelectedText(const std::string& text) { | 295 void WaitForSelectedText(const std::string& text, |
| 285 selected_text_ = text; | 296 bool user_initiated = true) { |
| 286 Wait(); | 297 expected_text_ = text; |
| 298 expected_user_initiated_ = user_initiated; |
| 299 if (last_selected_text_.has_value() && |
| 300 last_selected_text_ == expected_text_ && |
| 301 last_user_initiated_ == expected_user_initiated_) { |
| 302 OnSuccess(); |
| 303 } else { |
| 304 Wait(); |
| 305 } |
| 287 } | 306 } |
| 288 | 307 |
| 308 int selection_changed_count() { return selection_changed_count_; } |
| 309 |
| 289 private: | 310 private: |
| 290 void VerifyChange() { | 311 void VerifyChange() { |
| 291 if (base::UTF16ToUTF8(tester()->GetUpdatedView()->GetSelectedText()) == | 312 selection_changed_count_++; |
| 292 selected_text_) { | 313 |
| 314 last_selected_text_ = |
| 315 base::UTF16ToUTF8(tester()->GetUpdatedView()->GetSelectedText()); |
| 316 EXPECT_TRUE(tester()->GetTextSelectionUserInitiatedForView( |
| 317 tester()->GetUpdatedView(), &last_user_initiated_)); |
| 318 |
| 319 // Check whether the expected values are already set. |
| 320 if (!expected_text_.has_value()) |
| 321 return; |
| 322 |
| 323 if (last_selected_text_ == expected_text_ && |
| 324 last_user_initiated_ == expected_user_initiated_) { |
| 293 OnSuccess(); | 325 OnSuccess(); |
| 294 } | 326 } |
| 295 } | 327 } |
| 296 | 328 |
| 297 std::string selected_text_; | 329 // These optional properties are also used to verify that the last and |
| 330 // expected properties are set. |
| 331 base::Optional<std::string> last_selected_text_; |
| 332 base::Optional<std::string> expected_text_; |
| 333 |
| 334 bool last_user_initiated_; |
| 335 bool expected_user_initiated_; |
| 336 |
| 337 int selection_changed_count_; |
| 298 | 338 |
| 299 DISALLOW_COPY_AND_ASSIGN(TextSelectionObserver); | 339 DISALLOW_COPY_AND_ASSIGN(TextSelectionObserver); |
| 300 }; | 340 }; |
| 301 | 341 |
| 302 // This class monitors all the changes in TextInputState and keeps a record of | 342 // This class monitors all the changes in TextInputState and keeps a record of |
| 303 // the active views. There is no waiting and the recording process is | 343 // the active views. There is no waiting and the recording process is |
| 304 // continuous. | 344 // continuous. |
| 305 class RecordActiveViewsObserver { | 345 class RecordActiveViewsObserver { |
| 306 public: | 346 public: |
| 307 explicit RecordActiveViewsObserver(content::WebContents* web_contents) | 347 explicit RecordActiveViewsObserver(content::WebContents* web_contents) |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 975 }; | 1015 }; |
| 976 | 1016 |
| 977 for (auto* frame : frames) { | 1017 for (auto* frame : frames) { |
| 978 focus_frame_and_input(frame); | 1018 focus_frame_and_input(frame); |
| 979 EXPECT_TRUE(active_contents()->IsFocusedElementEditable()); | 1019 EXPECT_TRUE(active_contents()->IsFocusedElementEditable()); |
| 980 active_contents()->ClearFocusedElement(); | 1020 active_contents()->ClearFocusedElement(); |
| 981 EXPECT_FALSE(active_contents()->IsFocusedElementEditable()); | 1021 EXPECT_FALSE(active_contents()->IsFocusedElementEditable()); |
| 982 } | 1022 } |
| 983 } | 1023 } |
| 984 | 1024 |
| 1025 // The following tests verify that the TextInputManager notifies about a |
| 1026 // text selection change event, the corresponding |user_initiated| property |
| 1027 // of TextSelection is valid, and the selection clipboard is updated |
| 1028 // according to the source of the event. |
| 1029 // See: https://crbug.com/671986 |
| 1030 |
| 1031 // Test text selection change event for non-user initiated cases |
| 1032 // (eg. JavaScript). Non-user initiated events should not update the selection |
| 1033 // clipboard. |
| 1034 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, |
| 1035 NonUserInitiatedTextSelection) { |
| 1036 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 1037 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); |
| 1038 ASSERT_TRUE(clipboard); |
| 1039 clipboard->Clear(ui::CLIPBOARD_TYPE_SELECTION); |
| 1040 #endif |
| 1041 |
| 1042 CreateIframePage("a(b, c)"); |
| 1043 std::vector<std::string> values{"node_a", "node_b", "node_c"}; |
| 1044 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}), |
| 1045 GetFrame(IndexVector{0}), |
| 1046 GetFrame(IndexVector{1})}; |
| 1047 |
| 1048 for (size_t i = 0; i < frames.size(); ++i) |
| 1049 AddInputFieldToFrame(frames[i], "text", values[i], true); |
| 1050 |
| 1051 // Test text selection from JavaScript across frames (non-user initiated). |
| 1052 for (size_t i = 0; i < frames.size(); ++i) { |
| 1053 // Trigger text selection. |
| 1054 TextSelectionObserver trigger_observer(active_contents()); |
| 1055 EXPECT_TRUE( |
| 1056 ExecuteScript(frames[i], "document.querySelector('input').select();")); |
| 1057 trigger_observer.WaitForSelectedText(values[i], false); |
| 1058 |
| 1059 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 1060 // Non-user initiated text selection should not update the selection |
| 1061 // clipboard. See: https://crbug.com/12392 |
| 1062 base::string16 result_text; |
| 1063 clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &result_text); |
| 1064 EXPECT_TRUE(result_text.empty()); |
| 1065 #endif |
| 1066 |
| 1067 // Clear text selection. |
| 1068 TextSelectionObserver clear_observer(active_contents()); |
| 1069 EXPECT_TRUE(ExecuteScript(frames[i], "document.getSelection().empty();")); |
| 1070 clear_observer.WaitForSelectedText("", false); |
| 1071 } |
| 1072 } |
| 1073 |
| 1074 // Test text selection change event for user initiated cases (eg. key press) |
| 1075 // User initiated events should update the selection clipboard where it is |
| 1076 // supported. |
| 1077 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, |
| 1078 UserInitiatedTextSelection) { |
| 1079 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 1080 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); |
| 1081 ASSERT_TRUE(clipboard); |
| 1082 clipboard->Clear(ui::CLIPBOARD_TYPE_SELECTION); |
| 1083 #endif |
| 1084 |
| 1085 CreateIframePage("a(b, c)"); |
| 1086 std::vector<std::string> values{"node_a", "node_b", "node_c"}; |
| 1087 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}), |
| 1088 GetFrame(IndexVector{0}), |
| 1089 GetFrame(IndexVector{1})}; |
| 1090 |
| 1091 for (size_t i = 0; i < frames.size(); ++i) |
| 1092 AddInputFieldToFrame(frames[i], "text", values[i], true); |
| 1093 |
| 1094 // Test text selection by user input across frames (user initiated). |
| 1095 for (size_t i = 0; i < frames.size(); ++i) { |
| 1096 // Focus on input element. |
| 1097 std::string result; |
| 1098 std::string script = |
| 1099 "function getInputField() {" |
| 1100 " return document.querySelector('input');" |
| 1101 "}" |
| 1102 "function onInputFocus(e) {" |
| 1103 " domAutomationController.setAutomationId(0);" |
| 1104 " domAutomationController.send(getInputField().value);" |
| 1105 "}" |
| 1106 "getInputField().addEventListener('focus', onInputFocus);"; |
| 1107 EXPECT_TRUE(ExecuteScript(frames[i], script)); |
| 1108 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 1109 frames[i], "window.focus(); document.querySelector('input').focus();", |
| 1110 &result)); |
| 1111 EXPECT_EQ(values[i], result); |
| 1112 EXPECT_EQ(frames[i], active_contents()->GetFocusedFrame()); |
| 1113 |
| 1114 // Press ctrl+a to select text in the input field. |
| 1115 TextSelectionObserver trigger_observer(active_contents()); |
| 1116 #if !defined(OS_MACOSX) |
| 1117 SimulateKeyPress(active_contents(), ui::DomKey::FromCharacter('A'), |
| 1118 ui::DomCode::US_A, ui::VKEY_A, true, false, false, false); |
| 1119 #else |
| 1120 // On macOS the select all shortcut (Cmd+A) is handled by the browser via |
| 1121 // keyboard accelerator. Thus we can't simulate key press on WebContents. |
| 1122 // As a workaround, call the SelectAll directly as the shortcut would do. |
| 1123 active_contents()->SelectAll(); |
| 1124 #endif |
| 1125 trigger_observer.WaitForSelectedText(values[i], true); |
| 1126 |
| 1127 #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 1128 // User initiated text selection should update the selection clipboard. |
| 1129 base::string16 result_text; |
| 1130 clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &result_text); |
| 1131 EXPECT_EQ(base::ASCIIToUTF16(values[i]), result_text); |
| 1132 #endif |
| 1133 |
| 1134 // Press down key to clear text selection. |
| 1135 TextSelectionObserver clear_observer(active_contents()); |
| 1136 SimulateKeyPress(active_contents(), ui::DomKey::ARROW_DOWN, |
| 1137 ui::DomCode::ARROW_DOWN, ui::VKEY_DOWN, false, false, |
| 1138 false, false); |
| 1139 clear_observer.WaitForSelectedText("", true); |
| 1140 } |
| 1141 } |
| 1142 |
| 1143 // This test changes focus between input fields and checks that no selection |
| 1144 // changed event was triggered when Blink tries to clear a potential text |
| 1145 // selection on the previous input field where there was no text selection. |
| 1146 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, |
| 1147 TextSelectionOnFocusChange) { |
| 1148 CreateIframePage("a(b, c)"); |
| 1149 std::vector<std::string> values{"node_a", "node_b", "node_c"}; |
| 1150 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}), |
| 1151 GetFrame(IndexVector{0}), |
| 1152 GetFrame(IndexVector{1})}; |
| 1153 |
| 1154 for (size_t i = 0; i < frames.size(); ++i) { |
| 1155 AddInputFieldToFrame(frames[i], "text", values[i], true); |
| 1156 AddInputFieldToFrame(frames[i], "number", std::to_string(i), true); |
| 1157 } |
| 1158 |
| 1159 for (size_t i = 0; i < frames.size(); ++i) { |
| 1160 std::string script = |
| 1161 "function onInputFocus(e) {" |
| 1162 " domAutomationController.setAutomationId(0);" |
| 1163 " domAutomationController.send(document.activeElement.value);" |
| 1164 "}" |
| 1165 "var text_input = document.querySelector('input[type=text]');" |
| 1166 "text_input.addEventListener('focus', onInputFocus);" |
| 1167 "var number_input = document.querySelector('input[type=number]');" |
| 1168 "number_input.addEventListener('focus', onInputFocus);"; |
| 1169 EXPECT_TRUE(ExecuteScript(frames[i], script)); |
| 1170 TextSelectionObserver selection_observer(active_contents()); |
| 1171 |
| 1172 // Focus on text input element. |
| 1173 std::string text_result; |
| 1174 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 1175 frames[i], |
| 1176 "window.focus(); document.querySelector('input[type=text]').focus();", |
| 1177 &text_result)); |
| 1178 EXPECT_EQ(values[i], text_result); |
| 1179 EXPECT_EQ(0, selection_observer.selection_changed_count()); |
| 1180 |
| 1181 // Focus on number input element. |
| 1182 std::string number_result; |
| 1183 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 1184 frames[i], |
| 1185 "window.focus(); document.querySelector('input[type=number]').focus();", |
| 1186 &number_result)); |
| 1187 EXPECT_EQ(std::to_string(i), number_result); |
| 1188 EXPECT_EQ(0, selection_observer.selection_changed_count()); |
| 1189 } |
| 1190 } |
| 1191 |
| 1192 // This test replaces text in input filed in IME composition mode. The text is |
| 1193 // replaced by using text selection during the composition mode. Verify that |
| 1194 // the text replacement doesn't trigger any selection changed event. |
| 1195 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, |
| 1196 ImeSetCompositionTextReplacement) { |
| 1197 CreateIframePage("a(b, c)"); |
| 1198 std::vector<std::string> values{"node_a", "node_b", "node_c"}; |
| 1199 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}), |
| 1200 GetFrame(IndexVector{0}), |
| 1201 GetFrame(IndexVector{1})}; |
| 1202 |
| 1203 for (size_t i = 0; i < frames.size(); ++i) |
| 1204 AddInputFieldToFrame(frames[i], "text", values[i], true); |
| 1205 |
| 1206 for (size_t i = 0; i < frames.size(); ++i) { |
| 1207 // Focus on input element. |
| 1208 EXPECT_TRUE(ExecuteScript(frames[i], |
| 1209 "window.focus();" |
| 1210 "document.querySelector('input').focus();")); |
| 1211 |
| 1212 TextSelectionObserver selection_observer(active_contents()); |
| 1213 |
| 1214 // Do text replacement in composition mode. |
| 1215 ViewCompositionRangeChangedObserver range_observer_set_composition( |
| 1216 active_contents(), frames[i]->GetView()); |
| 1217 content::SendImeSetCompositionTextToWidget( |
| 1218 frames[i]->GetView()->GetRenderWidgetHost(), |
| 1219 base::UTF8ToUTF16(values[i]), std::vector<ui::CompositionUnderline>(), |
| 1220 gfx::Range(5, 1), 0, 0); |
| 1221 range_observer_set_composition.Wait(); |
| 1222 |
| 1223 // Check composition text. |
| 1224 std::string result; |
| 1225 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 1226 frames[i], |
| 1227 "domAutomationController.setAutomationId(0);" |
| 1228 "var value = document.querySelector('input').value;" |
| 1229 "domAutomationController.send(value);", |
| 1230 &result)); |
| 1231 EXPECT_EQ("node_" + values[i], result); |
| 1232 |
| 1233 // Text selection should not be triggered by IME composition text |
| 1234 // replacement. |
| 1235 EXPECT_EQ(0, selection_observer.selection_changed_count()); |
| 1236 } |
| 1237 } |
| 1238 |
| 1239 // This test changes the cursor position in an input field from JavaScript. |
| 1240 // Verify that the cursor position |TextInputState.selection_start| always |
| 1241 // updated but non-user initiated text selection change is only triggered if |
| 1242 // an existing selection is changed. |
| 1243 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, JSCursorMovement) { |
| 1244 CreateIframePage("a(b, c)"); |
| 1245 std::vector<std::string> values{"node_a", "node_b", "node_c"}; |
| 1246 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}), |
| 1247 GetFrame(IndexVector{0}), |
| 1248 GetFrame(IndexVector{1})}; |
| 1249 |
| 1250 for (size_t i = 0; i < frames.size(); ++i) |
| 1251 AddInputFieldToFrame(frames[i], "text", values[i], true); |
| 1252 |
| 1253 for (size_t i = 0; i < frames.size(); ++i) { |
| 1254 // Focus on input element. |
| 1255 EXPECT_TRUE(ExecuteScript(frames[i], |
| 1256 "window.focus();" |
| 1257 "document.querySelector('input').focus();")); |
| 1258 |
| 1259 // No text selection, set cursor position. |
| 1260 { |
| 1261 TextSelectionObserver selection_observer(active_contents()); |
| 1262 TextInputManagerCursorPositionObserver position_observer( |
| 1263 active_contents(), 2); |
| 1264 EXPECT_TRUE(ExecuteScript( |
| 1265 frames[i], |
| 1266 "document.querySelector('input').setSelectionRange(2, 2);")); |
| 1267 position_observer.Wait(); |
| 1268 // Non-user initiated empty text selection after empty text selection |
| 1269 // should not trigger selection change. |
| 1270 EXPECT_EQ(0, selection_observer.selection_changed_count()); |
| 1271 } |
| 1272 |
| 1273 // Set text selection. |
| 1274 { |
| 1275 TextSelectionObserver selection_observer(active_contents()); |
| 1276 EXPECT_TRUE(ExecuteScript(frames[i], |
| 1277 "document.querySelector('input').select();")); |
| 1278 selection_observer.WaitForSelectedText(values[i], false); |
| 1279 EXPECT_EQ(1, selection_observer.selection_changed_count()); |
| 1280 } |
| 1281 |
| 1282 // Set cursor position and clear text selection. |
| 1283 { |
| 1284 TextSelectionObserver selection_observer(active_contents()); |
| 1285 TextInputManagerCursorPositionObserver position_observer( |
| 1286 active_contents(), 3); |
| 1287 EXPECT_TRUE(ExecuteScript( |
| 1288 frames[i], |
| 1289 "document.querySelector('input').setSelectionRange(3, 3);")); |
| 1290 position_observer.Wait(); |
| 1291 // Non-user initiated empty text selection clears an existing text |
| 1292 // selection. Notification is expected about the selection change. |
| 1293 selection_observer.WaitForSelectedText("", false); |
| 1294 EXPECT_EQ(1, selection_observer.selection_changed_count()); |
| 1295 } |
| 1296 } |
| 1297 } |
| 1298 |
| 985 // TODO(ekaramad): The following tests are specifically written for Aura and are | 1299 // TODO(ekaramad): The following tests are specifically written for Aura and are |
| 986 // based on InputMethodObserver. Write similar tests for Mac/Android/Mus | 1300 // based on InputMethodObserver. Write similar tests for Mac/Android/Mus |
| 987 // (crbug.com/602723). | 1301 // (crbug.com/602723). |
| 988 #if defined(USE_AURA) | 1302 #if defined(USE_AURA) |
| 989 // ----------------------------------------------------------------------------- | 1303 // ----------------------------------------------------------------------------- |
| 990 // Input Method Observer Tests | 1304 // Input Method Observer Tests |
| 991 // | 1305 // |
| 992 // The following tests will make use of the InputMethodObserver to verify that | 1306 // The following tests will make use of the InputMethodObserver to verify that |
| 993 // OOPIF pages interact properly with the InputMethod through the tab's view. | 1307 // OOPIF pages interact properly with the InputMethod through the tab's view. |
| 994 | 1308 |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1507 | 1821 |
| 1508 // Request for the dictionary lookup and intercept the word on its way back. | 1822 // Request for the dictionary lookup and intercept the word on its way back. |
| 1509 // The request is always on the tab's view which is a RenderWidgetHostViewMac. | 1823 // The request is always on the tab's view which is a RenderWidgetHostViewMac. |
| 1510 content::AskForLookUpDictionaryForRange(page_rwhv, gfx::Range(0, 4)); | 1824 content::AskForLookUpDictionaryForRange(page_rwhv, gfx::Range(0, 4)); |
| 1511 | 1825 |
| 1512 test_complete_waiter.Run(); | 1826 test_complete_waiter.Run(); |
| 1513 } | 1827 } |
| 1514 #endif // defined(MAC_OSX) | 1828 #endif // defined(MAC_OSX) |
| 1515 | 1829 |
| 1516 #endif // !defined(OS_ANDROID) | 1830 #endif // !defined(OS_ANDROID) |
| OLD | NEW |