| 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..3970e13cd66f7df5c7d6a9de6a8b3958ec43294c 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),
|
| + 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;
|
| + }
|
| +
|
| if (!cross_navigation_pending_) {
|
| DCHECK(!pending_render_frame_host_);
|
|
|
| @@ -619,6 +633,88 @@ void RenderFrameHostManager::ResetProxyHosts() {
|
| }
|
|
|
| // PlzNavigate
|
| +void RenderFrameHostManager::BeginNavigation(
|
| + const FrameHostMsg_BeginNavigation_Params& params,
|
| + const CommonNavigationParams& common_params) {
|
| + CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableBrowserSideNavigation));
|
| + // If there is an ongoing navigation, cancel it.
|
| + CleanUpNavigation();
|
| +
|
| + SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
|
| + // TODO(carlosk): Replace the default values with the right ones.
|
| + 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() ||
|
| + 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());
|
| + } else {
|
| + // 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 +746,18 @@ 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();
|
| +}
|
| +
|
| void RenderFrameHostManager::Observe(
|
| int type,
|
| const NotificationSource& source,
|
| @@ -1110,8 +1218,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
|
| @@ -1288,29 +1396,38 @@ int RenderFrameHostManager::GetRoutingIdForSiteInstance(
|
| void RenderFrameHostManager::CommitPending() {
|
| TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending",
|
| "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
|
| + bool 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();
|
| + if (!should_reuse_web_ui_)
|
| + 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;
|
| @@ -1324,10 +1441,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();
|
|
|
| @@ -1456,6 +1582,36 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
|
| scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation(
|
| url, instance, transition, is_restore, is_view_source_mode);
|
|
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableBrowserSideNavigation)) {
|
| + if (current_instance == new_instance.get() ||
|
| + (!frame_tree_node_->IsMainFrame() &&
|
| + !CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kSitePerProcess))) {
|
| + CleanUpNavigation();
|
| + } else {
|
| + // If the SiteInstance for the final URL doesn't match the one form 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
|
| + // 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();
|
|
|
|
|