Index: content/browser/web_contents/render_view_host_manager.cc |
diff --git a/content/browser/web_contents/render_view_host_manager.cc b/content/browser/web_contents/render_view_host_manager.cc |
index 95021bfbf2be75f0d7b09e1e628278fa3c28eea6..c167333623d82f11f32401fb98e9ff652ba7646f 100644 |
--- a/content/browser/web_contents/render_view_host_manager.cc |
+++ b/content/browser/web_contents/render_view_host_manager.cc |
@@ -206,7 +206,7 @@ void RenderViewHostManager::DidNavigateMainFrame( |
DCHECK(render_view_host == render_view_host_); |
// Even when there is no pending RVH, there may be a pending Web UI. |
- if (pending_web_ui_.get()) |
+ if (pending_web_ui()) |
CommitPending(); |
return; |
} |
@@ -358,7 +358,7 @@ bool RenderViewHostManager::ShouldTransitionCrossSite() { |
} |
bool RenderViewHostManager::ShouldSwapProcessesForNavigation( |
- const NavigationEntry* cur_entry, |
+ const NavigationEntry* curr_entry, |
const NavigationEntryImpl* new_entry) const { |
DCHECK(new_entry); |
@@ -366,9 +366,9 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation( |
// doesn't usually swap (e.g., process-per-tab). |
// For security, we should transition between processes when one is a Web UI |
- // page and one isn't. If there's no cur_entry, check the current RVH's |
+ // page and one isn't. If there's no curr_entry, check the current RVH's |
// site, which might already be committed to a Web UI URL (such as the NTP). |
- const GURL& current_url = (cur_entry) ? cur_entry->GetURL() : |
+ const GURL& current_url = (curr_entry) ? curr_entry->GetURL() : |
render_view_host_->GetSiteInstance()->GetSite(); |
content::BrowserContext* browser_context = |
delegate_->GetControllerForRenderManager().GetBrowserContext(); |
@@ -389,23 +389,37 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation( |
} |
if (content::GetContentClient()->browser()->ShouldSwapProcessesForNavigation( |
- cur_entry ? cur_entry->GetURL() : GURL(), new_entry->GetURL())) { |
+ curr_entry ? curr_entry->GetURL() : GURL(), new_entry->GetURL())) { |
return true; |
} |
- if (!cur_entry) |
+ if (!curr_entry) |
return false; |
// We can't switch a RenderView between view source and non-view source mode |
// without screwing up the session history sometimes (when navigating between |
// "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat |
// it as a new navigation). So require a view switch. |
- if (cur_entry->IsViewSourceMode() != new_entry->IsViewSourceMode()) |
+ if (curr_entry->IsViewSourceMode() != new_entry->IsViewSourceMode()) |
return true; |
return false; |
} |
+bool RenderViewHostManager::ShouldReuseWebUI( |
+ const NavigationEntry* curr_entry, |
+ const NavigationEntryImpl* new_entry) const { |
+ NavigationControllerImpl& controller = |
+ delegate_->GetControllerForRenderManager(); |
+ WebUIControllerFactory* factory = |
+ content::GetContentClient()->browser()->GetWebUIControllerFactory(); |
+ return curr_entry && web_ui_.get() && |
+ (factory->GetWebUIType(controller.GetBrowserContext(), |
+ curr_entry->GetURL()) == |
+ factory->GetWebUIType(controller.GetBrowserContext(), |
+ new_entry->GetURL())); |
+} |
+ |
SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( |
const NavigationEntryImpl& entry, |
SiteInstance* curr_instance) { |
@@ -581,8 +595,8 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host, |
const NavigationEntryImpl& entry) { |
// If the pending navigation is to a WebUI, tell the RenderView about any |
// bindings it will need enabled. |
- if (pending_web_ui_.get()) |
- render_view_host->AllowBindings(pending_web_ui_->GetBindings()); |
+ if (pending_web_ui()) |
+ render_view_host->AllowBindings(pending_web_ui()->GetBindings()); |
return delegate_->CreateRenderViewForRenderManager(render_view_host); |
} |
@@ -594,11 +608,14 @@ void RenderViewHostManager::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. |
- web_ui_.swap(pending_web_ui_); |
- if (web_ui_.get() && pending_web_ui_.get() && !pending_render_view_host_) |
- web_ui_->GetController()->DidBecomeActiveForReusedRenderView(); |
- pending_web_ui_.reset(); |
+ // 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_.get()) |
+ web_ui_.reset(pending_web_ui_.release()); |
+ else if (!pending_and_current_web_ui_.get()) |
+ web_ui_.reset(); |
// It's possible for the pending_render_view_host_ to be NULL when we aren't |
// crossing process boundaries. If so, we just needed to handle the Web UI |
@@ -692,14 +709,6 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( |
cross_navigation_pending_ = false; |
} |
- // This will possibly create (set to NULL) a Web UI object for the pending |
- // page. We'll use this later to give the page special access. This must |
- // happen before the new renderer is created below so it will get bindings. |
- // It must also happen after the above conditional call to CancelPending(), |
- // otherwise CancelPending may clear the pending_web_ui_ and the page will |
- // not have it's bindings set appropriately. |
- pending_web_ui_.reset(delegate_->CreateWebUIForRenderManager(entry.GetURL())); |
- |
// render_view_host_ will not be deleted before the end of this method, so we |
// don't have to worry about this SiteInstance's ref count dropping to zero. |
SiteInstance* curr_instance = render_view_host_->GetSiteInstance(); |
@@ -708,8 +717,9 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( |
// Again, new_instance won't be deleted before the end of this method, so it |
// is safe to use a normal pointer here. |
SiteInstance* new_instance = curr_instance; |
- bool force_swap = ShouldSwapProcessesForNavigation( |
- delegate_->GetLastCommittedNavigationEntryForRenderManager(), &entry); |
+ const content::NavigationEntry* curr_entry = |
+ delegate_->GetLastCommittedNavigationEntryForRenderManager(); |
+ bool force_swap = ShouldSwapProcessesForNavigation(curr_entry, &entry); |
if (ShouldTransitionCrossSite() || force_swap) |
new_instance = GetSiteInstanceForEntry(entry, curr_instance); |
@@ -717,6 +727,16 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( |
// New SiteInstance. |
DCHECK(!cross_navigation_pending_); |
+ // This will possibly create (set to NULL) a Web UI object for the pending |
+ // page. We'll use this later to give the page special access. This must |
+ // happen before the new renderer is created below so it will get bindings. |
+ // It must also happen after the above conditional call to CancelPending(), |
+ // otherwise CancelPending may clear the pending_web_ui_ and the page will |
+ // not have its bindings set appropriately. |
+ pending_web_ui_.reset( |
+ delegate_->CreateWebUIForRenderManager(entry.GetURL())); |
+ pending_and_current_web_ui_.reset(); |
+ |
// Create a pending RVH and navigate it. |
bool success = CreatePendingRenderView(entry, new_instance); |
if (!success) |
@@ -766,8 +786,17 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( |
return pending_render_view_host_; |
} else { |
- if (pending_web_ui_.get() && render_view_host_->IsRenderViewLive()) |
- pending_web_ui_->GetController()->RenderViewReused(render_view_host_); |
+ if (ShouldReuseWebUI(curr_entry, &entry)) { |
+ pending_web_ui_.reset(); |
+ pending_and_current_web_ui_ = web_ui_->AsWeakPtr(); |
+ } else { |
+ pending_and_current_web_ui_.reset(); |
+ pending_web_ui_.reset( |
+ delegate_->CreateWebUIForRenderManager(entry.GetURL())); |
+ } |
+ |
+ if (pending_web_ui() && render_view_host_->IsRenderViewLive()) |
+ pending_web_ui()->GetController()->RenderViewReused(render_view_host_); |
// The renderer can exit view source mode when any error or cancellation |
// happen. We must overwrite to recover the mode. |
@@ -811,6 +840,7 @@ void RenderViewHostManager::CancelPending() { |
} |
pending_web_ui_.reset(); |
+ pending_and_current_web_ui_.reset(); |
} |
void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { |