Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(533)

Unified Diff: content/browser/frame_host/navigation_controller_impl.cc

Issue 281653003: DRAFT CL: Add FrameNavigationEntry and track subframe session histories. Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698