Fix focus for PDF in mainframe, add test.

This CL started out as a re-implementation of
WebPluginContainerTest.PluginDocumentPluginIsFocused to work without
BrowserPlugin, but in the process I realized that we had regressed
the behaviour that was originally fixed in
https://codereview.chromium.org/1389093002.

That regression is also fixed in this CL.

Bug: 1019360, 536637, 1022469
Change-Id: I25bbe47fb602b8a3ef5d9be931e7d5fe486c4008
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1903653
Commit-Queue: James MacLean <[email protected]>
Reviewed-by: Lei Zhang <[email protected]>
Reviewed-by: Alex Moshchuk <[email protected]>
Cr-Commit-Position: refs/heads/master@{#714635}
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 023f7bb..be3fee2a 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -469,12 +469,7 @@
   auto* guest_web_contents = GetGuestViewManager()->WaitForSingleGuestCreated();
   ASSERT_TRUE(guest_web_contents);
   EXPECT_NE(embedder_web_contents, guest_web_contents);
-  while (guest_web_contents->IsLoading()) {
-    base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
-    run_loop.Run();
-  }
+  EXPECT_TRUE(content::WaitForLoadStop(guest_web_contents));
 
   // Make sure the text area still has focus.
   ASSERT_TRUE(
@@ -490,6 +485,29 @@
           .ExtractBool());
 }
 
+// This test is a re-implementation of
+// WebPluginContainerTest.PluginDocumentPluginIsFocused, which was introduced
+// for https://crbug.com/536637. The original implementation checked that the
+// BrowserPlugin hosting the pdf extension was focused; in this re-write, we
+// make sure the guest view's WebContents has focus.
+IN_PROC_BROWSER_TEST_F(PDFExtensionTestWithTestGuestViewManager,
+                       PdfInMainFrameHasFocus) {
+  // Load test HTML, and verify the text area has focus.
+  GURL main_url(embedded_test_server()->GetURL("/pdf/test.pdf"));
+  ui_test_utils::NavigateToURL(browser(), main_url);
+  auto* embedder_web_contents = GetActiveWebContents();
+
+  // Verify the pdf has loaded.
+  auto* guest_web_contents = GetGuestViewManager()->WaitForSingleGuestCreated();
+  ASSERT_TRUE(guest_web_contents);
+  EXPECT_NE(embedder_web_contents, guest_web_contents);
+  EXPECT_TRUE(content::WaitForLoadStop(guest_web_contents));
+
+  // Make sure the guest WebContents has focus.
+  EXPECT_EQ(guest_web_contents,
+            content::GetFocusedWebContents(embedder_web_contents));
+}
+
 class PDFExtensionLoadTest : public PDFExtensionTest,
                              public testing::WithParamInterface<int> {
  public:
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index 5d58f97..806cbfa 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -549,7 +549,8 @@
 
   if (content::GuestMode::IsCrossProcessFrameGuest(web_contents())) {
     owner_web_contents_->AttachInnerWebContents(
-        base::WrapUnique<WebContents>(web_contents()), outer_contents_frame);
+        base::WrapUnique<WebContents>(web_contents()), outer_contents_frame,
+        is_full_page_plugin);
     // TODO(ekaramad): MimeHandlerViewGuest might not need this ACK
     // (https://crbug.com/659750).
     // We don't ACK until after AttachToOuterWebContentsFrame, so that
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index edd87424..1ac1f50 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -168,7 +168,8 @@
   DCHECK_EQ(portal_contents_impl_->GetDelegate(), this);
 
   outer_contents_impl->AttachInnerWebContents(std::move(portal_contents_),
-                                              outer_node->current_frame_host());
+                                              outer_node->current_frame_host(),
+                                              false /* is_full_page */);
 
   FrameTreeNode* frame_tree_node =
       portal_contents_impl_->GetMainFrame()->frame_tree_node();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 15e5b38..fdd66fa 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1768,7 +1768,8 @@
 
 void WebContentsImpl::AttachInnerWebContents(
     std::unique_ptr<WebContents> inner_web_contents,
-    RenderFrameHost* render_frame_host) {
+    RenderFrameHost* render_frame_host,
+    bool is_full_page) {
   WebContentsImpl* inner_web_contents_impl =
       static_cast<WebContentsImpl*>(inner_web_contents.get());
   DCHECK(!inner_web_contents_impl->node_.outer_web_contents());
@@ -1833,6 +1834,14 @@
         render_frame_host_impl->GetSiteInstance());
   }
   outer_render_manager->set_attach_complete();
+
+  // If the inner WebContents is full frame, give it focus.
+  if (is_full_page) {
+    // There should only ever be one inner WebContents when |is_full_page| is
+    // true, and it is the one we just attached.
+    DCHECK_EQ(1u, node_.GetInnerWebContents().size());
+    inner_web_contents_impl->SetAsFocusedWebContentsIfNecessary();
+  }
 }
 
 std::unique_ptr<WebContents> WebContentsImpl::DetachFromOuterWebContents() {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index d33a2b55..1694eff 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -380,7 +380,8 @@
   bool NeedToFireBeforeUnload() override;
   void DispatchBeforeUnload(bool auto_cancel) override;
   void AttachInnerWebContents(std::unique_ptr<WebContents> inner_web_contents,
-                              RenderFrameHost* render_frame_host) override;
+                              RenderFrameHost* render_frame_host,
+                              bool is_full_page) override;
   RenderFrameHostImpl* GetOuterWebContentsFrame() override;
   WebContentsImpl* GetOuterWebContents() override;
   WebContentsImpl* GetOutermostWebContents() override;
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 49f725c3..d5d0677 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -3983,8 +3983,8 @@
       WebContents::Create(inner_params);
 
   // Attach grandchild to child.
-  child_contents_ptr->AttachInnerWebContents(std::move(grandchild_contents_ptr),
-                                             child_rfh);
+  child_contents_ptr->AttachInnerWebContents(
+      std::move(grandchild_contents_ptr), child_rfh, false /* is_full_page */);
 
   // At this point the child hasn't been attached to the root.
   EXPECT_EQ(1U, root_web_contents->GetInputEventRouter()
@@ -3992,7 +3992,8 @@
 
   // Attach child+grandchild subtree to root.
   root_web_contents->AttachInnerWebContents(std::move(child_contents_ptr),
-                                            child_to_replace_rfh);
+                                            child_to_replace_rfh,
+                                            false /* is_full_page */);
 
   // Verify views registered for both child and grandchild.
   EXPECT_EQ(3U, root_web_contents->GetInputEventRouter()
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 8a9d071..31f0ebe 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -596,9 +596,12 @@
   // but ideally it should be "about:blank" to avoid problems with beforeunload.
   // To ensure sane usage of this API users first should call the async API
   // RenderFrameHost::PrepareForInnerWebContentsAttach first.
+  // Note: If |is_full_page| is true, focus will be given to the inner
+  // WebContents.
   virtual void AttachInnerWebContents(
       std::unique_ptr<WebContents> inner_web_contents,
-      RenderFrameHost* render_frame_host) = 0;
+      RenderFrameHost* render_frame_host,
+      bool is_full_page) = 0;
 
   // Returns the outer WebContents frame, the same frame that this WebContents
   // was attached in AttachToOuterWebContentsFrame().
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index e71de39..481addfd 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -226,7 +226,8 @@
 
   // Attach. |inner_contents| becomes owned by |outer_contents|.
   WebContents* inner_contents = inner_contents_ptr.get();
-  outer_contents->AttachInnerWebContents(std::move(inner_contents_ptr), rfh);
+  outer_contents->AttachInnerWebContents(std::move(inner_contents_ptr), rfh,
+                                         false /* is_full_page */);
 
   return inner_contents;
 }
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
index 8b3692c..6dedb79 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
@@ -196,8 +196,6 @@
   fullscreen_waiter.Wait();
   WaitForFullscreenAnimation();
 
-  EXPECT_NE(guest_contents, content::GetFocusedWebContents(embedder_contents));
-  EXPECT_FALSE(IsRenderWidgetHostFocused(guest_rwh));
   // Send a touch to focus the guest. We can't directly test that the correct
   // RenderWidgetHost got focus, but the wait seems to work.
   SimulateMouseClick(guest_contents, 0, blink::WebMouseEvent::Button::kLeft);