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/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/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
10 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
11 #include "chrome/test/base/in_process_browser_test.h" | 12 #include "chrome/test/base/in_process_browser_test.h" |
12 #include "chrome/test/base/interactive_test_utils.h" | 13 #include "chrome/test/base/interactive_test_utils.h" |
13 #include "chrome/test/base/ui_test_utils.h" | 14 #include "chrome/test/base/ui_test_utils.h" |
15 #include "content/public/browser/browser_message_filter.h" | |
16 #include "content/public/browser/content_browser_client.h" | |
14 #include "content/public/browser/render_frame_host.h" | 17 #include "content/public/browser/render_frame_host.h" |
15 #include "content/public/browser/render_process_host.h" | 18 #include "content/public/browser/render_process_host.h" |
16 #include "content/public/browser/render_widget_host_view.h" | 19 #include "content/public/browser/render_widget_host_view.h" |
17 #include "content/public/browser/web_contents.h" | 20 #include "content/public/browser/web_contents.h" |
21 #include "content/public/common/content_client.h" | |
18 #include "content/public/test/browser_test_utils.h" | 22 #include "content/public/test/browser_test_utils.h" |
19 #include "content/public/test/content_browser_test_utils.h" | 23 #include "content/public/test/content_browser_test_utils.h" |
20 #include "content/public/test/test_utils.h" | 24 #include "content/public/test/test_utils.h" |
21 #include "content/public/test/text_input_test_utils.h" | 25 #include "content/public/test/text_input_test_utils.h" |
22 #include "net/dns/mock_host_resolver.h" | 26 #include "net/dns/mock_host_resolver.h" |
23 #include "net/test/embedded_test_server/embedded_test_server.h" | 27 #include "net/test/embedded_test_server/embedded_test_server.h" |
24 #include "ui/base/ime/composition_underline.h" | 28 #include "ui/base/ime/composition_underline.h" |
25 #include "ui/base/ime/text_edit_commands.h" | 29 #include "ui/base/ime/text_edit_commands.h" |
26 #include "ui/base/ime/text_input_client.h" | 30 #include "ui/base/ime/text_input_client.h" |
27 #include "ui/base/ime/text_input_mode.h" | 31 #include "ui/base/ime/text_input_mode.h" |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 } | 327 } |
324 | 328 |
325 protected: | 329 protected: |
326 content::WebContents* active_contents() { | 330 content::WebContents* active_contents() { |
327 return browser()->tab_strip_model()->GetActiveWebContents(); | 331 return browser()->tab_strip_model()->GetActiveWebContents(); |
328 } | 332 } |
329 | 333 |
330 // static | 334 // static |
331 // Adds an <input> field to a given frame by executing javascript code. | 335 // Adds an <input> field to a given frame by executing javascript code. |
332 // The input can be added as the first element or the last element of | 336 // The input can be added as the first element or the last element of |
333 // |document.body|. | 337 // |document.body|. The text range defined by |selection_range| will be |
338 // marked. | |
334 static void AddInputFieldToFrame(content::RenderFrameHost* rfh, | 339 static void AddInputFieldToFrame(content::RenderFrameHost* rfh, |
335 const std::string& type, | 340 const std::string& type, |
336 const std::string& value, | 341 const std::string& value, |
337 bool append_as_first_child) { | 342 bool append_as_first_child) { |
338 std::string script = base::StringPrintf( | 343 std::string script = base::StringPrintf( |
339 "var input = document.createElement('input');" | 344 "var input = document.createElement('input');" |
340 "input.setAttribute('type', '%s');" | 345 "input.setAttribute('type', '%s');" |
341 "input.setAttribute('value', '%s');" | 346 "input.setAttribute('value', '%s');" |
342 "document.body.%s;", | 347 "document.body.%s;", |
343 type.c_str(), value.c_str(), | 348 type.c_str(), value.c_str(), |
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
941 true, true, true, false)); | 946 true, true, true, false)); |
942 ui::SetTextEditKeyBindingsDelegate(old_delegate); | 947 ui::SetTextEditKeyBindingsDelegate(old_delegate); |
943 | 948 |
944 // Verify that the input field in the subframe is erased. | 949 // Verify that the input field in the subframe is erased. |
945 EXPECT_TRUE(ExecuteScriptAndExtractString( | 950 EXPECT_TRUE(ExecuteScriptAndExtractString( |
946 child, "window.domAutomationController.send(getInputFieldText());", | 951 child, "window.domAutomationController.send(getInputFieldText());", |
947 &result)); | 952 &result)); |
948 EXPECT_EQ("", result); | 953 EXPECT_EQ("", result); |
949 } | 954 } |
950 #endif | 955 #endif |
956 | |
957 // Ideally, the following code + test should be live in | |
958 // 'site_per_process_mac_browsertest.mm'. However, the test | |
959 // 'LookUpStringForRangeRoutesToFocusedWidget' relies on an override in | |
960 // ContentBrowserClient to register its filters in time. In content shell, we | |
961 // cannot have two instances of ShellContentBrowserClient (due to a DCHECK in | |
962 // the ctor). Therefore, we put the test here to use ChromeContentBrowserClient | |
963 // which does not have the same singleton constraint. | |
EhsanK
2016/10/18 04:02:08
This comment explains why we are adding the test h
| |
964 #if defined(OS_MACOSX) | |
965 // An observer of number of open windows. | |
966 class WindowCountObserver { | |
967 public: | |
968 explicit WindowCountObserver(size_t lower_limit) : limit_(lower_limit) {} | |
969 ~WindowCountObserver() {} | |
970 | |
971 // Keep polling the count of open windows until the number exceeds |limit_|. | |
972 void WaitForLimitOrMore() { | |
973 size_t current_count = content::GetOpenNSWindowsCount(); | |
974 if (current_count >= limit_) | |
975 return; | |
976 | |
977 message_loop_runner_ = new content::MessageLoopRunner(); | |
978 message_loop_runner_->Run(); | |
979 content::BrowserThread::PostTask( | |
980 content::BrowserThread::UI, FROM_HERE, | |
981 base::Bind(&WindowCountObserver::CheckWindowCount, | |
982 base::Unretained(this))); | |
983 } | |
984 | |
985 private: | |
986 void CheckWindowCount() { | |
987 size_t current_count = content::GetOpenNSWindowsCount(); | |
988 if (current_count >= limit_) { | |
989 message_loop_runner_->Quit(); | |
990 return; | |
991 } | |
992 content::BrowserThread::PostTask( | |
993 content::BrowserThread::UI, FROM_HERE, | |
994 base::Bind(&WindowCountObserver::CheckWindowCount, | |
995 base::Unretained(this))); | |
996 } | |
997 | |
998 size_t limit_; | |
999 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
1000 | |
1001 DISALLOW_COPY_AND_ASSIGN(WindowCountObserver); | |
1002 }; | |
1003 | |
1004 // The original TextInputClientMessageFilter is added during the initialization | |
1005 // phase of RenderProcessHost. The only chance we have to add the test filter | |
1006 // (so that it can receive the TextInputClientMac incoming IPC messages) is | |
1007 // during the call to RenderProcessWillLaunch() on ContentBrowserClient. This | |
1008 // class provides that for testing. | |
1009 class TestBrowserClient : public ChromeContentBrowserClient { | |
1010 public: | |
1011 TestBrowserClient() {} | |
1012 ~TestBrowserClient() override {} | |
1013 | |
1014 // ContentBrowserClient overrides. | |
1015 void RenderProcessWillLaunch( | |
1016 content::RenderProcessHost* process_host) override { | |
1017 ChromeContentBrowserClient::RenderProcessWillLaunch(process_host); | |
1018 filters_.push_back( | |
1019 new content::TestTextInputClientMessageFilter(process_host)); | |
1020 } | |
1021 | |
1022 // Retrieves the registered filter for the given RenderProcessHost. It will | |
1023 // return false if the RenderProcessHost was initialized while a different | |
1024 // instance of ContentBrowserClient was in action. | |
1025 scoped_refptr<content::TestTextInputClientMessageFilter> | |
1026 GetTextInputClientMessageFilterForProcess( | |
1027 content::RenderProcessHost* process_host) const { | |
1028 for (auto filter : filters_) { | |
1029 if (filter->process() == process_host) | |
1030 return filter; | |
1031 } | |
1032 return nullptr; | |
1033 } | |
1034 | |
1035 private: | |
1036 std::vector<scoped_refptr<content::TestTextInputClientMessageFilter>> | |
1037 filters_; | |
1038 | |
1039 DISALLOW_COPY_AND_ASSIGN(TestBrowserClient); | |
1040 }; | |
1041 | |
1042 // This test verifies that requests for dictionary lookup based on selection | |
1043 // range are routed to the focused RenderWidgetHost. | |
1044 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, | |
1045 LookUpStringForRangeRoutesToFocusedWidget) { | |
1046 // TestBrowserClient needs to replace the ChromeContenBrowserClient after most | |
1047 // things are initialized but before the WebContents is created. Here we make | |
1048 // that happen by creating a new WebContents in a new tab. But before the test | |
1049 // exits, we must destroy the contents and replace the old | |
1050 // ContentBrowserClient because the original WebContents and the new one have | |
1051 // been initialized with the original ContentBrowserClient and the new | |
1052 // TestBrowserClient, respectively. | |
1053 TestBrowserClient browser_client; | |
1054 content::ContentBrowserClient* old_browser_client = | |
1055 content::SetBrowserClientForTesting(&browser_client); | |
1056 | |
1057 content::WebContents* new_contents = | |
1058 content::WebContents::Create(content::WebContents::CreateParams( | |
1059 active_contents()->GetBrowserContext(), nullptr)); | |
1060 browser()->tab_strip_model()->InsertWebContentsAt(1, new_contents, | |
1061 TabStripModel::ADD_ACTIVE); | |
1062 EXPECT_EQ(active_contents(), new_contents); | |
1063 | |
1064 // Starting the test body. | |
1065 CreateIframePage("a(b)"); | |
1066 std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{}), | |
1067 GetFrame(IndexVector{0})}; | |
1068 std::vector<content::RenderWidgetHostView*> views; | |
1069 for (auto frame : frames) | |
1070 views.push_back(frame->GetView()); | |
1071 std::vector<std::string> values{"main frame", "child frame"}; | |
1072 | |
1073 // Adding some field with text to each frame so that we can later query for | |
1074 // dictionary lookup. | |
1075 for (size_t i = 0; i < frames.size(); ++i) | |
1076 AddInputFieldToFrame(frames[i], "text", values[i], true); | |
1077 | |
1078 std::string result; | |
1079 // Recording window count now so that our WindowCountObserver will detect the | |
1080 // popup window. | |
1081 size_t current_window_count = content::GetOpenNSWindowsCount(); | |
1082 | |
1083 // Ensure we have both focus and selected text inside the main frame. | |
1084 EXPECT_TRUE( | |
1085 ExecuteScript(frames[0], "document.querySelector('input').focus();")); | |
1086 | |
1087 // Request for the dictionary lookup and intercept the word on its way back. | |
1088 // The request is always on the tab's view which is a RenderWidgetHostViewMac. | |
1089 content::AskForLookUpDictionaryForRange(views[0], gfx::Range(0, 4)); | |
1090 | |
1091 // Wait until the result comes back. | |
1092 auto root_filter = browser_client.GetTextInputClientMessageFilterForProcess( | |
1093 frames[0]->GetProcess()); | |
1094 EXPECT_TRUE(root_filter); | |
1095 root_filter->WaitForStringFromRange(); | |
1096 | |
1097 EXPECT_EQ("main", root_filter->string_from_range()); | |
1098 | |
1099 // Wait for the popup to appear to make sure TextInputClientMac has consumed | |
1100 // the reply handler for the previous request. | |
1101 WindowCountObserver(current_window_count).WaitForLimitOrMore(); | |
1102 | |
1103 // Ensure we have both focus and selected text inside the child frame. | |
1104 EXPECT_TRUE( | |
1105 ExecuteScript(frames[1], "document.querySelector('input').focus();")); | |
1106 | |
1107 // Record window count again for the popup observer. | |
1108 current_window_count = content::GetOpenNSWindowsCount(); | |
1109 | |
1110 // Make another request. | |
1111 content::AskForLookUpDictionaryForRange(views[0], gfx::Range(0, 5)); | |
1112 | |
1113 // Wait until the result comes back. | |
1114 auto child_filter = browser_client.GetTextInputClientMessageFilterForProcess( | |
1115 frames[1]->GetProcess()); | |
1116 child_filter->WaitForStringFromRange(); | |
1117 | |
1118 EXPECT_EQ("child", child_filter->string_from_range()); | |
1119 | |
1120 // Wait for the popup to appear to make sure TextInputClientMac has consumed | |
1121 // the reply handler for the previous request. | |
1122 WindowCountObserver(current_window_count).WaitForLimitOrMore(); | |
1123 // Test ends here. The rest is cleanup. | |
1124 | |
1125 // Closing this WebContents while we still hold on to our TestBrowserClient. | |
1126 EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt( | |
1127 1, TabStripModel::CLOSE_USER_GESTURE)); | |
1128 | |
1129 // For the cleanup of the original WebContents in tab index 0. | |
1130 content::SetBrowserClientForTesting(old_browser_client); | |
1131 } | |
1132 #endif | |
OLD | NEW |