Index: content/browser/tab_contents/render_view_host_manager.cc |
diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc |
index 973a1d0e7832c4490cc74e698f2fce67dfc8d133..d06ccf53afe70d572d8491ef56e234636ac5621c 100644 |
--- a/content/browser/tab_contents/render_view_host_manager.cc |
+++ b/content/browser/tab_contents/render_view_host_manager.cc |
@@ -49,6 +49,13 @@ RenderViewHostManager::~RenderViewHostManager() { |
RenderViewHost* render_view_host = render_view_host_; |
render_view_host_ = NULL; |
render_view_host->Shutdown(); |
+ |
+ // Shut down any swapped out RenderViewHosts. |
+ for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin(); |
+ iter != swapped_out_hosts_.end(); |
+ ++iter) { |
+ iter->second->Shutdown(); |
+ } |
} |
void RenderViewHostManager::Init(Profile* profile, |
@@ -148,21 +155,17 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { |
if (pending_render_view_host_->are_navigations_suspended()) |
pending_render_view_host_->SetNavigationsSuspended(false); |
} else { |
- // The request has been started and paused, while we're waiting for the |
+ // The request has been started and paused while we're waiting for the |
// unload handler to finish. We'll pretend that it did, by notifying the |
// IO thread to let the response continue. The pending renderer will then |
// be swapped in as part of the usual DidNavigate logic. (If the unload |
// handler later finishes, this call will be ignored because the state in |
// CrossSiteResourceHandler will already be cleaned up.) |
- ViewMsg_ClosePage_Params params; |
- params.closing_process_id = |
- render_view_host_->process()->id(); |
- params.closing_route_id = render_view_host_->routing_id(); |
- params.for_cross_site_transition = true; |
+ ViewMsg_SwapOut_Params params; |
params.new_render_process_host_id = |
pending_render_view_host_->process()->id(); |
params.new_request_id = pending_request_id; |
- current_host()->process()->CrossSiteClosePageACK(params); |
+ current_host()->process()->CrossSiteSwapOutACK(params); |
} |
return false; |
} |
@@ -244,7 +247,7 @@ void RenderViewHostManager::ShouldClosePage(bool for_cross_site_transition, |
if (proceed_to_fire_unload) { |
// This is not a cross-site navigation, the tab is being closed. |
- render_view_host_->ClosePage(false, -1, -1); |
+ render_view_host_->ClosePage(); |
} |
} |
} |
@@ -256,12 +259,12 @@ void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, |
return; |
DCHECK(pending_render_view_host_); |
- // Tell the old renderer to run its onunload handler. When it finishes, it |
- // will send a ClosePage_ACK to the ResourceDispatcherHost with the given |
- // IDs (of the pending RVH's request), allowing the pending RVH's response to |
- // resume. |
- render_view_host_->ClosePage(true, |
- new_render_process_host_id, new_request_id); |
+ // Tell the old renderer it is being swapped out. This will fire the unload |
+ // handler (without firing the beforeunload handler a second time). When the |
+ // unload handler finishes and the navigation completes, we will send a |
+ // message to the ResourceDispatcherHost with the given pending request IDs, |
+ // allowing the pending RVH's response to resume. |
+ render_view_host_->SwapOut(new_render_process_host_id, new_request_id); |
// ResourceDispatcherHost has told us to run the onunload handler, which |
// means it is not a download or unsafe page, and we are going to perform the |
@@ -459,6 +462,17 @@ bool RenderViewHostManager::CreatePendingRenderView( |
// we're about to switch away, so that it sends an UpdateState message. |
} |
+ // Check if we've already created an RVH for this SiteInstance. |
+ CHECK(instance); |
+ RenderViewHostMap::iterator iter = |
+ swapped_out_hosts_.find(instance->id()); |
+ if (iter != swapped_out_hosts_.end()) { |
+ // Re-use the existing RenderViewHost, which has already been initialized. |
+ // We'll remove it from the list of swapped out hosts if it commits. |
+ pending_render_view_host_ = iter->second; |
+ return true; |
+ } |
+ |
pending_render_view_host_ = RenderViewHostFactory::Create( |
instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_-> |
GetControllerForRenderManager().session_storage_namespace()); |
@@ -515,9 +529,7 @@ void RenderViewHostManager::CommitPending() { |
bool focus_render_view = !will_focus_location_bar && |
render_view_host_->view() && render_view_host_->view()->HasFocus(); |
- // Hide the current view and prepare to destroy it. |
- // TODO(creis): Get the old RenderViewHost to send us an UpdateState message |
- // before we destroy it. |
+ // Hide the current view and prepare to swap it out. |
if (render_view_host_->view()) |
render_view_host_->view()->Hide(); |
RenderViewHost* old_render_view_host = render_view_host_; |
@@ -526,6 +538,13 @@ void RenderViewHostManager::CommitPending() { |
render_view_host_ = pending_render_view_host_; |
pending_render_view_host_ = NULL; |
+ // If the pending view was on the swapped out list, we can remove it. |
+ RenderViewHostMap::iterator iter = swapped_out_hosts_.find( |
+ render_view_host_->site_instance()->id()); |
+ if (iter != swapped_out_hosts_.end()) { |
+ swapped_out_hosts_.erase(iter); |
+ } |
+ |
// If the view is gone, then this RenderViewHost died while it was hidden. |
// We ignored the RenderViewGone call at the time, so we should send it now |
// to make sure the sad tab shows up, etc. |
@@ -550,7 +569,9 @@ void RenderViewHostManager::CommitPending() { |
Source<NavigationController>(&delegate_->GetControllerForRenderManager()), |
Details<RenderViewHostSwitchedDetails>(&details)); |
- old_render_view_host->Shutdown(); |
+ // Keep track of the old swapped out RVH in case we navigate back to it. |
+ swapped_out_hosts_[old_render_view_host->site_instance()->id()] = |
+ old_render_view_host; |
// Let the task manager know that we've swapped RenderViewHosts, since it |
// might need to update its process groupings. |
@@ -661,7 +682,11 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateForNavigate( |
void RenderViewHostManager::CancelPending() { |
RenderViewHost* pending_render_view_host = pending_render_view_host_; |
pending_render_view_host_ = NULL; |
- pending_render_view_host->Shutdown(); |
+ |
+ // Only shutdown the pending RVH if it isn't currently swapped out. |
+ // This can happen if we abort a pending load. |
+ if (!IsSwappedOut(pending_render_view_host)) |
+ pending_render_view_host->Shutdown(); |
pending_web_ui_.reset(); |
} |
@@ -681,9 +706,10 @@ void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { |
} |
void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { |
+ // TODO(creis): Abstract out the common code between this and CommitPending. |
web_ui_.reset(); |
- // Hide the current view and prepare to destroy it. |
+ // Hide the current view and prepare to swap it out. |
if (render_view_host_->view()) |
render_view_host_->view()->Hide(); |
RenderViewHost* old_render_view_host = render_view_host_; |
@@ -704,6 +730,13 @@ void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { |
render_view_host_->view()->Show(); |
} |
+ // If the given RVH was on the swapped out list, we can remove it. |
+ RenderViewHostMap::iterator iter = swapped_out_hosts_.find( |
+ render_view_host_->site_instance()->id()); |
+ if (iter != swapped_out_hosts_.end()) { |
+ swapped_out_hosts_.erase(iter); |
+ } |
+ |
delegate_->UpdateRenderViewSizeForRenderManager(); |
RenderViewHostSwitchedDetails details; |
@@ -714,10 +747,19 @@ void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { |
Source<NavigationController>(&delegate_->GetControllerForRenderManager()), |
Details<RenderViewHostSwitchedDetails>(&details)); |
- // This will cause the old RenderViewHost to delete itself. |
- old_render_view_host->Shutdown(); |
+ // Keep track of the old swapped out RVH in case we navigate back to it. |
+ swapped_out_hosts_[old_render_view_host->site_instance()->id()] = |
+ old_render_view_host; |
// Let the task manager know that we've swapped RenderViewHosts, since it |
// might need to update its process groupings. |
delegate_->NotifySwappedFromRenderManager(); |
} |
+ |
+bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) { |
+ if (!rvh->site_instance()) |
+ return false; |
+ |
+ return swapped_out_hosts_.find(rvh->site_instance()->id()) != |
+ swapped_out_hosts_.end(); |
+} |