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 0b0f411a1a041f52893e84357af935f7fe81c0df..bf1d76bd3a02c01364e432f326dc878bef706951 100644 |
--- a/content/browser/frame_host/navigation_controller_impl.cc |
+++ b/content/browser/frame_host/navigation_controller_impl.cc |
@@ -18,9 +18,11 @@ |
#include "content/browser/dom_storage/dom_storage_context_wrapper.h" |
#include "content/browser/dom_storage/session_storage_namespace_impl.h" |
#include "content/browser/frame_host/debug_urls.h" |
+#include "content/browser/frame_host/frame_navigation_entry.h" |
#include "content/browser/frame_host/interstitial_page_impl.h" |
#include "content/browser/frame_host/navigation_entry_impl.h" |
#include "content/browser/frame_host/navigation_entry_screenshot_manager.h" |
+#include "content/browser/frame_host/navigator_impl.h" |
#include "content/browser/renderer_host/render_view_host_impl.h" // Temporary |
#include "content/browser/site_instance_impl.h" |
#include "content/common/frame_messages.h" |
@@ -70,6 +72,7 @@ void NotifyPrunedEntries(NavigationControllerImpl* nav_controller, |
// this one. We don't want that. To avoid this we create a valid state which |
// WebKit will not treat as a new navigation. |
void SetPageStateIfEmpty(NavigationEntryImpl* entry) { |
+ // TODO(creis): Do this for FrameNavigationEntries instead. |
if (!entry->GetPageState().IsValid()) |
entry->SetPageState(PageState::CreateFromURL(entry->GetURL())); |
} |
@@ -90,6 +93,7 @@ NavigationEntryImpl::RestoreType ControllerRestoreTypeToEntryType( |
// Configure all the NavigationEntries in entries for restore. This resets |
// the transition type to reload and makes sure the content state isn't empty. |
+// TODO(creis): Take in a vector of FrameNavigationEntries instead. |
void ConfigureEntriesForRestore( |
std::vector<linked_ptr<NavigationEntryImpl> >* entries, |
NavigationController::RestoreType type) { |
@@ -181,6 +185,7 @@ NavigationEntry* NavigationController::CreateNavigationEntry( |
BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary( |
&loaded_url, browser_context, &reverse_on_redirect); |
+ // Common case: Navigate the top-level frame. |
NavigationEntryImpl* entry = new NavigationEntryImpl( |
NULL, // The site instance for tabs is sent on navigation |
// (WebContents::GetSiteInstance). |
@@ -197,6 +202,46 @@ NavigationEntry* NavigationController::CreateNavigationEntry( |
return entry; |
} |
+// TODO(creis): Share code with CreateNavigationEntry. |
+NavigationEntryImpl* NavigationControllerImpl::CreateSubframeNavigationEntry( |
+ int64 frame_tree_node_id, |
+ const GURL& url, |
+ const Referrer& referrer, |
+ ui::PageTransition transition, |
+ bool is_renderer_initiated, |
+ const std::string& extra_headers, |
+ BrowserContext* browser_context) { |
+ // Allow the browser URL handler to rewrite the URL. This will, for example, |
+ // remove "view-source:" from the beginning of the URL to get the URL that |
+ // will actually be loaded. This real URL won't be shown to the user, just |
+ // used internally. |
+ GURL loaded_url(url); |
+ bool reverse_on_redirect = false; |
+ BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary( |
+ &loaded_url, browser_context, &reverse_on_redirect); |
+ |
+ FrameTreeNode* main_frame = delegate_->GetFrameTreeRoot(); |
+ |
+ // Subframe navigation: Clone the current tree, then create a FrameNavEntry |
+ // for the specified frame, clearing its subtree. |
+ // TODO(creis): Don't clear subtree for in-page navigations. |
+ NavigationEntryImpl* entry = new NavigationEntryImpl(); |
+ AddFramesToNavigationEntry(entry->root_node(), main_frame); |
+ NavigationEntryImpl::TreeNode* node = |
+ entry->GetTreeNodeForFrame( |
+ main_frame->frame_tree()->FindByID(frame_tree_node_id)); |
+ DCHECK(node) << "Couldn't find TreeNode for " << frame_tree_node_id; |
+ node->frame_entry = new FrameNavigationEntry(NULL, loaded_url, referrer); |
+ node->frame_entry->set_frame_tree_node_id(frame_tree_node_id); |
+ node->children.clear(); |
+ |
+ entry->SetVirtualURL(url); |
+ entry->set_user_typed_url(url); |
+ entry->set_update_virtual_url_with_url(reverse_on_redirect); |
+ entry->set_extra_headers(extra_headers); |
+ return entry; |
+} |
+ |
// static |
void NavigationController::DisablePromptOnRepost() { |
g_check_for_repost = false; |
@@ -227,6 +272,7 @@ NavigationControllerImpl::NavigationControllerImpl( |
pending_entry_index_(-1), |
transient_entry_index_(-1), |
delegate_(delegate), |
+ next_page_id_(1), |
max_restored_page_id_(-1), |
ssl_manager_(this), |
needs_reload_(false), |
@@ -409,8 +455,8 @@ bool NavigationControllerImpl::IsInitialNavigation() const { |
} |
NavigationEntryImpl* NavigationControllerImpl::GetEntryWithPageID( |
- SiteInstance* instance, int32 page_id) const { |
- int index = GetEntryIndexWithPageID(instance, page_id); |
+ int32 page_id) const { |
+ int index = GetEntryIndexWithPageID(page_id); |
return (index != -1) ? entries_[index].get() : NULL; |
} |
@@ -719,15 +765,23 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) { |
} |
NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( |
- CreateNavigationEntry( |
- params.url, |
- params.referrer, |
- params.transition_type, |
- params.is_renderer_initiated, |
- params.extra_headers, |
- browser_context_)); |
- if (params.frame_tree_node_id != -1) |
- entry->set_frame_tree_node_id(params.frame_tree_node_id); |
+ params.frame_tree_node_id == -1 ? |
+ CreateNavigationEntry( |
+ params.url, |
+ params.referrer, |
+ params.transition_type, |
+ params.is_renderer_initiated, |
+ params.extra_headers, |
+ browser_context_) : |
+ CreateSubframeNavigationEntry( |
+ params.frame_tree_node_id, |
+ params.url, |
+ params.referrer, |
+ params.transition_type, |
+ params.is_renderer_initiated, |
+ params.extra_headers, |
+ browser_context_)); |
+ // TODO(creis): Move source_site_instance to FNE. |
entry->set_source_site_instance( |
static_cast<SiteInstanceImpl*>(params.source_site_instance.get())); |
if (params.redirect_chain.size() > 0) |
@@ -860,8 +914,10 @@ bool NavigationControllerImpl::RendererDidNavigate( |
NavigationEntryImpl* active_entry = GetLastCommittedEntry(); |
active_entry->SetTimestamp(timestamp); |
active_entry->SetHttpStatusCode(params.http_status_code); |
- active_entry->SetPageState(params.page_state); |
active_entry->SetRedirectChain(params.redirects); |
+ FrameNavigationEntry* frame_entry = |
+ active_entry->GetFrameEntryForFrame(rfh->frame_tree_node()); |
+ frame_entry->set_page_state(params.page_state); |
// Use histogram to track memory impact of redirect chain because it's now |
// not cleared for committed entries. |
@@ -876,10 +932,7 @@ bool NavigationControllerImpl::RendererDidNavigate( |
active_entry->ResetForCommit(); |
// The active entry's SiteInstance should match our SiteInstance. |
- // TODO(creis): This check won't pass for subframes until we create entries |
- // for subframe navigations. |
- if (ui::PageTransitionIsMainFrame(params.transition)) |
- CHECK(active_entry->site_instance() == rfh->GetSiteInstance()); |
+ CHECK(frame_entry->site_instance() == rfh->GetSiteInstance()); |
// Remember the bindings the renderer process has at this point, so that |
// we do not grant this entry additional bindings if we come back to it. |
@@ -899,16 +952,8 @@ bool NavigationControllerImpl::RendererDidNavigate( |
NavigationType NavigationControllerImpl::ClassifyNavigation( |
RenderFrameHostImpl* rfh, |
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { |
- if (params.page_id == -1) { |
- // TODO(nasko, creis): An out-of-process child frame has no way of |
- // knowing the page_id of its parent, so it is passing back -1. The |
- // semantics here should be re-evaluated during session history refactor |
- // (see http://crbug.com/236848). For now, we assume this means the |
- // child frame loaded and proceed. Note that this may do the wrong thing |
- // for cross-process AUTO_SUBFRAME navigations. |
- if (rfh->IsCrossProcessSubframe()) |
- return NAVIGATION_TYPE_NEW_SUBFRAME; |
- |
+ // TODO(creis): Can this go away? We now have page_id == -1 for all new navs. |
+ if (params.item_sequence_number == -1) { |
// The renderer generates the page IDs, and so if it gives us the invalid |
// page ID (-1) we know it didn't actually navigate. This happens in a few |
// cases: |
@@ -930,8 +975,9 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
return NAVIGATION_TYPE_NAV_IGNORE; |
} |
- if (params.page_id > delegate_->GetMaxPageIDForSiteInstance( |
- rfh->GetSiteInstance())) { |
+ if (params.page_id == -1) { |
+ // A page ID of -1 means this is a new navigation of some kind. |
+ // TODO(creis): update comment below. |
// Greater page IDs than we've ever seen before are new pages. We may or may |
// not have a pending entry for the page, and this may or may not be the |
// main frame. |
@@ -947,6 +993,10 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
return NAVIGATION_TYPE_NAV_IGNORE; |
// Valid subframe navigation. |
+ // TODO(creis): Do this once 464014 is fixed. |
+ //if (ui::PageTransitionCoreTypeIs(params.transition, |
+ // ui::PAGE_TRANSITION_AUTO_SUBFRAME)) |
+ // return NAVIGATION_TYPE_AUTO_SUBFRAME; |
return NAVIGATION_TYPE_NEW_SUBFRAME; |
} |
@@ -954,9 +1004,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
DCHECK(!params.history_list_was_cleared); |
// Now we know that the notification is for an existing page. Find that entry. |
- int existing_entry_index = GetEntryIndexWithPageID( |
- rfh->GetSiteInstance(), |
- params.page_id); |
+ int existing_entry_index = GetEntryIndexWithPageID(params.page_id); |
if (existing_entry_index == -1) { |
// The page was not found. It could have been pruned because of the limit on |
// back/forward entries (not likely since we'll usually tell it to navigate |
@@ -1043,18 +1091,25 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage( |
const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
bool replace_entry) { |
NavigationEntryImpl* new_entry; |
+ FrameNavigationEntry* new_frame_entry; |
bool update_virtual_url; |
// Only make a copy of the pending entry if it is appropriate for the new page |
// that was just loaded. We verify this at a coarse grain by checking that |
// the SiteInstance hasn't been assigned to something else. |
- if (pending_entry_ && |
- (!pending_entry_->site_instance() || |
- pending_entry_->site_instance() == rfh->GetSiteInstance())) { |
- new_entry = pending_entry_->Clone(); |
+ // TODO(creis): Copy over details from pending entry when appropriate. |
+ // (Do we need a pending entry for each frame?) |
+ /*FrameNavigationEntryImpl* pending_entry = ...; |
+ if (pending_entry && |
+ (!pending_entry_>site_instance() || |
+ pending_entry->site_instance() == rfh->GetSiteInstance())) { |
+ new_entry = new FrameNavigationEntryImpl(*pending_entry); |
update_virtual_url = new_entry->update_virtual_url_with_url(); |
- } else { |
+ } else { */ |
new_entry = new NavigationEntryImpl; |
+ new_frame_entry = new FrameNavigationEntry; |
+ int64 frame_tree_node_id = rfh->frame_tree_node()->frame_tree_node_id(); |
+ new_frame_entry->set_frame_tree_node_id(frame_tree_node_id); |
// Find out whether the new entry needs to update its virtual URL on URL |
// change and set up the entry accordingly. This is needed to correctly |
@@ -1070,21 +1125,28 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage( |
// to show chrome://bookmarks/#1 when the bookmarks webui extension changes |
// the URL. |
update_virtual_url = needs_update; |
- } |
+ //} |
// Don't use the page type from the pending entry. Some interstitial page |
// may have set the type to interstitial. Once we commit, however, the page |
// type must always be normal or error. |
+ // TODO(creis): Move page type to FNE. |
new_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR |
: PAGE_TYPE_NORMAL); |
- new_entry->SetURL(params.url); |
+ new_frame_entry->set_url(params.url); |
if (update_virtual_url) |
UpdateVirtualURLToURL(new_entry, params.url); |
- new_entry->SetReferrer(params.referrer); |
- new_entry->SetPageID(params.page_id); |
+ new_frame_entry->set_referrer(params.referrer); |
+ new_frame_entry->set_site_instance(rfh->GetSiteInstance()); |
+ new_frame_entry->set_item_sequence_number(params.item_sequence_number); |
+ new_frame_entry->set_document_sequence_number( |
+ params.document_sequence_number); |
+ |
+ // Use a new page ID for this entry. |
+ CHECK_EQ(-1, params.page_id); |
+ new_entry->SetPageID(next_page_id_++); |
+ |
new_entry->SetTransitionType(params.transition); |
- new_entry->set_site_instance( |
- static_cast<SiteInstanceImpl*>(rfh->GetSiteInstance())); |
new_entry->SetHasPostData(params.is_post); |
new_entry->SetPostID(params.post_id); |
new_entry->SetOriginalRequestURL(params.original_request_url); |
@@ -1106,9 +1168,10 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage( |
DiscardNonCommittedEntriesInternal(); |
entries_.clear(); |
last_committed_entry_index_ = -1; |
+ rfh->frame_tree_node()->set_last_committed_frame_entry(nullptr); |
} |
- InsertOrReplaceEntry(new_entry, replace_entry); |
+ InsertOrReplaceEntry(rfh, new_entry, new_frame_entry, replace_entry); |
} |
void NavigationControllerImpl::RendererDidNavigateToExistingPage( |
@@ -1120,12 +1183,12 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage( |
// This is a back/forward navigation. The existing page for the ID is |
// guaranteed to exist by ClassifyNavigation, and we just need to update it |
// with new information from the renderer. |
- int entry_index = GetEntryIndexWithPageID(rfh->GetSiteInstance(), |
- params.page_id); |
+ int entry_index = GetEntryIndexWithPageID(params.page_id); |
DCHECK(entry_index >= 0 && |
entry_index < static_cast<int>(entries_.size())); |
NavigationEntryImpl* entry = entries_[entry_index].get(); |
+ // TODO(creis): Do these operations directly on the FNE. |
// The URL may have changed due to redirects. |
entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR |
: PAGE_TYPE_NORMAL); |
@@ -1143,8 +1206,7 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage( |
// when no site instance will be assigned. |
DCHECK(entry->site_instance() == NULL || |
entry->site_instance() == rfh->GetSiteInstance()); |
- entry->set_site_instance( |
- static_cast<SiteInstanceImpl*>(rfh->GetSiteInstance())); |
+ entry->set_site_instance(rfh->GetSiteInstance()); |
entry->SetHasPostData(params.is_post); |
entry->SetPostID(params.post_id); |
@@ -1162,8 +1224,9 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage( |
// If a transient entry was removed, the indices might have changed, so we |
// have to query the entry index again. |
- last_committed_entry_index_ = |
- GetEntryIndexWithPageID(rfh->GetSiteInstance(), params.page_id); |
+ last_committed_entry_index_ = GetEntryIndexWithPageID(params.page_id); |
+ rfh->frame_tree_node()->set_last_committed_frame_entry( |
+ entry->GetFrameEntryForFrame(rfh->frame_tree_node())); |
} |
void NavigationControllerImpl::RendererDidNavigateToSamePage( |
@@ -1172,8 +1235,7 @@ void NavigationControllerImpl::RendererDidNavigateToSamePage( |
// This mode implies we have a pending entry that's the same as an existing |
// entry for this page ID. This entry is guaranteed to exist by |
// ClassifyNavigation. All we need to do is update the existing entry. |
- NavigationEntryImpl* existing_entry = GetEntryWithPageID( |
- rfh->GetSiteInstance(), params.page_id); |
+ NavigationEntryImpl* existing_entry = GetEntryWithPageID(params.page_id); |
// We assign the entry's unique ID to be that of the new one. Since this is |
// always the result of a user action, we want to dismiss infobars, etc. like |
@@ -1199,11 +1261,11 @@ void NavigationControllerImpl::RendererDidNavigateInPage( |
RenderFrameHostImpl* rfh, |
const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
bool* did_replace_entry) { |
+ // TODO(creis): Why? Is this by spec? |
DCHECK(ui::PageTransitionIsMainFrame(params.transition)) << |
"WebKit should only tell us about in-page navs for the main frame."; |
// We're guaranteed to have an entry for this one. |
- NavigationEntryImpl* existing_entry = GetEntryWithPageID( |
- rfh->GetSiteInstance(), params.page_id); |
+ NavigationEntryImpl* existing_entry = GetEntryWithPageID(params.page_id); |
// Reference fragment navigation. We're guaranteed to have the last_committed |
// entry and it will be the same page as the new navigation (minus the |
@@ -1225,15 +1287,19 @@ void NavigationControllerImpl::RendererDidNavigateInPage( |
// If a transient entry was removed, the indices might have changed, so we |
// have to query the entry index again. |
- last_committed_entry_index_ = |
- GetEntryIndexWithPageID(rfh->GetSiteInstance(), params.page_id); |
+ last_committed_entry_index_ = GetEntryIndexWithPageID(params.page_id); |
+ rfh->frame_tree_node()->set_last_committed_frame_entry( |
+ existing_entry->GetFrameEntryForFrame(rfh->frame_tree_node())); |
} |
void NavigationControllerImpl::RendererDidNavigateNewSubframe( |
RenderFrameHostImpl* rfh, |
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) { |
- if (!ui::PageTransitionCoreTypeIs(params.transition, |
- ui::PAGE_TRANSITION_MANUAL_SUBFRAME)) { |
+ int64 frame_tree_node_id = rfh->frame_tree_node()->frame_tree_node_id(); |
+ // TODO(creis): Is this equivalent to checking PAGE_TRANSITION_AUTO_SUBFRAME? |
+ if (!rfh->frame_tree_node()->last_committed_frame_entry()) { |
+ DCHECK(ui::PageTransitionCoreTypeIs(params.transition, |
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME)); |
// There was a comment here that said, "This is not user-initiated. Ignore." |
// But this makes no sense; non-user-initiated navigations should be |
// determined to be of type NAVIGATION_TYPE_AUTO_SUBFRAME and sent to |
@@ -1251,6 +1317,24 @@ void NavigationControllerImpl::RendererDidNavigateNewSubframe( |
} |
DiscardNonCommittedEntriesInternal(); |
+ |
+ // New: We do need to add a FrameNavigationEntry. |
+ // TODO(creis): Refactor this method to avoid duplication. |
+ FrameNavigationEntry* frame_entry = new FrameNavigationEntry( |
+ rfh->GetSiteInstance(), params.url, params.referrer); |
+ frame_entry->set_frame_tree_node_id(frame_tree_node_id); |
+ frame_entry->set_item_sequence_number(params.item_sequence_number); |
+ frame_entry->set_document_sequence_number(params.document_sequence_number); |
+ rfh->frame_tree_node()->set_last_committed_frame_entry(frame_entry); |
+ |
+ // Reset the frame tree pointers for the last committed entry. |
+ NavigationEntryImpl* last_committed = |
+ NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry()); |
+ // TODO(creis): Just add this one; don't try to reset the whole tree. |
+ last_committed->ResetFrameTree(); |
+ AddFramesToNavigationEntry(last_committed->root_node(), |
+ delegate_->GetFrameTreeRoot()); |
+ |
return; |
} |
@@ -1261,8 +1345,19 @@ void NavigationControllerImpl::RendererDidNavigateNewSubframe( |
DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee " |
<< "that a last committed entry exists."; |
NavigationEntryImpl* new_entry = GetLastCommittedEntry()->Clone(); |
- new_entry->SetPageID(params.page_id); |
- InsertOrReplaceEntry(new_entry, false); |
+ |
+ // Use a new page ID for this entry. |
+ CHECK_EQ(-1, params.page_id); |
+ new_entry->SetPageID(next_page_id_++); |
+ |
+ // Create an appropriate subframe entry for it. |
+ FrameNavigationEntry* frame_entry = new FrameNavigationEntry( |
+ rfh->GetSiteInstance(), params.url, params.referrer); |
+ frame_entry->set_frame_tree_node_id(frame_tree_node_id); |
+ frame_entry->set_item_sequence_number(params.item_sequence_number); |
+ frame_entry->set_document_sequence_number(params.document_sequence_number); |
+ |
+ InsertOrReplaceEntry(rfh, new_entry, frame_entry, false); |
} |
bool NavigationControllerImpl::RendererDidNavigateAutoSubframe( |
@@ -1275,14 +1370,12 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe( |
// handle navigation inside of a subframe in it without creating a new entry. |
DCHECK(GetLastCommittedEntry()); |
- // Handle the case where we're navigating back/forward to a previous subframe |
- // navigation entry. This is case "2." in NAV_AUTO_SUBFRAME comment in the |
- // header file. In case "1." this will be a NOP. |
- int entry_index = GetEntryIndexWithPageID( |
- rfh->GetSiteInstance(), |
- params.page_id); |
- if (entry_index < 0 || |
- entry_index >= static_cast<int>(entries_.size())) { |
+ // TODO(creis): Split this out into ExistingSubframe. |
+ // Handle the case where we're navigating back/forward to a previous |
+ // subframe navigation entry. This is case "2." in NAV_AUTO_SUBFRAME comment |
+ // in the header file. In case "1." this will be a NOP. |
+ int entry_index = GetEntryIndexWithPageID(params.page_id); |
+ if (entry_index < 0 || entry_index >= static_cast<int>(entries_.size())) { |
NOTREACHED(); |
return false; |
} |
@@ -1291,9 +1384,47 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe( |
if (entry_index != last_committed_entry_index_) { |
last_committed_entry_index_ = entry_index; |
DiscardNonCommittedEntriesInternal(); |
+ |
+ // New: Find the FrameNavigationEntry this corresponds to and update our |
+ // index for that frame. |
+ // TODO(creis): Update the FNE, similar to ExistingPage. |
+ NavigationEntryImpl* entry = GetEntryAtIndex(entry_index); |
+ FrameNavigationEntry* frame_entry = |
+ entry->GetFrameEntryForFrame(rfh->frame_tree_node()); |
+ rfh->frame_tree_node()->set_last_committed_frame_entry(frame_entry); |
+ |
return true; |
} |
+ // If we get here without returning, then this was a second (or greater) |
+ // subframe committing as part of a back/forward. Only the first one causes |
+ // us to change the last_committed_entry_index_. |
+ |
+ // New: We do need to add a FrameNavigationEntry. |
+ FrameNavigationEntry* frame_entry = new FrameNavigationEntry( |
+ rfh->GetSiteInstance(), params.url, params.referrer); |
+ int64 frame_tree_node_id = rfh->frame_tree_node()->frame_tree_node_id(); |
+ frame_entry->set_frame_tree_node_id(frame_tree_node_id); |
+ frame_entry->set_item_sequence_number(params.item_sequence_number); |
+ frame_entry->set_document_sequence_number(params.document_sequence_number); |
+ |
+ // TODO(creis): This was missing in the case of going forward from an old main |
+ // frame to one with a subframe. We don't give the re-created subframe the |
+ // same FTN ID, so we don't find it in our array. (That's a bug on its own.) |
+ // But when we do get here legitimately, don't we need to assign page state? |
+ // What else? |
+ frame_entry->set_page_state(params.page_state); |
+ |
+ rfh->frame_tree_node()->set_last_committed_frame_entry(frame_entry); |
+ |
+ // Reset the frame tree pointers for the last committed entry. |
+ NavigationEntryImpl* last_committed = |
+ NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry()); |
+ // TODO(creis): Just add this one; don't try to reset the whole tree. |
+ last_committed->ResetFrameTree(); |
+ AddFramesToNavigationEntry(last_committed->root_node(), |
+ delegate_->GetFrameTreeRoot()); |
+ |
// We do not need to discard the pending entry in this case, since we will |
// not generate commit notifications for this auto-subframe navigation. |
return false; |
@@ -1441,6 +1572,7 @@ void NavigationControllerImpl::PruneAllButLastCommittedInternal() { |
entries_.begin() + last_committed_entry_index_); |
entries_.erase(entries_.begin() + 1, entries_.end()); |
last_committed_entry_index_ = 0; |
+ // TODO(creis): Update last committed FNE?. |
} |
void NavigationControllerImpl::ClearAllScreenshots() { |
@@ -1563,8 +1695,11 @@ int NavigationControllerImpl::GetPendingEntryIndex() const { |
return pending_entry_index_; |
} |
-void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry, |
- bool replace) { |
+void NavigationControllerImpl::InsertOrReplaceEntry( |
+ RenderFrameHostImpl* rfh, |
+ NavigationEntryImpl* entry, |
+ FrameNavigationEntry* frame_entry, |
+ bool replace) { |
DCHECK(entry->GetTransitionType() != ui::PAGE_TRANSITION_AUTO_SUBFRAME); |
// Copy the pending entry's unique ID to the committed entry. |
@@ -1601,13 +1736,51 @@ void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry, |
PruneOldestEntryIfFull(); |
+ // New: Set the last committed frame entry for this frame. |
+ // TODO(creis): This breaks in the replace case. We need to update the |
+ // existing FNE with all the data from frame_entry in that case, since many |
+ // NE's might already have references to the existing one. |
+ rfh->frame_tree_node()->set_last_committed_frame_entry(frame_entry); |
+ |
+ // New: Give the entry a fresh tree of pointers to the current frame entry for |
+ // each current frame, starting from the root. |
+ // TODO(creis): How can we clear it without deleting the refcounted FNEs? |
+ // I think we want to verify that it's empty here, and have a different way to |
+ // append a new frame to an existing NE. |
+ entry->ResetFrameTree(); |
+ AddFramesToNavigationEntry(entry->root_node(), delegate_->GetFrameTreeRoot()); |
+ |
+ // Finally, add the entry to the joint session history. |
entries_.push_back(linked_ptr<NavigationEntryImpl>(entry)); |
last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1; |
// This is a new page ID, so we need everybody to know about it. |
+ // TODO(creis): Is this still necessary? |
delegate_->UpdateMaxPageID(entry->GetPageID()); |
} |
+void NavigationControllerImpl::AddFramesToNavigationEntry( |
+ NavigationEntryImpl::TreeNode* entry_node, |
+ FrameTreeNode* frame_tree_node) { |
+ // TODO(creis): Remove this once auto-subframe case is fixed. // ? |
+ if (!frame_tree_node->last_committed_frame_entry()) |
+ return; |
+ |
+ // Put the last committed FrameNavigationEntry for this frame into the |
+ // corresponding spot of the top-level NavigationEntry. |
+ entry_node->SetFrameEntry(frame_tree_node->last_committed_frame_entry()); |
+ CHECK(entry_node->frame_entry); |
+ |
+ // Repeat for all the child frames. |
+ for (size_t i=0; i < frame_tree_node->child_count(); i++) { |
+ entry_node->children.push_back( |
+ new NavigationEntryImpl::TreeNode(entry_node->entry, nullptr)); |
+ CHECK_EQ(i + 1, entry_node->children.size()); |
+ AddFramesToNavigationEntry(entry_node->children[i], |
+ frame_tree_node->child_at(i)); |
+ } |
+} |
+ |
void NavigationControllerImpl::PruneOldestEntryIfFull() { |
if (entries_.size() >= max_entry_count()) { |
DCHECK_EQ(max_entry_count(), entries_.size()); |
@@ -1661,7 +1834,7 @@ void NavigationControllerImpl::NavigateToPendingEntry(ReloadType reload_type) { |
// This call does not support re-entrancy. See http://crbug.com/347742. |
CHECK(!in_navigate_to_pending_entry_); |
in_navigate_to_pending_entry_ = true; |
- bool success = delegate_->NavigateToPendingEntry(reload_type); |
+ bool success = NavigateToPendingEntryInternal(reload_type); |
in_navigate_to_pending_entry_ = false; |
if (!success) |
@@ -1740,6 +1913,7 @@ void NavigationControllerImpl::FinishRestore(int selected_index, |
SetMaxRestoredPageID(static_cast<int32>(GetEntryCount())); |
last_committed_entry_index_ = selected_index; |
+ // TODO(creis): Update last committed FNE. |
} |
void NavigationControllerImpl::DiscardNonCommittedEntriesInternal() { |
@@ -1769,11 +1943,9 @@ void NavigationControllerImpl::DiscardTransientEntry() { |
transient_entry_index_ = -1; |
} |
-int NavigationControllerImpl::GetEntryIndexWithPageID( |
- SiteInstance* instance, int32 page_id) const { |
+int NavigationControllerImpl::GetEntryIndexWithPageID(int32 page_id) const { |
for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { |
- if ((entries_[i]->site_instance() == instance) && |
- (entries_[i]->GetPageID() == page_id)) |
+ if (entries_[i]->GetPageID() == page_id) |
return i; |
} |
return -1; |
@@ -1821,4 +1993,77 @@ void NavigationControllerImpl::SetGetTimestampCallbackForTest( |
get_timestamp_callback_ = get_timestamp_callback; |
} |
+bool NavigationControllerImpl::NavigateToPendingEntryInternal( |
+ ReloadType reload_type) { |
+ FrameLoadVector same_document_loads; |
+ FrameLoadVector different_document_loads; |
+ DCHECK(pending_entry_); |
+ |
+ FrameTreeNode* main_frame = delegate_->GetFrameTreeRoot(); |
+ if (GetLastCommittedEntry()) { |
+ RecursiveNavigateToPendingEntry( |
+ main_frame, &same_document_loads, &different_document_loads); |
+ } |
+ |
+ if (same_document_loads.empty() && different_document_loads.empty()) { |
+ // If we don't have any frames to navigate at this point, either |
+ // (1) there is no previous history entry to compare against, or |
+ // (2) we were unable to match any frames by name. In the first case, |
+ // doing a different document navigation to the root item is the only valid |
+ // thing to do. In the second case, we should have been able to find a |
+ // frame to navigate based on names if this were a same document |
+ // navigation, so we can safely assume this is the different document case. |
+ // TODO(creis): Is it safe to use a raw pointer for the FNE here? |
+ different_document_loads.push_back( |
+ std::make_pair(main_frame, |
+ pending_entry_->root_node()->frame_entry.get())); |
+ } |
+ |
+ // If all the frame loads fail, we will discard the pending entry. |
+ bool success = false; |
+ |
+ // Send all the same document frame loads before the different document loads. |
+ for (size_t i = 0; i < same_document_loads.size(); ++i) { |
+ FrameTreeNode* frame = same_document_loads[i].first; |
+ success |= frame->navigator()->NavigateToPendingEntry( |
+ frame, *same_document_loads[i].second, reload_type); |
+ } |
+ for (size_t i = 0; i < different_document_loads.size(); ++i) { |
+ FrameTreeNode* frame = different_document_loads[i].first; |
+ success |= frame->navigator()->NavigateToPendingEntry( |
+ frame, *different_document_loads[i].second, reload_type); |
+ } |
+ return success; |
+} |
+ |
+void NavigationControllerImpl::RecursiveNavigateToPendingEntry( |
+ FrameTreeNode* frame, |
+ FrameLoadVector* same_document_loads, |
+ FrameLoadVector* different_document_loads) { |
+ DCHECK(pending_entry_); |
+ DCHECK_GE(last_committed_entry_index_, 0); |
+ FrameNavigationEntry* new_item = pending_entry_->GetFrameEntryForFrame(frame); |
+ FrameNavigationEntry* old_item = |
+ GetLastCommittedEntry()->GetFrameEntryForFrame(frame); |
+ if (!new_item) |
+ return; |
+ |
+ if (!old_item || |
+ new_item->item_sequence_number() != old_item->item_sequence_number()) { |
+ if (old_item && |
+ new_item->document_sequence_number() == |
+ old_item->document_sequence_number()) { |
+ same_document_loads->push_back(std::make_pair(frame, new_item)); |
+ } else { |
+ different_document_loads->push_back(std::make_pair(frame, new_item)); |
+ } |
+ return; |
+ } |
+ |
+ for (size_t i = 0; i < frame->child_count(); i++) { |
+ RecursiveNavigateToPendingEntry(frame->child_at(i), same_document_loads, |
+ different_document_loads); |
+ } |
+} |
+ |
} // namespace content |