Index: content/browser/frame_host/navigation_controller_impl.cc |
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc |
index 8a0c2071d62e92317fc55811882780ab5f859997..e3256686dd802b6414302d68431d47b65605eecd 100644 |
--- a/content/browser/frame_host/navigation_controller_impl.cc |
+++ b/content/browser/frame_host/navigation_controller_impl.cc |
@@ -223,10 +223,10 @@ NavigationControllerImpl::NavigationControllerImpl( |
NavigationControllerDelegate* delegate, |
BrowserContext* browser_context) |
: browser_context_(browser_context), |
- pending_entry_(NULL), |
+ pending_entry_(nullptr), |
failed_pending_entry_id_(0), |
failed_pending_entry_should_replace_(false), |
- last_committed_entry_index_(-1), |
+ last_committed_entry_index_(0), |
pending_entry_index_(-1), |
transient_entry_index_(-1), |
delegate_(delegate), |
@@ -263,11 +263,13 @@ void NavigationControllerImpl::Restore( |
RestoreType type, |
ScopedVector<NavigationEntry>* entries) { |
// Verify that this controller is unused and that the input is valid. |
- DCHECK(GetEntryCount() == 0 && !GetPendingEntry()); |
+ DCHECK(IsInitialBlankNavigation() && GetEntryCount() == 1 && |
+ !GetPendingEntry()); |
DCHECK(selected_navigation >= 0 && |
selected_navigation < static_cast<int>(entries->size())); |
needs_reload_ = true; |
+ entries_.clear(); |
for (size_t i = 0; i < entries->size(); ++i) { |
NavigationEntryImpl* entry = |
NavigationEntryImpl::FromNavigationEntry((*entries)[i]); |
@@ -402,6 +404,14 @@ bool NavigationControllerImpl::IsInitialNavigation() const { |
return is_initial_navigation_; |
} |
+bool NavigationControllerImpl::IsInitialBlankNavigation() const { |
+ // Only return true if the initial navigation is not marked as a restore, as |
+ // it is during a clone. |
+ return IsInitialNavigation() && |
+ GetEntryCount() == 1 && |
+ GetEntryAtIndex(0)->restore_type() == NavigationEntryImpl::RESTORE_NONE; |
+} |
+ |
NavigationEntryImpl* NavigationControllerImpl::GetEntryWithPageID( |
SiteInstance* instance, int32 page_id) const { |
int index = GetEntryIndexWithPageID(instance, page_id); |
@@ -483,8 +493,8 @@ int NavigationControllerImpl::GetCurrentEntryIndex() const { |
} |
NavigationEntryImpl* NavigationControllerImpl::GetLastCommittedEntry() const { |
- if (last_committed_entry_index_ == -1) |
- return NULL; |
+ DCHECK_GE(last_committed_entry_index_, 0); |
+ DCHECK_LT(last_committed_entry_index_, GetEntryCount()); |
return entries_[last_committed_entry_index_]; |
} |
@@ -792,8 +802,6 @@ bool NavigationControllerImpl::RendererDidNavigate( |
RenderFrameHostImpl* rfh, |
const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
LoadCommittedDetails* details) { |
- is_initial_navigation_ = false; |
- |
// Save the previous state before we clobber it. |
if (GetLastCommittedEntry()) { |
details->previous_url = GetLastCommittedEntry()->GetURL(); |
@@ -827,6 +835,12 @@ bool NavigationControllerImpl::RendererDidNavigate( |
pending_entry_->should_replace_entry(); |
} |
+ // If this is the first navigation after the initial about:blank page, then it |
+ // should replace the initial NavigationEntry, regardless of the checks above. |
+ if (IsInitialBlankNavigation()) |
+ details->did_replace_entry = true; |
+ is_initial_navigation_ = false; |
+ |
// Do navigation-type specific actions. These will make and commit an entry. |
details->type = ClassifyNavigation(rfh, params); |
@@ -839,6 +853,9 @@ bool NavigationControllerImpl::RendererDidNavigate( |
RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); |
break; |
case NAVIGATION_TYPE_EXISTING_PAGE: |
+ // TODO(creis): This is wrong. See |
+ // https://codereview.chromium.org/1214073005. Shouldn't touch this value |
+ // in most cases. |
details->did_replace_entry = details->is_in_page; |
RendererDidNavigateToExistingPage(rfh, params); |
break; |
@@ -852,16 +869,6 @@ bool NavigationControllerImpl::RendererDidNavigate( |
if (!RendererDidNavigateAutoSubframe(rfh, params)) |
return false; |
break; |
- case NAVIGATION_TYPE_NAV_IGNORE: |
- // If a pending navigation was in progress, this canceled it. We should |
- // discard it and make sure it is removed from the URL bar. After that, |
- // there is nothing we can do with this navigation, so we just return to |
- // the caller that nothing has happened. |
- if (pending_entry_) { |
- DiscardNonCommittedEntries(); |
- delegate_->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); |
- } |
- return false; |
default: |
NOTREACHED(); |
} |
@@ -953,20 +960,9 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
if (params.did_create_new_entry) { |
// A new entry. We may or may not have a pending entry for the page, and |
// this may or may not be the main frame. |
- if (!rfh->GetParent()) { |
- return NAVIGATION_TYPE_NEW_PAGE; |
- } |
- |
- // When this is a new subframe navigation, we should have a committed page |
- // in which it's a subframe. This may not be the case when an iframe is |
- // navigated on a popup navigated to about:blank (the iframe would be |
- // written into the popup by script on the main page). For these cases, |
- // there isn't any navigation stuff we can do, so just ignore it. |
- if (!GetLastCommittedEntry()) |
- return NAVIGATION_TYPE_NAV_IGNORE; |
- |
- // Valid subframe navigation. |
- return NAVIGATION_TYPE_NEW_SUBFRAME; |
+ return rfh->GetParent() ? |
+ NAVIGATION_TYPE_NEW_SUBFRAME : |
+ NAVIGATION_TYPE_NEW_PAGE; |
} |
// We only clear the session history when navigating to a new page. |
@@ -975,28 +971,13 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
if (rfh->GetParent()) { |
// All manual subframes would be did_create_new_entry and handled above, so |
// we know this is auto. |
- if (GetLastCommittedEntry()) { |
- return NAVIGATION_TYPE_AUTO_SUBFRAME; |
- } else { |
- // We ignore subframes created in non-committed pages; we'd appreciate if |
- // people stopped doing that. |
- return NAVIGATION_TYPE_NAV_IGNORE; |
- } |
+ return NAVIGATION_TYPE_AUTO_SUBFRAME; |
} |
if (params.nav_entry_id == 0) { |
// This is a renderer-initiated navigation (nav_entry_id == 0), but didn't |
- // create a new page. |
- |
- // Just like above in the did_create_new_entry case, it's possible to |
- // scribble onto an uncommitted page. Again, there isn't any navigation |
- // stuff that we can do, so ignore it here as well. |
- NavigationEntry* last_committed = GetLastCommittedEntry(); |
- if (!last_committed) |
- return NAVIGATION_TYPE_NAV_IGNORE; |
- |
- // This is history.replaceState(), history.reload(), or a client-side |
- // redirect. |
+ // create a new page. This happens for history.replaceState(), |
+ // history.reload(), or a client-side redirect. |
return NAVIGATION_TYPE_EXISTING_PAGE; |
} |
@@ -1353,13 +1334,7 @@ bool NavigationControllerImpl::IsURLInPageNavigation( |
if (rfh->GetParent()) { |
last_committed_url = rfh->GetLastCommittedURL(); |
} else { |
- NavigationEntry* last_committed = GetLastCommittedEntry(); |
- // There must be a last-committed entry to compare URLs to. TODO(avi): When |
- // might Blink say that a navigation is in-page yet there be no last- |
- // committed entry? |
- if (!last_committed) |
- return false; |
- last_committed_url = last_committed->GetURL(); |
+ last_committed_url = GetLastCommittedEntry()->GetURL(); |
} |
WebPreferences prefs = rfh->GetRenderViewHost()->GetWebkitPreferences(); |
@@ -1387,12 +1362,13 @@ void NavigationControllerImpl::CopyStateFrom( |
const NavigationControllerImpl& source = |
static_cast<const NavigationControllerImpl&>(temp); |
// Verify that we look new. |
- DCHECK(GetEntryCount() == 0 && !GetPendingEntry()); |
- |
- if (source.GetEntryCount() == 0) |
- return; // Nothing new to do. |
+ DCHECK(IsInitialBlankNavigation() && GetEntryCount() == 1 && |
+ !GetPendingEntry()); |
+ DCHECK_GT(source.GetEntryCount(), 0); |
needs_reload_ = true; |
+ // Drop the initial entry first. |
+ entries_.pop_back(); |
InsertEntriesFrom(source, source.GetEntryCount()); |
for (SessionStorageNamespaceMap::const_iterator it = |
@@ -1469,7 +1445,7 @@ bool NavigationControllerImpl::CanPruneAllButLastCommitted() { |
// If there is no last committed entry, we cannot prune. Even if there is a |
// pending entry, it may not commit, leaving this WebContents blank, despite |
// possibly giving it new entries via CopyStateFromAndPrune. |
- if (last_committed_entry_index_ == -1) |
+ if (IsInitialBlankNavigation()) |
return false; |
// We cannot prune if there is a pending entry at an existing entry index. |
@@ -1537,9 +1513,28 @@ int32 NavigationControllerImpl::GetMaxRestoredPageID() const { |
return max_restored_page_id_; |
} |
+void NavigationControllerImpl::Init(SiteInstance* instance) { |
+ DCHECK(IsInitialNavigation()); |
+ |
+ // Start with an entry for the initial about:blank page, which will be |
+ // replaced on first navigation. |
+ scoped_ptr<NavigationEntryImpl> initial_entry = |
+ make_scoped_ptr(new NavigationEntryImpl( |
+ static_cast<SiteInstanceImpl*>(instance), -1, |
+ GURL(url::kAboutBlankURL), Referrer(), base::string16(), |
+ ui::PAGE_TRANSITION_LINK, false)); |
+ |
+ // Make sure the initial RenderFrameHost knows about it. |
+ RenderFrameHostImpl* main_frame = |
+ delegate_->GetFrameTree()->root()->current_frame_host(); |
+ static_cast<RenderViewHostImpl*>(main_frame->GetRenderViewHost())-> |
+ set_nav_entry_id(initial_entry->GetUniqueID()); |
+ |
+ entries_.push_back(initial_entry.Pass()); |
+} |
+ |
bool NavigationControllerImpl::IsUnmodifiedBlankTab() const { |
- return IsInitialNavigation() && |
- !GetLastCommittedEntry() && |
+ return IsInitialBlankNavigation() && |
!delegate_->HasAccessedInitialDocument(); |
} |
@@ -1987,8 +1982,7 @@ void NavigationControllerImpl::SetTransientEntry( |
scoped_ptr<NavigationEntry> entry) { |
// Discard any current transient entry, we can only have one at a time. |
int index = 0; |
- if (last_committed_entry_index_ != -1) |
- index = last_committed_entry_index_ + 1; |
+ index = last_committed_entry_index_ + 1; |
DiscardTransientEntry(); |
entries_.insert(entries_.begin() + index, |
NavigationEntryImpl::FromNavigationEntry(entry.release())); |