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 06ab825123e4b1fd294dd577e6aee18ab9ff94fe..990ba4334ff9d479f0409c0d2a708324ec94b99e 100644 |
| --- a/content/browser/frame_host/render_frame_host_manager.cc |
| +++ b/content/browser/frame_host/render_frame_host_manager.cc |
| @@ -61,7 +61,8 @@ RenderFrameHostManager::RenderFrameHostManager( |
| render_view_delegate_(render_view_delegate), |
| render_widget_delegate_(render_widget_delegate), |
| interstitial_page_(NULL), |
| - weak_factory_(this) { |
| + weak_factory_(this), |
|
Charlie Reis
2014/12/04 21:46:28
weak_factory_ must be last.
carlosk
2014/12/09 07:55:41
Done.
|
| + should_reuse_web_ui_(false) { |
| DCHECK(frame_tree_node_); |
| } |
| @@ -69,6 +70,11 @@ RenderFrameHostManager::~RenderFrameHostManager() { |
| if (pending_render_frame_host_) |
| CancelPending(); |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + CleanUpNavigation(); |
| + } |
| + |
| // We should always have a current RenderFrameHost except in some tests. |
| SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>()); |
| @@ -288,6 +294,8 @@ void RenderFrameHostManager::OnBeforeUnloadACK( |
| bool proceed, |
| const base::TimeTicks& proceed_time) { |
| if (for_cross_site_transition) { |
| + DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)); |
| // Ignore if we're not in a cross-site navigation. |
| if (!cross_navigation_pending_) |
| return; |
| @@ -419,6 +427,12 @@ void RenderFrameHostManager::ClearNavigationTransitionData() { |
| void RenderFrameHostManager::DidNavigateFrame( |
| RenderFrameHostImpl* render_frame_host) { |
| + DCHECK(render_frame_host); |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + return; |
|
Charlie Reis
2014/12/04 21:46:28
I'm not sure this is correct.
What happens if a D
clamy
2014/12/05 17:16:19
If we go along with committing the NavigationEntry
Charlie Reis
2014/12/05 19:06:23
I'm nervous about this as well: ignoring a commit
carlosk
2014/12/09 07:55:42
I'm having trouble following your lines of thought
clamy
2014/12/09 15:09:51
Indeed, it seems we are in agreement that the spec
carlosk
2014/12/16 01:53:47
Done.
|
| + } |
| + |
| if (!cross_navigation_pending_) { |
| DCHECK(!pending_render_frame_host_); |
| @@ -574,7 +588,10 @@ void RenderFrameHostManager::DiscardUnusedFrame( |
| RenderFrameProxyHost* proxy = |
| new RenderFrameProxyHost(site_instance, frame_tree_node_); |
| proxy_hosts_[site_instance->GetId()] = proxy; |
| - render_frame_host->SwapOut(proxy); |
| + |
| + if (!render_frame_host->is_swapped_out()) |
| + render_frame_host->SwapOut(proxy); |
| + |
| if (frame_tree_node_->IsMainFrame()) |
| proxy->TakeFrameHostOwnership(render_frame_host.Pass()); |
| } else { |
| @@ -619,6 +636,88 @@ void RenderFrameHostManager::ResetProxyHosts() { |
| } |
| // PlzNavigate |
| +void RenderFrameHostManager::BeginNavigation( |
|
Charlie Reis
2014/12/04 21:46:28
This code looks a lot like UpdateStateForNavigate,
carlosk
2014/12/09 07:55:42
Both methods do check if the current SiteInstance
|
| + const FrameHostMsg_BeginNavigation_Params& params, |
| + const CommonNavigationParams& common_params) { |
| + CHECK(CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)); |
| + // If there is an ongoing navigation, cancel it. |
|
Charlie Reis
2014/12/04 21:46:28
cancel it -> cancel any state we have for it.
(RF
clamy
2014/12/05 17:16:19
NavigatorImpl is normally responsible for cancelin
carlosk
2014/12/09 07:55:42
Updated the comment.
This was more of a just-in-c
clamy
2014/12/09 15:09:52
The way the code is written, there would not have
carlosk
2014/12/16 01:53:47
It is already being called in NavigatorImpl::Cance
|
| + CleanUpNavigation(); |
| + |
| + SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); |
| + // TODO(carlosk): Replace the default values with the right ones. |
|
Charlie Reis
2014/12/04 21:46:28
I see this is the same TODO as in GetFrameHostForN
clamy
2014/12/05 17:16:19
Note that it also concerns the SiteInstance pointe
carlosk
2014/12/09 07:55:42
Updated comment.
|
| + scoped_refptr<SiteInstanceImpl> new_instance = |
| + static_cast<SiteInstanceImpl*>(GetSiteInstanceForNavigation( |
| + common_params.url, nullptr, common_params.transition, false, false)); |
| + |
| + if (new_instance.get() != current_instance && |
| + (frame_tree_node_->IsMainFrame() || |
|
Charlie Reis
2014/12/04 21:46:28
These additional checks are non-obvious, so please
clamy
2014/12/05 17:16:19
In that case, we need to be able to distinguish he
Charlie Reis
2014/12/05 19:06:23
Yes, but this is an important TODO we'll need to r
carlosk
2014/12/09 07:55:42
I inverted the logic here to match the similar sni
clamy
2014/12/09 15:09:51
I think it is fine to have an if-block with just a
carlosk
2014/12/16 01:53:47
Done!
|
| + CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kSitePerProcess))) { |
| + // Navigating to a new SiteInstance -> speculatively create a new RFH. |
| + |
| + // TODO(carlosk): enable bindings check below. |
| + bool success = CreateSpeculativeRenderFrameHost( |
| + common_params.url, current_instance, new_instance.get(), |
| + NavigationEntryImpl::kInvalidBindings); |
| + if (!success) |
| + return; |
| + DCHECK(new_instance->GetProcess()->HasConnection()); |
| + DCHECK(new_instance->GetProcess()->GetBrowserContext()); |
|
Charlie Reis
2014/12/04 21:46:28
This second check seems unnecessary. Is there a w
carlosk
2014/12/09 07:55:42
I was going to say this was a copy/paste from anot
|
| + } else { |
|
Charlie Reis
2014/12/04 21:46:28
nit: Return here inside the previous block, so tha
carlosk
2014/12/09 07:55:42
Done.
|
| + // Navigating to the same SiteInstance -> make sure the current RFH is |
| + // alive. |
| + 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(current_instance->GetProcess()->HasConnection()); |
| + DCHECK(current_instance->GetProcess()->GetBrowserContext()); |
| + } |
| +} |
| + |
| +// PlzNavigate |
| +bool RenderFrameHostManager::CreateSpeculativeRenderFrameHost( |
| + const GURL& url, |
| + SiteInstance* old_instance, |
| + SiteInstance* new_instance, |
| + int bindings) { |
| + CHECK(new_instance); |
| + CHECK_NE(old_instance, new_instance); |
| + |
| + const NavigationEntry* current_navigation_entry = |
| + delegate_->GetLastCommittedNavigationEntryForRenderManager(); |
| + scoped_ptr<WebUIImpl> new_web_ui; |
| + should_reuse_web_ui_ = ShouldReuseWebUI(current_navigation_entry, url); |
| + if (!should_reuse_web_ui_) |
| + new_web_ui = CreateWebUI(url, bindings); |
| + |
| + int opener_route_id = |
| + CreateOpenerRenderViewsIfNeeded(old_instance, new_instance); |
| + |
| + int create_render_frame_flags = 0; |
| + if (frame_tree_node_->IsMainFrame()) |
| + create_render_frame_flags |= CREATE_RF_FOR_MAIN_FRAME_NAVIGATION; |
| + if (delegate_->IsHidden()) |
| + create_render_frame_flags |= CREATE_RF_HIDDEN; |
| + scoped_ptr<RenderFrameHostImpl> new_render_frame_host = |
| + CreateRenderFrame(new_instance, new_web_ui.get(), opener_route_id, |
| + create_render_frame_flags, nullptr); |
| + if (!new_render_frame_host) { |
| + return false; |
| + } |
| + 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, |
| ui::PageTransition transition) { |
| @@ -650,6 +749,19 @@ RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation( |
| return render_frame_host; |
| } |
| +// PlzNavigate |
| +void RenderFrameHostManager::CleanUpNavigation() { |
| + CHECK(CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)); |
| + if (speculative_render_frame_host_) { |
| + speculative_render_frame_host_->GetProcess()->RemovePendingView(); |
| + DiscardUnusedFrame(speculative_render_frame_host_.Pass()); |
| + } |
| + if (speculative_web_ui_) |
| + speculative_web_ui_.reset(); |
| + should_reuse_web_ui_ = false; |
| +} |
| + |
| void RenderFrameHostManager::Observe( |
| int type, |
| const NotificationSource& source, |
| @@ -1110,8 +1222,8 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrame( |
| 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 |
| - // it in the same SiteInstance as our current RFH. |
| + // We are creating a pending, speculative 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); |
| // Check if we've already created an RFH for this SiteInstance. If so, try |
| @@ -1294,23 +1406,32 @@ void RenderFrameHostManager::CommitPending() { |
| // 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 (!CommandLine::ForCurrentProcess()->HasSwitch( |
|
Charlie Reis
2014/12/04 21:46:28
Please cache this in a bool so we don't repeatedly
carlosk
2014/12/09 07:55:42
Ha! I had just undone that. :) Re-added the boolea
|
| + switches::kEnableBrowserSideNavigation)) { |
| + 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(); |
| + if (!should_reuse_web_ui_) |
| + web_ui_.reset(speculative_web_ui_.release()); |
|
Charlie Reis
2014/12/04 21:46:28
Let's add a DCHECK(!speculative_web_ui_) after thi
carlosk
2014/12/09 07:55:42
Done.
|
| } |
| // 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_ && |
| + !CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
|
Charlie Reis
2014/12/04 21:46:28
Can we make this !pending_render_frame_host_ && !s
carlosk
2014/12/09 07:55:42
Makes sense. Done.
|
| if (will_focus_location_bar) |
| delegate_->SetFocusToLocationBar(false); |
| return; |
| @@ -1324,10 +1445,20 @@ 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 (!CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableBrowserSideNavigation)) { |
| + 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(); |
| @@ -1456,6 +1587,36 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation( |
| url, instance, transition, is_restore, is_view_source_mode); |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
|
Charlie Reis
2014/12/04 21:46:28
This doesn't feel like it fits here. Most of Upda
carlosk
2014/12/09 07:55:42
Makes total sense and so I moved it.
It might nee
|
| + switches::kEnableBrowserSideNavigation)) { |
| + if (current_instance == new_instance.get() || |
| + (!frame_tree_node_->IsMainFrame() && |
|
Charlie Reis
2014/12/04 21:46:28
Same concern about the process model policy.
carlosk
2014/12/09 07:55:41
Done: TODO + reference in crbug.com/440266 .
|
| + !CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kSitePerProcess))) { |
| + CleanUpNavigation(); |
| + } else { |
| + // If the SiteInstance for the final URL doesn't match the one from the |
| + // speculatively created RenderFrameHost, create a new one using the |
| + // former. |
| + if (!speculative_render_frame_host_ || |
| + speculative_render_frame_host_->GetSiteInstance() != |
| + new_instance.get()) { |
| + CleanUpNavigation(); |
| + // TODO(carlosk): Should rename this method and the speculative members |
|
Charlie Reis
2014/12/04 21:46:28
I'm not concerned about the name. We're creating
carlosk
2014/12/09 07:55:41
Great! Later on I realized that as soon as we begi
|
| + // because in this case they are not speculative. Suggestions are |
| + // very welcome! |
| + bool success = CreateSpeculativeRenderFrameHost( |
| + url, current_instance, new_instance.get(), bindings); |
| + if (!success) |
| + return nullptr; |
| + } |
| + DCHECK(speculative_render_frame_host_); |
| + CommitPending(); |
| + DCHECK(!speculative_render_frame_host_); |
| + } |
| + return render_frame_host_.get(); |
| + } |
| + |
| const NavigationEntry* current_entry = |
| delegate_->GetLastCommittedNavigationEntryForRenderManager(); |