| 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
|
|
|