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 99327e83f51ee98cfbd19e2ec07173f668ef1b08..b736965e1d4a3ec10c6bb006fe9d99d5e20b2fca 100644 |
--- a/content/browser/site_per_process_browsertest.cc |
+++ b/content/browser/site_per_process_browsertest.cc |
@@ -398,21 +398,30 @@ void RenderFrameHostCreatedObserver::RenderFrameCreated( |
class FrameFocusedObserver : public FrameTreeNode::Observer { |
public: |
FrameFocusedObserver(FrameTreeNode* owner) |
- : owner_(owner), message_loop_runner_(new MessageLoopRunner) { |
+ : focused_(false), |
+ owner_(owner), |
+ message_loop_runner_(new MessageLoopRunner) { |
owner->AddObserver(this); |
} |
~FrameFocusedObserver() override { owner_->RemoveObserver(this); } |
- void Wait() { message_loop_runner_->Run(); } |
+ void Wait() { |
+ if (focused_) |
+ return; |
+ message_loop_runner_->Run(); |
+ } |
private: |
// FrameTreeNode::Observer |
void OnFrameTreeNodeFocused(FrameTreeNode* node) override { |
- if (node == owner_) |
+ if (node == owner_) { |
+ focused_ = true; |
message_loop_runner_->Quit(); |
+ } |
} |
+ bool focused_; |
FrameTreeNode* owner_; |
scoped_refptr<MessageLoopRunner> message_loop_runner_; |
@@ -5215,4 +5224,91 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
EXPECT_FALSE(mixed_child->has_committed_real_load()); |
} |
+// This class observes the first change in the text input state |
+// for a given RenderWidgetHostViewBase. |
+class TextInputStateObserver { |
+ public: |
+ TextInputStateObserver(RenderWidgetHostViewBase* view) |
+ : view_(view), |
+ state_(*view->current_text_input_state()), |
+ message_loop_runner_(nullptr) {} |
+ |
+ // Hold and keep polling the |view_| until its text input state changes. |
+ TextInputState WaitUntilStateChanges() { |
+ while (!DidChangeState()) { |
+ message_loop_runner_ = new MessageLoopRunner; |
+ BrowserThread::ID current_thread_id; |
+ EXPECT_TRUE( |
+ BrowserThread::GetCurrentThreadIdentifier(¤t_thread_id)); |
+ BrowserThread::PostDelayedTask(current_thread_id, FROM_HERE, |
+ message_loop_runner_->QuitClosure(), |
+ base::TimeDelta::FromMicroseconds(500)); |
+ message_loop_runner_->Run(); |
+ } |
+ return *view_->current_text_input_state(); |
+ } |
+ |
+ private: |
+ bool DidChangeState() { |
+ TextInputState current = *view_->current_text_input_state(); |
+ return state_.type != current.type || state_.mode != current.mode || |
+ state_.value != current.value; |
+ } |
+ RenderWidgetHostViewBase* view_; |
+ TextInputState state_; |
+ scoped_refptr<MessageLoopRunner> message_loop_runner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TextInputStateObserver); |
+}; |
+ |
+// Verify that by moving the focus between different frames the top-level |
+// RenderWidgetHostViewBase tracks the input state properly. |
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, TextInputStateChanged) { |
+ GURL main_page_url(embedded_test_server()->GetURL( |
+ "a.com", "/textinput/page_with_input_field_and_iframe.html")); |
+ NavigateToURL(shell(), main_page_url); |
+ GURL cross_origin_url(embedded_test_server()->GetURL( |
+ "b.com", "/textinput/page_with_input_field_and_iframe.html")); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ // Wait for the main frame to finish loading. |
+ EXPECT_TRUE(WaitForRenderFrameReady(root->current_frame_host())); |
+ |
+ // Navigate the child frame. |
+ FrameTreeNode* child_frame_node = root->child_at(0); |
+ NavigateFrameToURL(child_frame_node, cross_origin_url); |
+ |
+ // Wait for the child frame to finish loading. |
+ EXPECT_TRUE(WaitForRenderFrameReady(child_frame_node->current_frame_host())); |
+ |
+ RenderWidgetHostImpl* root_rwh = |
+ root->current_frame_host()->GetRenderWidgetHost(); |
+ RenderWidgetHostViewBase* root_rwhv = root_rwh->GetView(); |
+ |
+ EXPECT_EQ(root_rwhv->current_text_input_state()->type, |
+ ui::TEXT_INPUT_TYPE_NONE); |
+ // Focus the root (main-frame). This would focus the text input field. |
+ LOG(INFO) << "Sending a mouse click to top level page's <input>."; |
+ TextInputStateObserver root_observer(root_rwhv); |
+ SimulateMouseClick(root_rwh, 1, 1); |
+ TextInputState new_state = root_observer.WaitUntilStateChanges(); |
+ EXPECT_EQ(new_state.type, ui::TEXT_INPUT_TYPE_TEXT); |
+ |
+ // Now focus the child frame and read the text input state. |
+ RenderWidgetHostImpl* child_rwh = |
+ child_frame_node->current_frame_host()->GetRenderWidgetHost(); |
+ RenderWidgetHostViewBase* child_rwhv = child_rwh->GetView(); |
+ TextInputStateObserver child_observer(child_rwhv); |
+ SimulateMouseClick(child_rwh, 1, 1); |
+ new_state = child_observer.WaitUntilStateChanges(); |
+ |
+ EXPECT_EQ(new_state.type, ui::TEXT_INPUT_TYPE_TEXT); |
+ |
+ // Finally, the top level view should see the child's view. |
+ new_state = *root_rwhv->current_text_input_state(); |
+ EXPECT_EQ(new_state.type, ui::TEXT_INPUT_TYPE_TEXT); |
+ EXPECT_EQ(new_state.value, cross_origin_url.spec()); |
+} |
+ |
} // namespace content |