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 |