Chromium Code Reviews| Index: content/browser/frame_host/render_frame_host_manager.cc |
| diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc |
| index 49b9495e32d2cb4d0da64a6b03a606afce8c3006..2086703305b9204d398449b83ec8289807e06e0b 100644 |
| --- a/content/browser/frame_host/render_frame_host_manager.cc |
| +++ b/content/browser/frame_host/render_frame_host_manager.cc |
| @@ -69,6 +69,11 @@ RenderFrameHostManager::~RenderFrameHostManager() { |
| if (pending_render_frame_host_) |
| CancelPending(); |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + CleanUpSpeculativeRenderFrameHost(); |
| + } |
| + |
| // We should always have a current RenderFrameHost except in some tests. |
| SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>()); |
| @@ -307,6 +312,10 @@ void RenderFrameHostManager::OnBeforeUnloadACK( |
| // Current page says to cancel. |
| CancelPending(); |
| cross_navigation_pending_ = false; |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + CleanUpSpeculativeRenderFrameHost(); |
| + } |
| } |
| } else { |
| // Non-cross site transition means closing the entire tab. |
| @@ -321,6 +330,10 @@ void RenderFrameHostManager::OnBeforeUnloadACK( |
| if (pending_render_frame_host_) { |
| CancelPending(); |
| cross_navigation_pending_ = false; |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + CleanUpSpeculativeRenderFrameHost(); |
| + } |
| } |
| // This is not a cross-site navigation, the tab is being closed. |
| @@ -419,6 +432,16 @@ void RenderFrameHostManager::ClearNavigationTransitionData() { |
| void RenderFrameHostManager::DidNavigateFrame( |
| RenderFrameHostImpl* render_frame_host) { |
| + DCHECK(render_frame_host); |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + if (speculative_render_frame_host_.get() == render_frame_host) { |
| + CommitPending(true); |
| + return; |
| + } |
| + CleanUpSpeculativeRenderFrameHost(); |
| + } |
| + |
| if (!cross_navigation_pending_) { |
| DCHECK(!pending_render_frame_host_); |
| @@ -427,13 +450,13 @@ void RenderFrameHostManager::DidNavigateFrame( |
| // Even when there is no pending RVH, there may be a pending Web UI. |
| if (pending_web_ui()) |
| - CommitPending(); |
| + CommitPending(false); |
| return; |
| } |
| if (render_frame_host == pending_render_frame_host_) { |
| // The pending cross-site navigation completed, so show the renderer. |
| - CommitPending(); |
| + CommitPending(false); |
| cross_navigation_pending_ = false; |
| } else if (render_frame_host == render_frame_host_) { |
| // A navigation in the original page has taken place. Cancel the pending |
| @@ -446,6 +469,10 @@ void RenderFrameHostManager::DidNavigateFrame( |
| } |
| } |
| +void RenderFrameHostManager::CancelNavigation() { |
| + CleanUpSpeculativeRenderFrameHost(); |
| +} |
| + |
| void RenderFrameHostManager::DidDisownOpener( |
| RenderFrameHost* render_frame_host) { |
| // Notify all RenderFrameHosts but the one that notified us. This is necessary |
| @@ -559,6 +586,30 @@ void RenderFrameHostManager::SwapOutOldFrame( |
| } |
| } |
| +void RenderFrameHostManager::RecycleRenderFrameHost( |
| + 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 |
| @@ -594,6 +645,152 @@ void RenderFrameHostManager::ResetProxyHosts() { |
| STLDeleteValues(&proxy_hosts_); |
| } |
| +void RenderFrameHostManager::BeginNavigation( |
| + const FrameHostMsg_BeginNavigation_Params& params, |
| + const CommonNavigationParams& common_params) { |
| + CHECK(CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)); |
| + // If there is an ongoing navigation, just clean it up. |
|
clamy
2014/11/14 10:11:09
nit: s/just clean it up/cancel it
carlosk
2014/11/14 17:43:37
Done.
|
| + CancelNavigation(); |
| + |
| + SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); |
| + // TODO(carlosk): Replace the default values by the right ones. |
| + scoped_refptr<SiteInstanceImpl> new_instance = |
| + static_cast<SiteInstanceImpl*>(GetSiteInstanceForNavigation( |
| + common_params.url, NULL, common_params.transition, false, false, |
| + true)); |
| + |
| + if (new_instance.get() != current_instance) { |
| + // Navigating to a new SiteInstance -> speculatively create a new RFH |
| + |
| + // TODO(carlosk): what the TRACE_EVENT_INSTANT2 for New SiteInstance found |
| + // in UpdateStateForNavigate be copied here? |
| + |
| + bool success = CreateSpeculativeRenderFrameHost( |
| + common_params.url, current_instance, new_instance.get()); |
| + if (!success) |
| + return; |
| + } else { |
| + // Navigating to the same SiteInstance -> make sure the current RFH is alive |
| + DCHECK(render_frame_host_->GetSiteInstance() == new_instance); |
| + if (!render_frame_host_->render_view_host()->IsRenderViewLive()) { |
| + // Recreate the opener chain. |
| + int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager( |
| + render_frame_host_->GetSiteInstance()); |
| + if (!InitRenderView(render_frame_host_->render_view_host(), |
| + opener_route_id, MSG_ROUTING_NONE, |
| + frame_tree_node_->IsMainFrame())) { |
| + return; |
| + } |
| + } |
| + } |
| + DCHECK(new_instance->GetProcess()->HasConnection()); |
| + DCHECK(new_instance->GetProcess()->GetBrowserContext()); |
| +} |
| + |
| +bool RenderFrameHostManager::CreateSpeculativeRenderFrameHost( |
| + const GURL& url, |
| + SiteInstance* old_instance, |
| + SiteInstance* new_instance) { |
| + CHECK(new_instance); |
| + CHECK_NE(old_instance, new_instance); |
| + |
| + // TODO(carlosk): should also try to reuse the current web_ui |
| + // (ShouldReuseWebUI)? |
| + scoped_ptr<WebUIImpl> new_web_ui(delegate_->CreateWebUIForRenderManager(url)); |
| + // TODO(carlosk): confirm this next section copied from SetPendingWebUI |
| + // is in fact needed... I need access to the respective navigation entry |
| + // though. |
| + // 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 (new_web_ui && |
| + // bindings != NavigationEntryImpl::kInvalidBindings && |
| + // new_web_ui->GetBindings() != bindings) { |
| + // RecordAction( |
| + // base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM")); |
| + // new_web_ui.reset(); |
| + // } |
| + |
| + scoped_ptr<RenderFrameHostImpl> new_render_frame_host; |
| + |
| + // Check if we've already created an RFH for this SiteInstance. If so, try |
| + // 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(new_instance); |
| + if (proxy && proxy->render_frame_host()) { |
| + // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost. |
| + // Prevent the process from exiting while we're trying to use it. |
| + new_render_frame_host = proxy->PassFrameHostOwnership(); |
| + new_render_frame_host->GetProcess()->AddPendingView(); |
| + |
| + proxy_hosts_.erase(new_instance->GetId()); |
| + delete proxy; |
| + |
| + // When a new render view is created by the renderer, the new WebContents |
| + // 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 (new_web_ui && !new_render_frame_host->GetProcess()->IsIsolatedGuest()) { |
| + int required_bindings = new_web_ui->GetBindings(); |
| + RenderViewHost* rvh = new_render_frame_host->render_view_host(); |
| + if ((rvh->GetEnabledBindings() & required_bindings) != |
| + required_bindings) { |
| + rvh->AllowBindings(required_bindings); |
| + } |
| + } |
| + } else { |
| + // Create a new RenderFrameHost if we don't find an existing one. |
| + new_render_frame_host = |
| + CreateRenderFrameHost(new_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, |
| + false, delegate_->IsHidden()); |
| + DCHECK(new_render_frame_host); |
| + RenderViewHostImpl* rvh = new_render_frame_host->render_view_host(); |
| + |
| + // Prevent the process from exiting while we're trying to navigate in it. |
| + // Otherwise, if the new RFH is swapped out already, store it. |
| + new_render_frame_host->GetProcess()->AddPendingView(); |
| + |
| + // 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). |
| + int opener_route_id = MSG_ROUTING_NONE; |
| + if (new_instance->IsRelatedSiteInstance(old_instance)) { |
| + opener_route_id = |
| + delegate_->CreateOpenerRenderViewsForRenderManager(new_instance); |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kSitePerProcess)) { |
| + // Ensure that the frame tree has RenderFrameProxyHosts for the new |
| + // SiteInstance in all nodes except the current one. |
| + frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance( |
| + frame_tree_node_, new_instance); |
| + } |
| + } |
| + |
| + bool success = InitRenderView(rvh, opener_route_id, MSG_ROUTING_NONE, |
| + frame_tree_node_->IsMainFrame()); |
| + if (success) { |
| + if (frame_tree_node_->IsMainFrame()) { |
| + // Don't show the main frame's view until we know it will be used. |
| + rvh->GetView()->Hide(); |
| + } else { |
| + // Init the RFH, so a RenderFrame is created in the renderer. |
| + success = InitRenderFrame(new_render_frame_host.get()); |
| + } |
| + } |
| + if (!success) |
| + return false; |
| + |
| + render_frame_delegate_->RenderFrameCreated(new_render_frame_host.get()); |
| + } |
| + |
| + DCHECK(new_render_frame_host->GetSiteInstance() == new_instance); |
| + speculative_render_frame_host_.reset(new_render_frame_host.release()); |
| + speculative_web_ui_.reset(new_web_ui.release()); |
| + return true; |
| +} |
| + |
| // PlzNavigate |
| RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation( |
| const GURL& url, |
| @@ -757,7 +954,8 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation( |
| SiteInstance* dest_instance, |
| ui::PageTransition dest_transition, |
| bool dest_is_restore, |
| - bool dest_is_view_source_mode) { |
| + bool dest_is_view_source_mode, |
| + bool create_unbounded_site_instance) { |
| SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); |
| SiteInstance* new_instance = current_instance; |
| @@ -789,13 +987,9 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation( |
| dest_is_view_source_mode); |
| if (ShouldTransitionCrossSite() || force_swap) { |
| new_instance = GetSiteInstanceForURL( |
| - dest_url, |
| - dest_instance, |
| - dest_transition, |
| - dest_is_restore, |
| - dest_is_view_source_mode, |
| - current_instance, |
| - force_swap); |
| + dest_url, dest_instance, dest_transition, dest_is_restore, |
| + dest_is_view_source_mode, current_instance, force_swap, |
| + create_unbounded_site_instance); |
| } |
| // If force_swap is true, we must use a different SiteInstance. If we didn't, |
| @@ -813,7 +1007,8 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( |
| bool dest_is_restore, |
| bool dest_is_view_source_mode, |
| SiteInstance* current_instance, |
| - bool force_browsing_instance_swap) { |
| + bool force_browsing_instance_swap, |
| + bool create_unbounded_site_instance) { |
| NavigationControllerImpl& controller = |
| delegate_->GetControllerForRenderManager(); |
| BrowserContext* browser_context = controller.GetBrowserContext(); |
| @@ -828,10 +1023,16 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( |
| return dest_instance; |
| } |
| + SiteInstanceImpl* current_site_instance = |
| + static_cast<SiteInstanceImpl*>(current_instance); |
| + |
| // If a swap is required, we need to force the SiteInstance AND |
| // BrowsingInstance to be different ones, using CreateForURL. |
| - if (force_browsing_instance_swap) |
| - return SiteInstance::CreateForURL(browser_context, dest_url); |
| + if (force_browsing_instance_swap) { |
| + return CreateSiteInstanceForURL(browser_context, dest_url, |
| + create_unbounded_site_instance, |
| + current_site_instance); |
| + } |
| // (UGLY) HEURISTIC, process-per-site only: |
| // |
| @@ -849,9 +1050,6 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( |
| return current_instance; |
| } |
| - SiteInstanceImpl* current_site_instance = |
| - static_cast<SiteInstanceImpl*>(current_instance); |
| - |
| // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it |
| // for this entry. We won't commit the SiteInstance to this site until the |
| // navigation commits (in DidNavigate), unless the navigation entry was |
| @@ -873,28 +1071,36 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( |
| RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url); |
| if (current_site_instance->HasRelatedSiteInstance(dest_url) || |
| use_process_per_site) { |
| - return current_site_instance->GetRelatedSiteInstance(dest_url); |
| + return GetRelatedSiteInstanceForURL(current_site_instance, dest_url, |
| + create_unbounded_site_instance); |
| } |
| // For extensions, Web UI URLs (such as the new tab page), and apps we do |
| // not want to use the current_instance if it has no site, since it will |
| // have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance for |
| // this URL instead (with the correct process type). |
| - if (current_site_instance->HasWrongProcessForURL(dest_url)) |
| - return current_site_instance->GetRelatedSiteInstance(dest_url); |
| + if (current_site_instance->HasWrongProcessForURL(dest_url)) { |
| + return GetRelatedSiteInstanceForURL(current_site_instance, dest_url, |
| + create_unbounded_site_instance); |
| + } |
| // View-source URLs must use a new SiteInstance and BrowsingInstance. |
| // TODO(nasko): This is the same condition as later in the function. This |
| // should be taken into account when refactoring this method as part of |
| // http://crbug.com/123007. |
| - if (dest_is_view_source_mode) |
| - return SiteInstance::CreateForURL(browser_context, dest_url); |
| + if (dest_is_view_source_mode) { |
| + return CreateSiteInstanceForURL(browser_context, dest_url, |
| + create_unbounded_site_instance, |
| + current_site_instance); |
| + } |
| // If we are navigating from a blank SiteInstance to a WebUI, make sure we |
| // create a new SiteInstance. |
| if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( |
| browser_context, dest_url)) { |
| - return SiteInstance::CreateForURL(browser_context, dest_url); |
| + return CreateSiteInstanceForURL(browser_context, dest_url, |
| + create_unbounded_site_instance, |
| + current_site_instance); |
| } |
| // Normally the "site" on the SiteInstance is set lazily when the load |
| @@ -944,7 +1150,9 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( |
| if (current_entry && |
| current_entry->IsViewSourceMode() != dest_is_view_source_mode && |
| !IsRendererDebugURL(dest_url)) { |
| - return SiteInstance::CreateForURL(browser_context, dest_url); |
| + return CreateSiteInstanceForURL(browser_context, dest_url, |
| + create_unbounded_site_instance, |
| + current_site_instance); |
| } |
| // Use the current SiteInstance for same site navigations, as long as the |
| @@ -962,6 +1170,51 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( |
| // SiteInstance to a RenderViewHost (if it is different than our current |
| // SiteInstance), so that it is ref counted. This will happen in |
| // CreateRenderView. |
| + return GetRelatedSiteInstanceForURL(current_site_instance, dest_url, |
| + create_unbounded_site_instance); |
| +} |
| + |
| +SiteInstance* RenderFrameHostManager::CreateSiteInstanceForURL( |
| + BrowserContext* browser_context, |
| + const GURL& dest_url, |
| + bool create_unbounded_site_instance, |
| + SiteInstanceImpl* current_instance) { |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + if (create_unbounded_site_instance) { |
| + return SiteInstance::Create(browser_context); |
| + } |
| + if (speculative_render_frame_host_) { |
| + SiteInstanceImpl* sii = speculative_render_frame_host_->GetSiteInstance(); |
| + if (!sii->HasSite() && !sii->IsRelatedSiteInstance(current_instance)) { |
| + return sii; |
| + } |
| + } |
| + } |
| + |
| + return SiteInstance::CreateForURL(browser_context, dest_url); |
| +} |
| + |
| +SiteInstance* RenderFrameHostManager::GetRelatedSiteInstanceForURL( |
| + SiteInstanceImpl* current_instance, |
| + const GURL& dest_url, |
| + bool create_unbounded_site_instance) { |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + if (!current_instance->HasRelatedSiteInstance(dest_url)) { |
| + if (create_unbounded_site_instance) { |
| + return current_instance->GetRelatedEmptySiteInstance(); |
| + } |
| + if (speculative_render_frame_host_) { |
| + SiteInstanceImpl* sii = |
| + speculative_render_frame_host_->GetSiteInstance(); |
| + if (!sii->HasSite() && sii->IsRelatedSiteInstance(current_instance)) { |
| + return sii; |
| + } |
| + } |
| + } |
| + } |
| + |
| return current_instance->GetRelatedSiteInstance(dest_url); |
| } |
| @@ -1197,10 +1450,9 @@ bool RenderFrameHostManager::InitRenderView( |
| } |
| } |
| - return delegate_->CreateRenderViewForRenderManager(render_view_host, |
| - opener_route_id, |
| - proxy_routing_id, |
| - for_main_frame_navigation); |
| + return delegate_->CreateRenderViewForRenderManager( |
| + render_view_host, opener_route_id, proxy_routing_id, |
| + for_main_frame_navigation); |
| } |
| bool RenderFrameHostManager::InitRenderFrame( |
| @@ -1246,32 +1498,42 @@ int RenderFrameHostManager::GetRoutingIdForSiteInstance( |
| return MSG_ROUTING_NONE; |
| } |
| -void RenderFrameHostManager::CommitPending() { |
| +void RenderFrameHostManager::CommitPending(bool use_speculative_rfh) { |
| TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending", |
| "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); |
| + // If use_speculative_rfh then kEnableBrowserSideNavigation must be enabled. |
| + CHECK(!use_speculative_rfh || |
| + CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)); |
| + |
| // First check whether we're going to want to focus the location bar after |
| // this commit. We do this now because the navigation hasn't formally |
| // committed yet, so if we've already cleared |pending_web_ui_| the call chain |
| // this triggers won't be able to figure out what's going on. |
| bool will_focus_location_bar = delegate_->FocusLocationBarByDefault(); |
| - // Next commit the Web UI, if any. Either replace |web_ui_| with |
| - // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or |
| - // leave |web_ui_| as is if reusing it. |
| - DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get())); |
| - if (pending_web_ui_) { |
| - web_ui_.reset(pending_web_ui_.release()); |
| - } else if (!pending_and_current_web_ui_.get()) { |
| - web_ui_.reset(); |
| + if (!use_speculative_rfh) { |
| + DCHECK(!speculative_web_ui_); |
| + // Next commit the Web UI, if any. Either replace |web_ui_| with |
| + // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or |
| + // leave |web_ui_| as is if reusing it. |
| + DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get())); |
| + if (pending_web_ui_) { |
| + web_ui_.reset(pending_web_ui_.release()); |
| + } else if (!pending_and_current_web_ui_.get()) { |
| + web_ui_.reset(); |
| + } else { |
| + DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get()); |
| + pending_and_current_web_ui_.reset(); |
| + } |
| } else { |
| - DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get()); |
| - pending_and_current_web_ui_.reset(); |
| + web_ui_.reset(speculative_web_ui_.release()); |
| } |
| // It's possible for the pending_render_frame_host_ to be NULL when we aren't |
| // crossing process boundaries. If so, we just needed to handle the Web UI |
| // committing above and we're done. |
| - if (!pending_render_frame_host_) { |
| + if (!pending_render_frame_host_ && !use_speculative_rfh) { |
| if (will_focus_location_bar) |
| delegate_->SetFocusToLocationBar(false); |
| return; |
| @@ -1285,10 +1547,19 @@ void RenderFrameHostManager::CommitPending() { |
| bool is_main_frame = frame_tree_node_->IsMainFrame(); |
| - // Swap in the pending frame and make it active. Also ensure the FrameTree |
| - // stays in sync. |
| - scoped_ptr<RenderFrameHostImpl> old_render_frame_host = |
| - SetRenderFrameHost(pending_render_frame_host_.Pass()); |
| + scoped_ptr<RenderFrameHostImpl> old_render_frame_host; |
| + if (!use_speculative_rfh) { |
| + DCHECK(!speculative_render_frame_host_); |
| + // Swap in the pending frame and make it active. Also ensure the FrameTree |
| + // stays in sync. |
| + old_render_frame_host = |
| + SetRenderFrameHost(pending_render_frame_host_.Pass()); |
| + } else { |
| + DCHECK(speculative_render_frame_host_); |
| + old_render_frame_host = |
| + SetRenderFrameHost(speculative_render_frame_host_.Pass()); |
| + } |
| + |
| if (is_main_frame) |
| render_frame_host_->render_view_host()->AttachToFrameTree(); |
| @@ -1415,7 +1686,15 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); |
| scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation( |
| - url, instance, transition, is_restore, is_view_source_mode); |
| + url, instance, transition, is_restore, is_view_source_mode, false); |
| + |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation) && |
| + speculative_render_frame_host_) { |
| + if (speculative_render_frame_host_->GetSiteInstance() == new_instance) |
| + return speculative_render_frame_host_.get(); |
| + CleanUpSpeculativeRenderFrameHost(); |
| + } |
| const NavigationEntry* current_entry = |
| delegate_->GetLastCommittedNavigationEntryForRenderManager(); |
| @@ -1452,7 +1731,7 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| // navigate. Just switch to the pending RFH now and go back to non |
| // cross-navigating (Note that we don't care about on{before}unload |
| // handlers if the current RFH isn't live.) |
| - CommitPending(); |
| + CommitPending(false); |
| return render_frame_host_.get(); |
| } else { |
| NOTREACHED(); |
| @@ -1557,29 +1836,23 @@ void RenderFrameHostManager::CancelPending() { |
| // 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(); |
| - } |
| + RecycleRenderFrameHost(pending_render_frame_host.Pass()); |
| pending_web_ui_.reset(); |
| pending_and_current_web_ui_.reset(); |
| } |
| +void RenderFrameHostManager::CleanUpSpeculativeRenderFrameHost() { |
| + CHECK(CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)); |
| + if (speculative_render_frame_host_) { |
| + speculative_render_frame_host_->GetProcess()->RemovePendingView(); |
| + RecycleRenderFrameHost(speculative_render_frame_host_.Pass()); |
| + } |
| + if (speculative_web_ui_) |
| + speculative_web_ui_.reset(); |
| +} |
| + |
| scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost( |
| scoped_ptr<RenderFrameHostImpl> render_frame_host) { |
| // Swap the two. |