| 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
|
|
|