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

Unified Diff: content/browser/site_per_process_browsertest.cc

Issue 1652483002: Browser Side Text Input State Tracking for OOPIF. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merged Created 4 years, 8 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
« no previous file with comments | « content/browser/site_per_process_browsertest.h ('k') | content/browser/web_contents/web_contents_impl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 9143f47f9786b8981f8f882bd93498ad56039c0a..f9266bd2104543d5e6dceb64fb49402fa733d313 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -31,7 +31,6 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
-#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/frame_messages.h"
#include "content/common/input/synthetic_tap_gesture_params.h"
#include "content/common/view_messages.h"
@@ -47,7 +46,6 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
-#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/test_frame_navigation_observer.h"
#include "ipc/ipc_security_test_util.h"
@@ -6322,4 +6320,217 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_FALSE(rvh->is_swapped_out_);
}
+// This class will sniff incoming IPC for ViewHostMsg_TextInputStateChanged.
+class TextInputStateChangedMessageFilter : public BrowserMessageFilter {
+ public:
+ explicit TextInputStateChangedMessageFilter(
+ RenderWidgetHostImpl* render_widget_host)
+ : BrowserMessageFilter(ViewMsgStart), text_input_state_changed_(false) {
+ if (!render_widget_host || !render_widget_host->GetProcess())
+ text_input_state_changed_ = true;
+ old_state = *render_widget_host->GetView()->text_input_state();
+ render_widget_host->GetProcess()->AddFilter(this);
+ }
+
+ void WaitUntilTextInputStateChanges() {
+ if (!text_input_state_changed_) {
+ message_loop_runner_ = new MessageLoopRunner;
+ message_loop_runner_->Run();
+ }
+ }
+
+ private:
+ ~TextInputStateChangedMessageFilter() override {}
+
+ bool OnMessageReceived(const IPC::Message& msg) override {
+ IPC_BEGIN_MESSAGE_MAP(TextInputStateChangedMessageFilter, msg)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
+ OnTextInputStateChangedMessageReceived)
+ IPC_END_MESSAGE_MAP()
+ return false;
+ }
+
+ void OnTextInputStateChangedMessageReceived(const TextInputState& new_state) {
+ if (new_state.type != old_state.type || new_state.mode != old_state.mode ||
+ new_state.value != old_state.value) {
+ text_input_state_changed_ = true;
+ if (message_loop_runner_)
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ message_loop_runner_->QuitClosure());
+ }
+ }
+
+ bool text_input_state_changed_;
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ TextInputState old_state;
+
+ DISALLOW_COPY_AND_ASSIGN(TextInputStateChangedMessageFilter);
+};
+
+// Verify that when moving the focus between different frames, the WebContents
+// properly keeps track of the text input state.
+// The test loads a page with one input field, two out of process frames, and a
+// second input field positioned after the last <iframe>. Then a sequence of TAB
+// inputs are faked to navigate focus in between the different <input> elements.
+// After each change, we check with the RWHV of the frame as well as the
+// WebContents to make sure the text input state is as expected.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, TextInputStateChanged) {
+ GURL main_page_url(embedded_test_server()->GetURL(
+ "a.com", "/textinput/page_with_input_iframeX2_input.html"));
+ NavigateToURL(shell(), main_page_url);
+
+ WebContents* contents = shell()->web_contents();
+
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+ FrameTreeNode* child_b = root->child_at(0);
+ GURL child_b_url(embedded_test_server()->GetURL(
+ "b.com", "/textinput/page_with_input.html"));
+ NavigateFrameToURL(child_b, child_b_url);
+ EXPECT_TRUE(WaitForRenderFrameReady(child_b->current_frame_host()));
+
+ FrameTreeNode* child_c = root->child_at(1);
+ GURL child_c_url(embedded_test_server()->GetURL(
+ "c.com", "/textinput/page_with_input.html"));
+ NavigateFrameToURL(child_c, child_c_url);
+ EXPECT_TRUE(WaitForRenderFrameReady(child_c->current_frame_host()));
+
+ RenderWidgetHostImpl* root_rwh =
+ root->current_frame_host()->GetRenderWidgetHost();
+ RenderWidgetHostViewBase* root_rwhv = root_rwh->GetView();
+
+ RenderWidgetHostImpl* child_b_rwh =
+ child_b->current_frame_host()->GetRenderWidgetHost();
+ RenderWidgetHostViewBase* child_b_rwhv = child_b_rwh->GetView();
+
+ RenderWidgetHostImpl* child_c_rwh =
+ child_c->current_frame_host()->GetRenderWidgetHost();
+ RenderWidgetHostViewBase* child_c_rwhv = child_c_rwh->GetView();
+
+ // Change the text value in <input> field of either frame so that we can
+ // later track the changes.
+ EXPECT_TRUE(
+ ExecuteScript(child_b->current_frame_host(),
+ "document.querySelector('input').value = 'second';"));
+ EXPECT_TRUE(
+ ExecuteScript(child_c->current_frame_host(),
+ "document.querySelector('input').value = 'third';"));
+
+ // Verify the input type is none in the beginning.
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, root_rwhv->text_input_state()->type);
+
+ // A helper function to send a tab key to the frame and wait for a state
+ // changed message.
+ auto press_tab_and_wait_for_text_input_state_change =
+ [contents](RenderWidgetHostImpl* rwh) {
+ scoped_refptr<TextInputStateChangedMessageFilter> filter =
+ new TextInputStateChangedMessageFilter(rwh);
+ SimulateKeyPress(contents, ui::VKEY_TAB, false, false, false, false);
+ filter->WaitUntilTextInputStateChanges();
+ };
+
+ // Send focus to the first input field.
+ press_tab_and_wait_for_text_input_state_change(root_rwh);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, root_rwhv->text_input_state()->type);
+ EXPECT_EQ("first", root_rwhv->text_input_state()->value);
+
+ // Verify the top-level state is changed.
+ EXPECT_EQ("first", web_contents()->GetTextInputState()->value);
+
+ // Send focus to the input field in frame b.
+ press_tab_and_wait_for_text_input_state_change(child_b_rwh);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, child_b_rwhv->text_input_state()->type);
+ EXPECT_EQ("second", child_b_rwhv->text_input_state()->value);
+
+ EXPECT_EQ("second", web_contents()->GetTextInputState()->value);
+
+ // Send focus to the input field in frame c.
+ press_tab_and_wait_for_text_input_state_change(child_c_rwh);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, child_c_rwhv->text_input_state()->type);
+ EXPECT_EQ("third", child_c_rwhv->text_input_state()->value);
+
+ EXPECT_EQ("third", web_contents()->GetTextInputState()->value);
+
+ // Send focus to the last input field in top frame.
+ press_tab_and_wait_for_text_input_state_change(root_rwh);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, root_rwhv->text_input_state()->type);
+ EXPECT_EQ("fourth", root_rwhv->text_input_state()->value);
+
+ EXPECT_EQ("fourth", web_contents()->GetTextInputState()->value);
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ TextInputStateChangesAfterRendererCrashes) {
+ GURL main_url(
+ embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
+ NavigateToURL(shell(), main_url);
+ WebContentsImpl* contents = web_contents();
+
+ FrameTreeNode* root = contents->GetFrameTree()->root();
+
+ FrameTreeNode* child = root->child_at(0);
+ GURL child_url(embedded_test_server()->GetURL(
+ "b.com", "/textinput/page_with_input.html"));
+ NavigateFrameToURL(child, child_url);
+ EXPECT_TRUE(WaitForRenderFrameReady(child->current_frame_host()));
+
+ // Verify that the text input state is initially none.
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, contents->GetTextInputState()->type);
+
+ auto press_tab_and_wait_for_state_change =
+ [contents](RenderWidgetHostImpl* rwh) {
+ scoped_refptr<TextInputStateChangedMessageFilter> filter =
+ new TextInputStateChangedMessageFilter(rwh);
+ SimulateKeyPress(contents, ui::VKEY_TAB, false, false, false, false);
+ filter->WaitUntilTextInputStateChanges();
+ };
+
+ auto crash_renderer_and_wait_for_input_state_none = [contents](
+ RenderProcessHost* host) {
+ RenderProcessHostWatcher crash_observer(
+ host, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ host->Shutdown(0, false);
+ crash_observer.Wait();
+
+ // We need to wait until the actual text input state update occurs.
+ while (contents->GetTextInputState()->type != ui::TEXT_INPUT_TYPE_NONE) {
+ scoped_refptr<MessageLoopRunner> loop_runner_ = new MessageLoopRunner();
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+ loop_runner_->QuitClosure(),
+ base::TimeDelta::FromMilliseconds(0LL));
+ loop_runner_->Run();
+ }
+ };
+
+ // Press a tab key to focus the <input> and verify that the top level
+ // WebContents sees it.
+ RenderWidgetHostImpl* child_rwh =
+ child->current_frame_host()->GetRenderWidgetHost();
+ press_tab_and_wait_for_state_change(child_rwh);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, contents->GetTextInputState()->type);
+
+ // Crash the renderer and wait until WebContentsImpl has updates the
+ // state.
+ RenderProcessHost* child_process = child_rwh->GetProcess();
+ crash_renderer_and_wait_for_input_state_none(child_process);
+
+ // Now repeat the same test for the top level RWHV.
+ // First remove the <iframe> and append an <input>
+ EXPECT_TRUE(ExecuteScript(contents,
+ "var f = document.querySelector('iframe'); "
+ "f.parentNode.removeChild(f);"));
+ EXPECT_TRUE(ExecuteScript(
+ contents, "document.body.appendChild(document.createElement('input'));"));
+
+ // Press tab to focus the <input> and observe the state change.
+ RenderWidgetHostImpl* root_rwh =
+ root->current_frame_host()->GetRenderWidgetHost();
+ press_tab_and_wait_for_state_change(root_rwh);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, contents->GetTextInputState()->type);
+
+ // Crash the tab renderer and observer the input state going back to none.
+ RenderProcessHost* host_process = root_rwh->GetProcess();
+ crash_renderer_and_wait_for_input_state_none(host_process);
+}
+
} // namespace content
« no previous file with comments | « content/browser/site_per_process_browsertest.h ('k') | content/browser/web_contents/web_contents_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698