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

Unified Diff: content/browser/site_per_process_browsertest.cc

Issue 2883033003: Propagate inert state to OOPIFs when a modal dialog is active (Closed)
Patch Set: alexmos comments addressed Created 3 years, 6 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/site_per_process_browsertest.cc
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 542db3ac6b3c555bdfa342b6cdeadf4cc32ad9bd..b0f7638524b50e851b79adea33ef3107927b244c 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -10200,4 +10200,121 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_EQ(foo_url, web_contents()->GetMainFrame()->GetLastCommittedURL());
}
+// Class to sniff incoming IPCs for FrameHostMsg_SetIsInert messages.
+class SetIsInertMessageFilter : public content::BrowserMessageFilter {
+ public:
+ SetIsInertMessageFilter()
+ : content::BrowserMessageFilter(FrameMsgStart),
+ message_loop_runner_(new content::MessageLoopRunner),
+ msg_received_(false) {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ IPC_BEGIN_MESSAGE_MAP(SetIsInertMessageFilter, message)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_SetIsInert, OnSetIsInert)
+ IPC_END_MESSAGE_MAP()
+ return false;
+ }
+
+ bool is_inert() const { return is_inert_; }
+
+ void Wait() { message_loop_runner_->Run(); }
+
+ private:
+ ~SetIsInertMessageFilter() override {}
+
+ void OnSetIsInert(bool is_inert) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&SetIsInertMessageFilter::OnSetIsInertOnUI, this, is_inert));
+ }
+ void OnSetIsInertOnUI(bool is_inert) {
+ is_inert_ = is_inert;
+ if (!msg_received_) {
+ msg_received_ = true;
+ message_loop_runner_->Quit();
+ }
+ }
+ scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+ bool msg_received_;
+ bool is_inert_;
+ DISALLOW_COPY_AND_ASSIGN(SetIsInertMessageFilter);
+};
+
+// Tests that when a frame contains a modal <dialog> element, out-of-process
+// iframe children cannot take focus, because they are inert.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossProcessInertSubframe) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* iframe_node = root->child_at(0);
+
+ EXPECT_TRUE(ExecuteScript(
+ iframe_node,
+ "document.head.innerHTML = '';"
+ "document.body.innerHTML = '<input id=\"text1\"> <input id=\"text2\">';"
+ "text1.focus();"));
+
+ // Add a filter to the parent frame's process to monitor for inert bit
+ // updates. These are sent through the proxy for b.com child frame.
+ scoped_refptr<SetIsInertMessageFilter> filter = new SetIsInertMessageFilter();
+ root->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+ // Add a <dialog> to the root frame and call showModal on it.
+ EXPECT_TRUE(ExecuteScript(root,
+ "let dialog = "
+ "document.body.appendChild(document.createElement('"
+ "dialog'));"
+ "dialog.innerHTML = 'Modal dialog <input>';"
+ "dialog.showModal();"));
+ filter->Wait();
+ EXPECT_TRUE(filter->is_inert());
+
+ // This yields the UI thread to ensure that the real SetIsInert message
+ // handler runs, in order to guarantee that the update arrives at the
+ // renderer process before the script below.
+ {
+ base::RunLoop loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ loop.QuitClosure());
+ loop.Run();
+ }
+
+ std::string focused_element;
+
+ // Attempt to change focus in the inert subframe. This should fail.
+ // The setTimeout ensures that the inert bit can propagate before the
+ // test JS code runs.
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ iframe_node,
+ "window.setTimeout(() => {text2.focus();"
+ "domAutomationController.send(document.activeElement.id);}, 0)",
+ &focused_element));
+ EXPECT_EQ("", focused_element);
+
+ // Navigate the child frame to another site, so that it moves into a new
+ // process.
+ GURL site_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
+ NavigateFrameToURL(iframe_node, site_url);
+
+ EXPECT_TRUE(ExecuteScript(
+ iframe_node,
+ "document.head.innerHTML = '';"
+ "document.body.innerHTML = '<input id=\"text1\"> <input id=\"text2\">';"
+ "text1.focus();"));
+
+ // Verify that inertness was preserved across the navigation.
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ iframe_node,
+ "text2.focus();"
+ "domAutomationController.send(document.activeElement.id);",
+ &focused_element));
+ EXPECT_EQ("", focused_element);
alexmos 2017/06/20 18:46:10 For completeness, and since it should be easy, cou
kenrb 2017/06/22 15:33:35 Done.
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698