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 52b3585d90da7f0b6c51427693b68534b69b698d..9d6fa02904b3dded88c2e18383bf2767a5a76c80 100644 |
--- a/content/browser/frame_host/render_frame_host_manager.cc |
+++ b/content/browser/frame_host/render_frame_host_manager.cc |
@@ -90,6 +90,7 @@ FrameHostMsg_BeginNavigation_Params MakeDefaultBeginNavigation( |
return begin_navigation_params; |
} |
+// static |
bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) { |
node->render_manager()->pending_delete_hosts_.clear(); |
return true; |
@@ -526,12 +527,10 @@ void RenderFrameHostManager::RendererProcessClosing( |
} |
} |
-void RenderFrameHostManager::SwapOutOldPage( |
- RenderFrameHostImpl* old_render_frame_host) { |
- TRACE_EVENT1("navigation", "RenderFrameHostManager::SwapOutOldPage", |
+void RenderFrameHostManager::SwapOutOldFrame( |
+ scoped_ptr<RenderFrameHostImpl> old_render_frame_host) { |
nasko
2014/10/02 16:04:02
I love that we are using scoped_ptrs more now. It
|
+ TRACE_EVENT1("navigation", "RenderFrameHostManager::SwapOutOldFrame", |
"FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); |
- // Should only see this while we have a pending renderer. |
- CHECK(cross_navigation_pending_); |
// Tell the renderer to suppress any further modal dialogs so that we can swap |
// it out. This must be done before canceling any current dialog, in case |
@@ -544,31 +543,90 @@ void RenderFrameHostManager::SwapOutOldPage( |
// no longer on the stack when we send the SwapOut message. |
delegate_->CancelModalDialogsForRenderManager(); |
- // Create the RenderFrameProxyHost that will replace the |
- // RenderFrameHost which is swapping out. If one exists, ensure it is deleted |
- // from the map and not leaked. |
- DeleteRenderFrameProxyHost(old_render_frame_host->GetSiteInstance()); |
+ // If the old RFH is not live, just return as there is no further work to do. |
+ // It will be deleted and there will be no proxy created. |
+ int32 old_site_instance_id = |
+ old_render_frame_host->GetSiteInstance()->GetId(); |
+ if (!old_render_frame_host->IsRenderFrameLive()) { |
+ ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id); |
+ return; |
+ } |
+ |
+ // If there are no active frames besides this one, we can delete the old |
+ // RenderFrameHost once it runs its unload handler, without replacing it with |
+ // a proxy. |
+ size_t active_frame_count = |
+ old_render_frame_host->GetSiteInstance()->active_frame_count(); |
+ if (active_frame_count <= 1) { |
+ // Tell the old RenderFrameHost to swap out, with no proxy to replace it. |
+ old_render_frame_host->SwapOut(NULL); |
+ MoveToPendingDeleteHosts(old_render_frame_host.Pass()); |
+ |
+ // Also clear out any proxies from this SiteInstance, in case this was the |
+ // last one keeping other proxies alive. |
+ ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id); |
+ return; |
+ } |
+ |
+ // Otherwise there are active views and we need a proxy for the old RFH. |
+ // (There should not be one yet.) |
+ CHECK(!GetRenderFrameProxyHost(old_render_frame_host->GetSiteInstance())); |
RenderFrameProxyHost* proxy = new RenderFrameProxyHost( |
old_render_frame_host->GetSiteInstance(), frame_tree_node_); |
- std::pair<RenderFrameProxyHostMap::iterator, bool> result = |
- proxy_hosts_.insert(std::make_pair( |
- old_render_frame_host->GetSiteInstance()->GetId(), proxy)); |
- CHECK(result.second) << "Inserting a duplicate item."; |
- |
- // Tell the old frame it is being swapped out. This will fire the unload |
- // handler in the background (without firing the beforeunload handler a second |
- // time). This is done right after we commit the new RenderFrameHost. |
+ CHECK(proxy_hosts_.insert(std::make_pair(old_site_instance_id, proxy)).second) |
+ << "Inserting a duplicate item."; |
+ |
+ // Tell the old RenderFrameHost to swap out and be replaced by the proxy. |
old_render_frame_host->SwapOut(proxy); |
+ |
+ bool is_main_frame = frame_tree_node_->IsMainFrame(); |
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && |
+ !is_main_frame) { |
+ // In --site-per-process, subframes delete their RFH rather than storing it |
+ // in the proxy. Schedule it for deletion once the SwapOutACK comes in. |
+ // TODO(creis): This will be the default when we remove swappedout://. |
+ MoveToPendingDeleteHosts(old_render_frame_host.Pass()); |
+ } else { |
+ // We shouldn't get here for subframes, since we only swap subframes when |
+ // --site-per-process is used. |
+ DCHECK(is_main_frame); |
+ |
+ // The old RenderFrameHost will stay alive inside the proxy so that existing |
+ // JavaScript window references to it stay valid. |
+ proxy->TakeFrameHostOwnership(old_render_frame_host.Pass()); |
+ } |
} |
-void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance( |
- int32 site_instance_id, |
- RenderFrameHostImpl* rfh) { |
- RFHPendingDeleteMap::iterator iter = |
- pending_delete_hosts_.find(site_instance_id); |
- if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh) |
- pending_delete_hosts_.erase(site_instance_id); |
+void RenderFrameHostManager::MoveToPendingDeleteHosts( |
+ scoped_ptr<RenderFrameHostImpl> render_frame_host) { |
+ // |render_frame_host| will be deleted when its SwapOut ACK is received, or |
+ // when the timer times out, or when the RFHM itself is deleted (whichever |
+ // comes first). |
+ pending_delete_hosts_.push_back( |
+ linked_ptr<RenderFrameHostImpl>(render_frame_host.release())); |
+} |
+ |
+bool RenderFrameHostManager::IsPendingDeletion( |
+ RenderFrameHostImpl* render_frame_host) { |
+ for (const auto& rfh : pending_delete_hosts_) { |
+ if (rfh == render_frame_host) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool RenderFrameHostManager::DeleteFromPendingList( |
+ RenderFrameHostImpl* render_frame_host) { |
+ for (RFHPendingDeleteList::iterator iter = pending_delete_hosts_.begin(); |
+ iter != pending_delete_hosts_.end(); |
+ iter++) { |
+ if (*iter == render_frame_host) { |
+ pending_delete_hosts_.erase(iter); |
+ return true; |
+ } |
+ } |
+ return false; |
} |
void RenderFrameHostManager::ResetProxyHosts() { |
@@ -709,6 +767,7 @@ void RenderFrameHostManager::Observe( |
} |
} |
+// static |
bool RenderFrameHostManager::ClearProxiesInSiteInstance( |
int32 site_instance_id, |
FrameTreeNode* node) { |
@@ -716,26 +775,15 @@ bool RenderFrameHostManager::ClearProxiesInSiteInstance( |
node->render_manager()->proxy_hosts_.find(site_instance_id); |
if (iter != node->render_manager()->proxy_hosts_.end()) { |
RenderFrameProxyHost* proxy = iter->second; |
- // If the RVH is pending swap out, it needs to switch state to |
- // pending shutdown. Otherwise it is deleted. |
- if (proxy->render_frame_host()->rfh_state() == |
+ // Delete the proxy. If it is for a main frame (and thus the RFH is stored |
+ // in the proxy) and it was still pending swap out, move the RFH to the |
+ // pending deletion list first. |
+ if (node->IsMainFrame() && |
+ proxy->render_frame_host()->rfh_state() == |
RenderFrameHostImpl::STATE_PENDING_SWAP_OUT) { |
scoped_ptr<RenderFrameHostImpl> swapped_out_rfh = |
proxy->PassFrameHostOwnership(); |
- |
- swapped_out_rfh->SetPendingShutdown(base::Bind( |
- &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance, |
- node->render_manager()->weak_factory_.GetWeakPtr(), |
- site_instance_id, |
- swapped_out_rfh.get())); |
- RFHPendingDeleteMap::iterator pending_delete_iter = |
- node->render_manager()->pending_delete_hosts_.find(site_instance_id); |
- if (pending_delete_iter == |
- node->render_manager()->pending_delete_hosts_.end() || |
- pending_delete_iter->second.get() != swapped_out_rfh) { |
- node->render_manager()->pending_delete_hosts_[site_instance_id] = |
- linked_ptr<RenderFrameHostImpl>(swapped_out_rfh.release()); |
- } |
+ node->render_manager()->MoveToPendingDeleteHosts(swapped_out_rfh.Pass()); |
} |
delete proxy; |
node->render_manager()->proxy_hosts_.erase(site_instance_id); |
@@ -1329,8 +1377,6 @@ void RenderFrameHostManager::CommitPending() { |
render_frame_host_->render_view_host()->GetView() && |
render_frame_host_->render_view_host()->GetView()->HasFocus(); |
- // TODO(creis): As long as show/hide are on RVH, we don't want to do them for |
- // subframe navigations or they'll interfere with the top-level page. |
bool is_main_frame = frame_tree_node_->IsMainFrame(); |
// Swap in the pending frame and make it active. Also ensure the FrameTree |
@@ -1343,34 +1389,25 @@ void RenderFrameHostManager::CommitPending() { |
// The process will no longer try to exit, so we can decrement the count. |
render_frame_host_->GetProcess()->RemovePendingView(); |
- // If the view is gone, then this RenderViewHost died while it was hidden. |
- // We ignored the RenderProcessGone call at the time, so we should send it now |
- // to make sure the sad tab shows up, etc. |
- if (!render_frame_host_->render_view_host()->GetView()) { |
- delegate_->RenderProcessGoneFromRenderManager( |
- render_frame_host_->render_view_host()); |
- } else if (!delegate_->IsHidden()) { |
+ // Show the new view (or a sad tab) if necessary. |
+ bool new_rfh_has_view = !!render_frame_host_->render_view_host()->GetView(); |
+ if (!delegate_->IsHidden() && new_rfh_has_view) { |
+ // In most cases, we need to show the new view. |
render_frame_host_->render_view_host()->GetView()->Show(); |
} |
- |
- // If the old frame is live, swap it out now that the new frame is visible. |
- int32 old_site_instance_id = |
- old_render_frame_host->GetSiteInstance()->GetId(); |
- if (old_render_frame_host->IsRenderFrameLive()) { |
- SwapOutOldPage(old_render_frame_host.get()); |
- |
- // Schedule the old frame to shut down after it swaps out, if there are no |
- // other active frames in its SiteInstance. |
- if (!old_render_frame_host->GetSiteInstance()->active_frame_count()) { |
- old_render_frame_host->SetPendingShutdown(base::Bind( |
- &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance, |
- weak_factory_.GetWeakPtr(), |
- old_site_instance_id, |
- old_render_frame_host.get())); |
- } |
+ if (!new_rfh_has_view) { |
+ // If the view is gone, then this RenderViewHost died while it was hidden. |
+ // We ignored the RenderProcessGone call at the time, so we should send it |
+ // now to make sure the sad tab shows up, etc. |
+ DCHECK(!render_frame_host_->IsRenderFrameLive()); |
+ DCHECK(!render_frame_host_->render_view_host()->IsRenderViewLive()); |
+ delegate_->RenderProcessGoneFromRenderManager( |
+ render_frame_host_->render_view_host()); |
} |
// For top-level frames, also hide the old RenderViewHost's view. |
+ // TODO(creis): As long as show/hide are on RVH, we don't want to hide on |
+ // subframe navigations or we will interfere with the top-level frame. |
if (is_main_frame && old_render_frame_host->render_view_host()->GetView()) |
old_render_frame_host->render_view_host()->GetView()->Hide(); |
@@ -1389,72 +1426,23 @@ void RenderFrameHostManager::CommitPending() { |
delegate_->NotifySwappedFromRenderManager( |
old_render_frame_host.get(), render_frame_host_.get(), is_main_frame); |
- // If the old RFH is not live, just return as there is no further work to do. |
- if (!old_render_frame_host->IsRenderFrameLive()) |
- return; |
- |
- // If the old RFH is live, we are swapping it out and should keep track of |
- // it in case we navigate back to it, or it is waiting for the unload event |
- // to execute in the background. |
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) { |
- DCHECK(old_render_frame_host->is_swapped_out() || |
- !RenderFrameHostImpl::IsRFHStateActive( |
- old_render_frame_host->rfh_state())); |
- } |
- |
- // If the RenderViewHost backing the RenderFrameHost is pending shutdown, |
- // the RenderFrameHost should be put in the map of RenderFrameHosts pending |
- // shutdown. Otherwise, it is stored in the map of proxy hosts. |
- if (old_render_frame_host->rfh_state() == |
- RenderFrameHostImpl::STATE_PENDING_SHUTDOWN) { |
- // The proxy for this RenderFrameHost is created when sending the |
- // SwapOut message, so check if it already exists and delete it. |
- RenderFrameProxyHostMap::iterator iter = |
- proxy_hosts_.find(old_site_instance_id); |
- if (iter != proxy_hosts_.end()) { |
- delete iter->second; |
- proxy_hosts_.erase(iter); |
- } |
- RFHPendingDeleteMap::iterator pending_delete_iter = |
- pending_delete_hosts_.find(old_site_instance_id); |
- if (pending_delete_iter == pending_delete_hosts_.end() || |
- pending_delete_iter->second.get() != old_render_frame_host) { |
- pending_delete_hosts_[old_site_instance_id] = |
- linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release()); |
- } |
- } else { |
- CHECK(proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId()) == |
- proxy_hosts_.end()); |
- |
- // Capture the active frame count on the old RFH SiteInstance, since the |
- // ownership might be passed into the proxy and the pointer will be |
- // invalid. |
- int active_frame_count = |
- old_render_frame_host->GetSiteInstance()->active_frame_count(); |
- |
- if (is_main_frame) { |
- RenderFrameProxyHostMap::iterator iter = |
- proxy_hosts_.find(old_site_instance_id); |
- CHECK(iter != proxy_hosts_.end()); |
- iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass()); |
- } |
- |
- // If there are no active frames in this SiteInstance, it means that |
- // this RFH was the last active one in the SiteInstance. Now that we |
- // know that all RFHs are swapped out, we can delete all the RFPHs and |
- // RVHs in this SiteInstance. |
- if (!active_frame_count) { |
- ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id); |
- } |
- } |
+ // Swap out the old frame now that the new one is visible. |
+ // This will swap it out and then put it on the proxy list (if there are other |
+ // active views in its SiteInstance) or schedule it for deletion when the swap |
+ // out ack arrives (or immediately if the process isn't live). |
+ // In the --site-per-process case, old subframe RHFs are not kept alive inside |
+ // the proxy. |
+ SwapOutOldFrame(old_render_frame_host.Pass()); |
// If this is a subframe, it should have a CrossProcessFrameConnector |
- // created already and we just need to link it to the proper view in the |
- // new process. |
- if (!is_main_frame) { |
- RenderFrameProxyHost* proxy = GetProxyToParent(); |
- if (proxy) { |
- proxy->SetChildRWHView( |
+ // created already. Use it to link the new RFH's view to the proxy that |
+ // belongs to the parent frame's SiteInstance. (We do this after swapping out |
nasko
2014/10/02 16:04:02
nit: I'd put the sentence in () on a new line star
Charlie Reis
2014/10/02 19:41:19
Done.
|
+ // the old RFH because that may create the proxy we're looking for.) |
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && |
+ !is_main_frame) { |
+ RenderFrameProxyHost* proxy_to_parent = GetProxyToParent(); |
+ if (proxy_to_parent) { |
+ proxy_to_parent->SetChildRWHView( |
render_frame_host_->render_view_host()->GetView()); |
} |
} |