Preparation steps for adding speculative renderer creation.

Generalized the RenderFrameHost and WebUI creation methods to allow for the
following step of speculatively creating renderers in browser side navigations
for the PlzNavigate project (spliting off of crrev.com/701953006).

BUG=376094

TBR=creis@chromium.org

Review URL: https://codereview.chromium.org/753173002

Cr-Commit-Position: refs/heads/master@{#305989}
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index ad2141e..96890f0 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -206,8 +206,8 @@
         source->frame_tree()->GetRenderViewHost(site_instance);
     if (!render_view_host) {
       root()->render_manager()->CreateRenderFrame(
-          site_instance, MSG_ROUTING_NONE,
-          CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN);
+          site_instance, nullptr, MSG_ROUTING_NONE,
+          CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
     }
   }
 
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 7780cc0..06ab82512 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -134,23 +134,25 @@
   return iter->second;
 }
 
-void RenderFrameHostManager::SetPendingWebUI(const GURL& url,
-                                             int bindings) {
-  pending_web_ui_.reset(
-      delegate_->CreateWebUIForRenderManager(url));
+void RenderFrameHostManager::SetPendingWebUI(const GURL& url, int bindings) {
+  pending_web_ui_ = CreateWebUI(url, bindings);
   pending_and_current_web_ui_.reset();
+}
+
+scoped_ptr<WebUIImpl> RenderFrameHostManager::CreateWebUI(const GURL& url,
+                                                          int bindings) {
+  scoped_ptr<WebUIImpl> new_web_ui(delegate_->CreateWebUIForRenderManager(url));
 
   // If we have assigned (zero or more) bindings to this NavigationEntry in the
   // past, make sure we're not granting it different bindings than it had
   // before.  If so, note it and don't give it any bindings, to avoid a
   // potential privilege escalation.
-  if (pending_web_ui_.get() &&
-      bindings != NavigationEntryImpl::kInvalidBindings &&
-      pending_web_ui_->GetBindings() != bindings) {
-    RecordAction(
-        base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
-    pending_web_ui_.reset();
+  if (new_web_ui && bindings != NavigationEntryImpl::kInvalidBindings &&
+      new_web_ui->GetBindings() != bindings) {
+    RecordAction(base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
+    return nullptr;
   }
+  return new_web_ui.Pass();
 }
 
 RenderFrameHostImpl* RenderFrameHostManager::Navigate(
@@ -557,6 +559,30 @@
   }
 }
 
+void RenderFrameHostManager::DiscardUnusedFrame(
+    scoped_ptr<RenderFrameHostImpl> render_frame_host) {
+  // TODO(carlosk): this code is very similar to what can be found in
+  // SwapOutOldFrame and we should see that these are unified at some point.
+
+  // If the SiteInstance for the pending RFH is being used by others don't
+  // delete the RFH. Just swap it out and it can be reused at a later point.
+  SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
+  if (site_instance->HasSite() && site_instance->active_frame_count() > 1) {
+    // Any currently suspended navigations are no longer needed.
+    render_frame_host->CancelSuspendedNavigations();
+
+    RenderFrameProxyHost* proxy =
+        new RenderFrameProxyHost(site_instance, frame_tree_node_);
+    proxy_hosts_[site_instance->GetId()] = proxy;
+    render_frame_host->SwapOut(proxy);
+    if (frame_tree_node_->IsMainFrame())
+      proxy->TakeFrameHostOwnership(render_frame_host.Pass());
+  } else {
+    // We won't be coming back, so delete this one.
+    render_frame_host.reset();
+  }
+}
+
 void RenderFrameHostManager::MoveToPendingDeleteHosts(
     scoped_ptr<RenderFrameHostImpl> render_frame_host) {
   // |render_frame_host| will be deleted when its SwapOut ACK is received, or
@@ -990,16 +1016,32 @@
   return current_instance->GetSiteURL();
 }
 
-void RenderFrameHostManager::CreateRenderFrameHostForNewSiteInstance(
+void RenderFrameHostManager::CreatePendingRenderFrameHost(
     SiteInstance* old_instance,
     SiteInstance* new_instance,
     bool is_main_frame) {
   int create_render_frame_flags = 0;
   if (is_main_frame)
     create_render_frame_flags |= CREATE_RF_FOR_MAIN_FRAME_NAVIGATION;
-  // Ensure that we have created RFHs for the new RFH's opener chain if
-  // we are staying in the same BrowsingInstance. This allows the new RFH
-  // to send cross-process script calls to its opener(s).
+
+  if (delegate_->IsHidden())
+    create_render_frame_flags |= CREATE_RF_HIDDEN;
+
+  int opener_route_id =
+      CreateOpenerRenderViewsIfNeeded(old_instance, new_instance);
+
+  if (pending_render_frame_host_)
+    CancelPending();
+
+  // Create a non-swapped-out RFH with the given opener.
+  pending_render_frame_host_ =
+      CreateRenderFrame(new_instance, pending_web_ui(), opener_route_id,
+                        create_render_frame_flags, nullptr);
+}
+
+int RenderFrameHostManager::CreateOpenerRenderViewsIfNeeded(
+    SiteInstance* old_instance,
+    SiteInstance* new_instance) {
   int opener_route_id = MSG_ROUTING_NONE;
   if (new_instance->IsRelatedSiteInstance(old_instance)) {
     opener_route_id =
@@ -1012,17 +1054,7 @@
           frame_tree_node_, new_instance);
     }
   }
-
-  if (delegate_->IsHidden())
-    create_render_frame_flags |= CREATE_RF_HIDDEN;
-
-  // Create a non-swapped-out RFH with the given opener.
-  int route_id = CreateRenderFrame(new_instance, opener_route_id,
-                                   create_render_frame_flags);
-  if (route_id == MSG_ROUTING_NONE) {
-    pending_render_frame_host_.reset();
-    return;
-  }
+  return opener_route_id;
 }
 
 scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
@@ -1056,9 +1088,12 @@
   return render_frame_host.Pass();
 }
 
-int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
-                                              int opener_route_id,
-                                              int flags) {
+scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrame(
+    SiteInstance* instance,
+    WebUIImpl* web_ui,
+    int opener_route_id,
+    int flags,
+    int* view_routing_id_ptr) {
   bool swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
   CHECK(instance);
   // Swapped out views should always be hidden.
@@ -1071,10 +1106,11 @@
   }
 
   scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
-  RenderFrameHostImpl* frame_to_announce = NULL;
-  int routing_id = MSG_ROUTING_NONE;
+  bool success = true;
+  if (view_routing_id_ptr)
+    *view_routing_id_ptr = MSG_ROUTING_NONE;
 
-  // We are creating a pending or swapped out RFH here.  We should never create
+  // We are creating a pending or swapped out RFH here. We should never create
   // it in the same SiteInstance as our current RFH.
   CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
 
@@ -1082,9 +1118,9 @@
   // to re-use the existing one, which has already been initialized.  We'll
   // remove it from the list of proxy hosts below if it will be active.
   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
-
   if (proxy && proxy->render_frame_host()) {
-    routing_id = proxy->GetRenderViewHost()->GetRoutingID();
+    if (view_routing_id_ptr)
+      *view_routing_id_ptr = proxy->GetRenderViewHost()->GetRoutingID();
     // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
     // Prevent the process from exiting while we're trying to use it.
     if (!swapped_out) {
@@ -1098,13 +1134,13 @@
       // gets a RenderViewHost in the SiteInstance of its opener WebContents.
       // If not used in the first navigation, this RVH is swapped out and is not
       // granted bindings, so we may need to grant them when swapping it in.
-      if (pending_web_ui() &&
-          !new_render_frame_host->GetProcess()->IsIsolatedGuest()) {
-        int required_bindings = pending_web_ui()->GetBindings();
-        RenderViewHost* rvh = new_render_frame_host->render_view_host();
-        if ((rvh->GetEnabledBindings() & required_bindings) !=
-                required_bindings) {
-          rvh->AllowBindings(required_bindings);
+      if (web_ui && !new_render_frame_host->GetProcess()->IsIsolatedGuest()) {
+        int required_bindings = web_ui->GetBindings();
+        RenderViewHost* render_view_host =
+            new_render_frame_host->render_view_host();
+        if ((render_view_host->GetEnabledBindings() & required_bindings) !=
+            required_bindings) {
+          render_view_host->AllowBindings(required_bindings);
         }
       }
     }
@@ -1129,7 +1165,7 @@
         proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
     }
 
-    bool success =
+    success =
         InitRenderView(render_view_host, opener_route_id, proxy_routing_id,
                        !!(flags & CREATE_RF_FOR_MAIN_FRAME_NAVIGATION));
     if (success) {
@@ -1141,22 +1177,24 @@
         DCHECK(new_render_frame_host.get());
         success = InitRenderFrame(new_render_frame_host.get());
       }
-    } else if (!swapped_out && pending_render_frame_host_) {
-      CancelPending();
+      if (success) {
+        if (view_routing_id_ptr)
+          *view_routing_id_ptr = render_view_host->GetRoutingID();
+        // If a brand new RFH was created, announce it to observers.
+        if (new_render_frame_host) {
+          render_frame_delegate_->RenderFrameCreated(
+              new_render_frame_host.get());
+        }
+      }
     }
-    routing_id = render_view_host->GetRoutingID();
-    frame_to_announce = new_render_frame_host.get();
   }
 
-  // Use this as our new pending RFH if it isn't swapped out.
-  if (!swapped_out)
-    pending_render_frame_host_ = new_render_frame_host.Pass();
-
-  // If a brand new RFH was created, announce it to observers.
-  if (frame_to_announce)
-    render_frame_delegate_->RenderFrameCreated(frame_to_announce);
-
-  return routing_id;
+  // Returns the new RFH if it isn't swapped out.
+  if (success && !swapped_out) {
+    DCHECK(new_render_frame_host->GetSiteInstance() == instance);
+    return new_render_frame_host.Pass();
+  }
+  return nullptr;
 }
 
 int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
@@ -1439,8 +1477,8 @@
     // otherwise CancelPending may clear the pending_web_ui_ and the page will
     // not have its bindings set appropriately.
     SetPendingWebUI(url, bindings);
-    CreateRenderFrameHostForNewSiteInstance(
-        current_instance, new_instance.get(), frame_tree_node_->IsMainFrame());
+    CreatePendingRenderFrameHost(current_instance, new_instance.get(),
+                                 frame_tree_node_->IsMainFrame());
     if (!pending_render_frame_host_.get()) {
       return NULL;
     }
@@ -1558,24 +1596,7 @@
   // We no longer need to prevent the process from exiting.
   pending_render_frame_host->GetProcess()->RemovePendingView();
 
-  // If the SiteInstance for the pending RFH is being used by others, don't
-  // delete the RFH, just swap it out and it can be reused at a later point.
-  SiteInstanceImpl* site_instance =
-      pending_render_frame_host->GetSiteInstance();
-  if (site_instance->active_frame_count() > 1) {
-    // Any currently suspended navigations are no longer needed.
-    pending_render_frame_host->CancelSuspendedNavigations();
-
-    RenderFrameProxyHost* proxy =
-        new RenderFrameProxyHost(site_instance, frame_tree_node_);
-    proxy_hosts_[site_instance->GetId()] = proxy;
-    pending_render_frame_host->SwapOut(proxy);
-    if (frame_tree_node_->IsMainFrame())
-      proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass());
-  } else {
-    // We won't be coming back, so delete this one.
-    pending_render_frame_host.reset();
-  }
+  DiscardUnusedFrame(pending_render_frame_host.Pass());
 
   pending_web_ui_.reset();
   pending_and_current_web_ui_.reset();
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index c40cac4..ae8d9f9d 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -26,14 +26,13 @@
 class BrowserContext;
 class CrossProcessFrameConnector;
 class CrossSiteTransferringRequest;
-class InterstitialPageImpl;
 class FrameTreeNode;
+class InterstitialPageImpl;
 class NavigationControllerImpl;
 class NavigationEntry;
 class NavigationEntryImpl;
 class RenderFrameHost;
 class RenderFrameHostDelegate;
-class RenderFrameHost;
 class RenderFrameHostImpl;
 class RenderFrameHostManagerTest;
 class RenderFrameProxyHost;
@@ -148,7 +147,8 @@
     // Creates a WebUI object for the given URL if one applies. Ownership of the
     // returned pointer will be passed to the caller. If no WebUI applies,
     // returns NULL.
-    virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0;
+    virtual scoped_ptr<WebUIImpl> CreateWebUIForRenderManager(
+        const GURL& url) = 0;
 
     // Returns the navigation entry of the current navigation, or NULL if there
     // is none.
@@ -231,10 +231,6 @@
                                    pending_and_current_web_ui_.get();
   }
 
-  // Sets the pending Web UI for the pending navigation, ensuring that the
-  // bindings are appropriate compared to |bindings|.
-  void SetPendingWebUI(const GURL& url, int bindings);
-
   // Called when we want to instruct the renderer to navigate to the given
   // navigation entry. It may create a new RenderFrameHost or re-use an existing
   // one. The RenderFrameHost to navigate will be returned. Returns NULL if one
@@ -297,11 +293,22 @@
   // Called when a renderer sets its opener to null.
   void DidDisownOpener(RenderFrameHost* render_frame_host);
 
-  // Helper method to create and initialize a RenderFrameHost.  If |flags|
-  // has the CREATE_RF_SWAPPED_OUT bit set from the CreateRenderFrameFlags
-  // enum, it will initially be placed on the swapped out hosts list.
-  // Returns the routing id of the *view* associated with the frame.
-  int CreateRenderFrame(SiteInstance* instance, int opener_route_id, int flags);
+  // Sets the pending Web UI for the pending navigation, ensuring that the
+  // bindings are appropriate compared to |bindings|.
+  void SetPendingWebUI(const GURL& url, int bindings);
+
+  // Creates and initializes a RenderFrameHost. The |web_ui| is an optional
+  // input parameter used to double check bindings when swapping back in a
+  // previously existing RenderFrameHost. If |flags| has the
+  // CREATE_RF_SWAPPED_OUT bit set from the CreateRenderFrameFlags enum, it will
+  // initially be placed on the swapped out hosts list. If |view_routing_id_ptr|
+  // is not nullptr it will be set to the routing id of the view associated with
+  // the frame.
+  scoped_ptr<RenderFrameHostImpl> CreateRenderFrame(SiteInstance* instance,
+                                                    WebUIImpl* web_ui,
+                                                    int opener_route_id,
+                                                    int flags,
+                                                    int* view_routing_id_ptr);
 
   // Helper method to create and initialize a RenderFrameProxyHost and return
   // its routing id.
@@ -401,6 +408,10 @@
       const GURL& new_effective_url,
       bool new_is_view_source_mode) const;
 
+  // Creates a new Web UI, ensuring that the bindings are appropriate compared
+  // to |bindings|.
+  scoped_ptr<WebUIImpl> CreateWebUI(const GURL& url, int bindings);
+
   // Returns true if it is safe to reuse the current WebUI when navigating from
   // |current_entry| to |new_url|.
   bool ShouldReuseWebUI(
@@ -435,12 +446,19 @@
       SiteInstance* current_instance,
       NavigationEntry* current_entry);
 
-  // Creates a new RenderFrameHostImpl for the |new_instance| while respecting
-  // the opener route if needed and stores it in pending_render_frame_host_.
-  void CreateRenderFrameHostForNewSiteInstance(
-      SiteInstance* old_instance,
-      SiteInstance* new_instance,
-      bool is_main_frame);
+  // Creates a new RenderFrameHostImpl for the |new_instance| and assign it to
+  // |pending_render_frame_host_| while respecting the opener route if needed
+  // and stores it in pending_render_frame_host_.
+  void CreatePendingRenderFrameHost(SiteInstance* old_instance,
+                                    SiteInstance* new_instance,
+                                    bool is_main_frame);
+
+  // Ensure that we have created RFHs for the new RFH's opener chain if
+  // we are staying in the same BrowsingInstance. This allows the new RFH
+  // to send cross-process script calls to its opener(s). Returns the opener
+  // route ID to be used for the new RenderView to be created.
+  int CreateOpenerRenderViewsIfNeeded(SiteInstance* old_instance,
+                                      SiteInstance* new_instance);
 
   // Creates a RenderFrameHost and corresponding RenderViewHost if necessary.
   scoped_ptr<RenderFrameHostImpl> CreateRenderFrameHost(SiteInstance* instance,
@@ -474,6 +492,10 @@
   // deleted or put on the pending delete list during this call.
   void SwapOutOldFrame(scoped_ptr<RenderFrameHostImpl> old_render_frame_host);
 
+  // Discards a RenderFrameHost that was never made active (for active ones
+  // SwapOutOldFrame is used instead).
+  void DiscardUnusedFrame(scoped_ptr<RenderFrameHostImpl> render_frame_host);
+
   // Holds |render_frame_host| until it can be deleted when its swap out ACK
   // arrives.
   void MoveToPendingDeleteHosts(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 3951d0f..84db9fe 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3905,10 +3905,13 @@
 
 int WebContentsImpl::CreateSwappedOutRenderView(
     SiteInstance* instance) {
-  return GetRenderManager()->CreateRenderFrame(
-      instance, MSG_ROUTING_NONE, CREATE_RF_SWAPPED_OUT |
-                                      CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
-                                      CREATE_RF_HIDDEN);
+  int render_view_routing_id = MSG_ROUTING_NONE;
+  GetRenderManager()->CreateRenderFrame(
+      instance, nullptr, MSG_ROUTING_NONE,
+      CREATE_RF_SWAPPED_OUT | CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
+          CREATE_RF_HIDDEN,
+      &render_view_routing_id);
+  return render_view_routing_id;
 }
 
 void WebContentsImpl::OnUserGesture() {
@@ -4080,17 +4083,22 @@
 
   // Create a swapped out RenderView in the given SiteInstance if none exists,
   // setting its opener to the given route_id.  Return the new view's route_id.
-  return GetRenderManager()->CreateRenderFrame(
-      instance, opener_route_id, CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
-                                     CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN);
+  int render_view_routing_id = MSG_ROUTING_NONE;
+  GetRenderManager()->CreateRenderFrame(instance, nullptr, opener_route_id,
+                                        CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
+                                            CREATE_RF_SWAPPED_OUT |
+                                            CREATE_RF_HIDDEN,
+                                        &render_view_routing_id);
+  return render_view_routing_id;
 }
 
 NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
   return GetController();
 }
 
-WebUIImpl* WebContentsImpl::CreateWebUIForRenderManager(const GURL& url) {
-  return static_cast<WebUIImpl*>(CreateWebUI(url));
+scoped_ptr<WebUIImpl> WebContentsImpl::CreateWebUIForRenderManager(
+    const GURL& url) {
+  return scoped_ptr<WebUIImpl>(static_cast<WebUIImpl*>(CreateWebUI(url)));
 }
 
 NavigationEntry*
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index c809f8d7..8e1c657 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -554,7 +554,7 @@
                                       bool is_main_frame) override;
   int CreateOpenerRenderViewsForRenderManager(SiteInstance* instance) override;
   NavigationControllerImpl& GetControllerForRenderManager() override;
-  WebUIImpl* CreateWebUIForRenderManager(const GURL& url) override;
+  scoped_ptr<WebUIImpl> CreateWebUIForRenderManager(const GURL& url) override;
   NavigationEntry* GetLastCommittedNavigationEntryForRenderManager() override;
   bool FocusLocationBarByDefault() override;
   void SetFocusToLocationBar(bool select_all) override;