diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/navigation_controller.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/navigation_controller.cc')
-rw-r--r-- | chrome/browser/navigation_controller.cc | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/chrome/browser/navigation_controller.cc b/chrome/browser/navigation_controller.cc new file mode 100644 index 0000000..a31db5f --- /dev/null +++ b/chrome/browser/navigation_controller.cc @@ -0,0 +1,712 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/browser/navigation_controller.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/common/navigation_types.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/scoped_vector.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/dom_ui/dom_ui_host.h" +#include "chrome/browser/navigation_entry.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/repost_form_warning_dialog.h" +#include "chrome/browser/site_instance.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/tab_contents_delegate.h" +#include "chrome/common/chrome_switches.h" +#include "net/base/net_util.h" + +// TabContentsCollector --------------------------------------------------- + +// We never destroy a TabContents synchronously because there are some +// complex code path that cause the current TabContents to be in the call +// stack. So instead, we use a TabContentsCollector which either destroys +// the TabContents or does nothing if it has been cancelled. +class TabContentsCollector : public Task { + public: + TabContentsCollector(NavigationController* target, + TabContentsType target_type) + : target_(target), + target_type_(target_type) { + } + + void Cancel() { + target_ = NULL; + } + + virtual void Run() { + if (target_) { + // Note: this will cancel this task as a side effect so target_ is + // now null. + TabContents* tc = target_->GetTabContents(target_type_); + tc->Destroy(); + } + } + + private: + // The NavigationController we are acting on. + NavigationController* target_; + + // The TabContentsType that needs to be collected. + TabContentsType target_type_; + + DISALLOW_EVIL_CONSTRUCTORS(TabContentsCollector); +}; + +// NavigationController --------------------------------------------------- + +// static +bool NavigationController::check_for_repost_ = true; + +// Creates a new NavigationEntry for each TabNavigation in navigations, adding +// the NavigationEntry to entries. This is used during session restore. +static void CreateNavigationEntriesFromTabNavigations( + const std::vector<TabNavigation>& navigations, + std::vector<NavigationEntry*>* entries) { + // Create a NavigationEntry for each of the navigations. + for (std::vector<TabNavigation>::const_iterator i = + navigations.begin(); i != navigations.end(); ++i) { + const TabNavigation& navigation = *i; + + GURL real_url = navigation.url; + TabContentsType type = TabContents::TypeForURL(&real_url); + DCHECK(type != TAB_CONTENTS_UNKNOWN_TYPE); + + NavigationEntry* entry = new NavigationEntry( + type, + NULL, // The site instance for restored tabs is sent on naviagion + // (WebContents::GetSiteInstanceForEntry). + static_cast<int>(i - navigations.begin()), + real_url, + navigation.title, + // Use a transition type of reload so that we don't incorrectly + // increase the typed count. + PageTransition::RELOAD); + entry->SetDisplayURL(navigation.url); + entry->SetContentState(navigation.state); + entry->SetHasPostData(navigation.type_mask & TabNavigation::HAS_POST_DATA); + entries->push_back(entry); + } +} + +// Configure all the NavigationEntries in entries for restore. This resets +// the transition type to reload and makes sure the content state isn't empty. +static void ConfigureEntriesForRestore( + std::vector<NavigationEntry*>* entries) { + for (size_t i = 0, count = entries->size(); i < count; ++i) { + // Use a transition type of reload so that we don't incorrectly increase + // the typed count. + (*entries)[i]->SetTransitionType(PageTransition::RELOAD); + (*entries)[i]->set_restored(true); + // NOTE(darin): This code is only needed for backwards compat. + NavigationControllerBase::SetContentStateIfEmpty((*entries)[i]); + } +} + +NavigationController::NavigationController(TabContents* contents, + Profile* profile) + : profile_(profile), + active_contents_(contents), + alternate_nav_url_fetcher_entry_unique_id_(0), + max_restored_page_id_(-1), + ssl_manager_(this, NULL), + needs_reload_(false), + load_pending_entry_when_active_(false) { + if (contents) + RegisterTabContents(contents); + DCHECK(profile_); + profile_->RegisterNavigationController(this); +} + +NavigationController::NavigationController( + Profile* profile, + const std::vector<TabNavigation>& navigations, + int selected_navigation, + HWND parent) + : profile_(profile), + active_contents_(NULL), + alternate_nav_url_fetcher_entry_unique_id_(0), + max_restored_page_id_(-1), + ssl_manager_(this, NULL), + needs_reload_(true), + load_pending_entry_when_active_(false) { + DCHECK(profile_); + DCHECK(selected_navigation >= 0 && + selected_navigation < static_cast<int>(navigations.size())); + + profile_->RegisterNavigationController(this); + + // Populate entries_ from the supplied TabNavigations. + CreateNavigationEntriesFromTabNavigations(navigations, &entries_); + + // And finish the restore. + FinishRestore(parent, selected_navigation); +} + +NavigationController::~NavigationController() { + DCHECK(tab_contents_map_.empty()); + DCHECK(tab_contents_collector_map_.empty()); + + SessionService* session_service = GetSessionService(); + if (session_service) + session_service->TabClosed(window_id_, session_id()); + + profile_->UnregisterNavigationController(this); + + NotificationService::current()->Notify( + NOTIFY_TAB_CLOSED, + Source<NavigationController>(this), + NotificationService::NoDetails()); +} + +TabContents* NavigationController::GetTabContents(TabContentsType t) { + // Make sure the TabContents is no longer scheduled for collection. + CancelTabContentsCollection(t); + return tab_contents_map_[t]; +} + +void NavigationController::Reset() { + NavigationControllerBase::Reset(); + + NotifyPrunedEntries(); +} + +void NavigationController::Reload() { + // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? + DiscardPendingEntryInternal(); + int current_index = GetCurrentEntryIndex(); + if (check_for_repost_ && current_index != -1 && + GetEntryAtIndex(current_index)->HasPostData() && + active_contents_->AsWebContents() && + !active_contents_->AsWebContents()->showing_repost_interstitial()) { + // The user is asking to reload a page with POST data and we're not showing + // the POST interstitial. Prompt to make sure they really want to do this. + // If they do, RepostFormWarningDialog calls us back with + // ReloadDontCheckForRepost. + active_contents_->Activate(); + RepostFormWarningDialog::RunRepostFormWarningDialog(this); + } else { + NavigationControllerBase::Reload(); + } +} + +void NavigationController::ReloadDontCheckForRepost() { + NavigationControllerBase::Reload(); +} + +void NavigationController::Destroy() { + // First, clean out all NULL entries in the map so that we know empty map + // means all tabs destroyed. This is needed since TabContentsWasDestroyed() + // won't get called for types that are in our map with a NULL contents. + for (int t = 0; t < TAB_CONTENTS_NUM_TYPES; t++) { + TabContentsMap::iterator i = + tab_contents_map_.find(static_cast<TabContentsType>(t)); + if (i != tab_contents_map_.end() && !i->second) + tab_contents_map_.erase(i); + } + + // Now close all tab contents owned by this controller. We make a list on + // the stack because they are removed from the map as they are Destroyed + // (invalidating the iterators), which may or may not occur synchronously. + std::list<TabContents*> tabs_to_destroy; + for (TabContentsMap::iterator i = tab_contents_map_.begin(); + i != tab_contents_map_.end(); ++i) { + DCHECK(i->second); + tabs_to_destroy.push_back(i->second); + } + + // Cancel all the TabContentsCollectors. + for (TabContentsCollectorMap::iterator i = + tab_contents_collector_map_.begin(); + i != tab_contents_collector_map_.end(); ++i) { + DCHECK(i->second); + i->second->Cancel(); + } + + // Finally destroy all the tab contents. + for (std::list<TabContents*>::iterator i = tabs_to_destroy.begin(); + i != tabs_to_destroy.end(); ++i) { + (*i)->Destroy(); + } + // We are deleted at this point. +} + +void NavigationController::TabContentsWasDestroyed(TabContentsType type) { + TabContentsMap::iterator i = tab_contents_map_.find(type); + DCHECK(i != tab_contents_map_.end()); + tab_contents_map_.erase(i); + + // Make sure we cancel any collector for that TabContents. + TabContentsCollectorMap::iterator ci = tab_contents_collector_map_.find(type); + if (ci != tab_contents_collector_map_.end()) { + DCHECK(ci->second); + ci->second->Cancel(); + } + + // If that was the last tab to be destroyed, delete ourselves. + if (tab_contents_map_.empty()) + delete this; +} + +NavigationEntry* NavigationController::CreateNavigationEntry( + const GURL& url, PageTransition::Type transition) { + GURL real_url = url; + TabContentsType type; + + // If the active contents supports |url|, use it. + // Note: in both cases, we give TabContents a chance to rewrite the URL. + TabContents* active = active_contents(); + if (active && active->SupportsURL(&real_url)) + type = active->type(); + else + type = TabContents::TypeForURL(&real_url); + + NavigationEntry* entry = new NavigationEntry(type, NULL, -1, real_url, + std::wstring(), transition); + entry->SetDisplayURL(url); + entry->SetUserTypedURL(url); + if (url.SchemeIsFile()) { + entry->SetTitle(file_util::GetFilenameFromPath(UTF8ToWide(url.host() + + url.path()))); + } + return entry; +} + +void NavigationController::LoadURL(const GURL& url, + PageTransition::Type transition) { + // The user initiated a load, we don't need to reload anymore. + needs_reload_ = false; + + NavigationEntry* entry = CreateNavigationEntry(url, transition); + + LoadEntry(entry); +} + +void NavigationController::LoadURLLazily(const GURL& url, + PageTransition::Type type, + const std::wstring& title, + SkBitmap* icon) { + NavigationEntry* entry = CreateNavigationEntry(url, type); + entry->SetTitle(title); + if (icon) + entry->SetFavIcon(*icon); + + // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? + DiscardPendingEntryInternal(); + pending_entry_ = entry; + load_pending_entry_when_active_ = true; +} + +bool NavigationController::LoadingURLLazily() { + return load_pending_entry_when_active_; +} + +const std::wstring& NavigationController::GetLazyTitle() const { + if (pending_entry_) + return pending_entry_->GetTitle(); + else + return EmptyWString(); +} + +const SkBitmap& NavigationController::GetLazyFavIcon() const { + if (pending_entry_) { + return pending_entry_->GetFavIcon(); + } else { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + return *rb.GetBitmapNamed(IDR_DEFAULT_FAVICON); + } +} + +void NavigationController::EntryUpdated(NavigationEntry* entry) { + if (entry == GetActiveEntry()) { + // Someone has modified our active navigation entry. + NotifyNavigationStateChanged(); + } +} + +void NavigationController::SetAlternateNavURLFetcher( + AlternateNavURLFetcher* alternate_nav_url_fetcher) { + DCHECK(!alternate_nav_url_fetcher_.get()); + DCHECK(pending_entry_); + alternate_nav_url_fetcher_.reset(alternate_nav_url_fetcher); + alternate_nav_url_fetcher_entry_unique_id_ = pending_entry_->unique_id(); +} + +void NavigationController::DidNavigateToEntry(NavigationEntry* entry) { + DCHECK(active_contents_); + DCHECK(entry->GetType() == active_contents_->type()); + + NavigationControllerBase::DidNavigateToEntry(entry); + // entry is now deleted + + if (alternate_nav_url_fetcher_.get()) { + // Because this call may synchronously show an infobar, we do it last, to + // make sure all other state is stable and the infobar won't get blown away + // by some transition. + alternate_nav_url_fetcher_->OnNavigatedToEntry(); + } + + // If the previous or next entry uses a different tab contents it is now a + // safe time to schedule collection because a navigation is neccessary to + // get back to them. + int index = GetCurrentEntryIndex(); + if (index < 0 || GetPendingEntryIndex() != -1) + return; + + TabContentsType active_type = GetEntryAtIndex(index)->GetType(); + if (index > 0) { + NavigationEntry* ne = GetEntryAtIndex(index - 1); + if (ne->GetType() != active_type) + ScheduleTabContentsCollection(ne->GetType()); + } + if (index < (GetEntryCount() - 1)) { + NavigationEntry* ne = GetEntryAtIndex(index + 1); + if (ne->GetType() != active_type) + ScheduleTabContentsCollection(ne->GetType()); + } +} + +void NavigationController::DiscardPendingEntry() { + NavigationControllerBase::DiscardPendingEntry(); + + // Synchronize the active_contents_ to the last committed entry. + NavigationEntry* last_entry = GetLastCommittedEntry(); + if (last_entry && last_entry->GetType() != active_contents_->type()) { + TabContents* from_contents = active_contents_; + from_contents->SetActive(false); + + // Switch back to the previous tab contents. + active_contents_ = GetTabContents(last_entry->GetType()); + DCHECK(active_contents_); + + active_contents_->SetActive(true); + + // If we are transitioning from two types of WebContents, we need to migrate + // the download shelf if it is visible. The download shelf may have been + // created before the error that caused us to discard the entry. + WebContents::MigrateShelfView(from_contents, active_contents_); + + if (from_contents->delegate()) { + from_contents->delegate()->ReplaceContents(from_contents, + active_contents_); + } + + // The entry we just discarded needed a different TabContents type. We no + // longer need it but we can't destroy it just yet because the TabContents + // is very likely involved in the current stack. + DCHECK(from_contents != active_contents_); + ScheduleTabContentsCollection(from_contents->type()); + } + + // Note: this may be redundant in some cases. we may want to optimize away + // the redundant notifications. + NotifyNavigationStateChanged(); +} + +void NavigationController::InsertEntry(NavigationEntry* entry) { + DCHECK(entry); + + NavigationControllerBase::InsertEntry(entry); + + int index = GetIndexOfEntry(entry); + DCHECK(entries_.size() > 0 && index != -1); + SyncSessionWithSelectedIndex(index); + + active_contents_->NotifyDidNavigate(NAVIGATION_NEW, 0); +} + +void NavigationController::SetWindowID(const SessionID& id) { + window_id_ = id; + + SessionService* session_service = GetSessionService(); + if (session_service) + session_service->SetTabWindow(window_id_, session_id()); +} + +void NavigationController::NavigateToPendingEntry(bool reload) { + TabContents* from_contents = active_contents_; + + // For session history navigations only the pending_entry_index_ is set. + if (!pending_entry_) { + DCHECK(pending_entry_index_ != -1); + pending_entry_ = entries_[pending_entry_index_]; + } + + // Reset the security states as any SSL error may have been resolved since we + // last visited that page. + pending_entry_->ResetSSLStates(); + + if (from_contents && from_contents->type() != pending_entry_->GetType()) + from_contents->SetActive(false); + + HWND parent = + from_contents ? GetParent(from_contents->GetContainerHWND()) : 0; + TabContents* contents = + GetTabContentsCreateIfNecessary(parent, *pending_entry_); + + contents->SetActive(true); + active_contents_ = contents; + + if (from_contents && from_contents != contents) { + if (from_contents->delegate()) + from_contents->delegate()->ReplaceContents(from_contents, contents); + } + + if (contents->Navigate(*pending_entry_, reload)) { + // Note: this is redundant if navigation completed synchronously because + // DidNavigateToEntry call this as well. + NotifyNavigationStateChanged(); + } else { + DiscardPendingEntry(); + } +} + +void NavigationController::NotifyNavigationStateChanged() { + // Reset the Alternate Nav URL Fetcher if we're loading some page it doesn't + // care about. We must do this before calling Notify() below as that may + // result in the creation of a new fetcher. + const NavigationEntry* const entry = GetActiveEntry(); + if (!entry || + (entry->unique_id() != alternate_nav_url_fetcher_entry_unique_id_)) { + alternate_nav_url_fetcher_.reset(); + alternate_nav_url_fetcher_entry_unique_id_ = 0; + } + + // TODO(pkasting): http://b/1113079 Probably these explicit notification paths + // should be removed, and interested parties should just listen for the + // notification below instead. + ssl_manager_.NavigationStateChanged(); + active_contents_->NotifyNavigationStateChanged( + TabContents::INVALIDATE_EVERYTHING); + + NotificationService::current()->Notify( + NOTIFY_NAVIGATION_STATE_CHANGED, + Source<NavigationController>(this), + NotificationService::NoDetails()); +} + +void NavigationController::NotifyPrunedEntries() { + SessionService* session_service = GetSessionService(); + if (!session_service) + return; + session_service->TabNavigationPathPruned(window_id(), session_id(), + GetEntryCount()); +} + +void NavigationController::IndexOfActiveEntryChanged( + int prev_committed_index) { + NavigationType nav_type = NAVIGATION_BACK_FORWARD; + int relative_navigation_offset = + GetLastCommittedEntryIndex() - prev_committed_index; + if (relative_navigation_offset == 0) { + nav_type = NAVIGATION_REPLACE; + } + active_contents_->NotifyDidNavigate(nav_type, relative_navigation_offset); + if (GetCurrentEntryIndex() != -1) + SyncSessionWithSelectedIndex(GetCurrentEntryIndex()); +} + +TabContents* NavigationController::GetTabContentsCreateIfNecessary( + HWND parent, + const NavigationEntry& entry) { + TabContents* contents = GetTabContents(entry.GetType()); + if (!contents) { + contents = TabContents::CreateWithType(entry.GetType(), parent, profile_, + entry.site_instance()); + if (!contents->AsWebContents()) { + // Update the max page id, otherwise the newly created TabContents may + // have reset its max page id resulting in all new navigations. We only + // do this for non-WebContents as WebContents takes care of this via its + // SiteInstance. If this creation is the result of a restore, WebContents + // handles invoking ReservePageIDRange to make sure the renderer's + // max_page_id is updated to reflect the restored range of page ids. + int32 max_page_id = contents->GetMaxPageID(); + for (size_t i = 0; i < entries_.size(); ++i) { + if (entries_[i]->GetType() == entry.GetType()) + max_page_id = std::max(max_page_id, entries_[i]->GetPageID()); + } + contents->UpdateMaxPageID(max_page_id); + } + RegisterTabContents(contents); + } + + // We should not be trying to collect this tab contents. + DCHECK(tab_contents_collector_map_.find(contents->type()) == + tab_contents_collector_map_.end()); + + return contents; +} + +void NavigationController::RegisterTabContents(TabContents* some_contents) { + DCHECK(some_contents); + TabContentsType t = some_contents->type(); + TabContents* tc; + if ((tc = tab_contents_map_[t]) != some_contents) { + if (tc) { + NOTREACHED() << "Should not happen. Multiple contents for one type"; + } else { + tab_contents_map_[t] = some_contents; + some_contents->set_controller(this); + } + } + if (some_contents->AsDOMUIHost()) + some_contents->AsDOMUIHost()->AttachMessageHandlers(); +} + +SessionService* NavigationController::GetSessionService() const { + if (profile_->HasSessionService()) + return profile_->GetSessionService(); + + return NULL; +} + +void NavigationController::SyncSessionWithEntryByPageID( + TabContentsType type, + SiteInstance *instance, + int32 page_id) const { + int index = GetEntryIndexWithPageID(type, instance, page_id); + if (index != -1) + SyncSessionWithEntry(entries_[index], index); +} + +// static +void NavigationController::DisablePromptOnRepost() { + check_for_repost_ = false; +} + +void NavigationController::SetActive(bool is_active) { + if (is_active) { + if (needs_reload_) { + LoadIfNecessary(); + } else if (load_pending_entry_when_active_) { + NavigateToPendingEntry(false); + load_pending_entry_when_active_ = false; + } + } +} + +void NavigationController::LoadIfNecessary() { + if (!needs_reload_) + return; + + needs_reload_ = false; + // Calling Reload() results in ignoring state, and not loading. + // Explicitly use NavigateToPendingEntry so that the renderer uses the + // cached state. + pending_entry_index_ = last_committed_entry_index_; + NavigateToPendingEntry(false); +} + +void NavigationController::SyncSessionWithEntry(const NavigationEntry* entry, + int index) const { + SessionService* session_service = GetSessionService(); + if (!session_service) + return; + + DCHECK(entry && index != -1); + if (entry->GetDisplayURL().is_valid()) + session_service->UpdateTabNavigation(window_id(), session_id(), index, + *entry); +} + +void NavigationController::SyncSessionWithSelectedIndex(int index) const { + DCHECK(index != -1); + SessionService* session_service = GetSessionService(); + if (!session_service) + return; + + session_service->SetSelectedNavigationIndex(window_id(), session_id(), index); +} + +int NavigationController::GetMaxPageID() const { + return active_contents_->GetMaxPageID(); +} + +NavigationController* NavigationController::Clone(HWND parent_hwnd) { + NavigationController* nc = new NavigationController(NULL, profile_); + + if (GetEntryCount() == 0) + return nc; + + nc->needs_reload_ = true; + + nc->entries_.reserve(entries_.size()); + for (int i = 0, c = GetEntryCount(); i < c; ++i) + nc->entries_.push_back(new NavigationEntry(*GetEntryAtIndex(i))); + + nc->FinishRestore(parent_hwnd, last_committed_entry_index_); + + return nc; +} + +void NavigationController::ScheduleTabContentsCollection(TabContentsType t) { + TabContentsCollectorMap::const_iterator i = + tab_contents_collector_map_.find(t); + + // The tab contents is already scheduled for collection. + if (i != tab_contents_collector_map_.end()) + return; + + // If we currently don't have a TabContents for t, skip. + if (tab_contents_map_.find(t) == tab_contents_map_.end()) + return; + + // Create a collector and schedule it. + TabContentsCollector* tcc = new TabContentsCollector(this, t); + tab_contents_collector_map_[t] = tcc; + MessageLoop::current()->PostTask(FROM_HERE, tcc); +} + +void NavigationController::CancelTabContentsCollection(TabContentsType t) { + TabContentsCollectorMap::iterator i = tab_contents_collector_map_.find(t); + + if (i != tab_contents_collector_map_.end()) { + DCHECK(i->second); + i->second->Cancel(); + tab_contents_collector_map_.erase(i); + } +} + +void NavigationController::FinishRestore(HWND parent_hwnd, int selected_index) { + DCHECK(selected_index >= 0 && selected_index < GetEntryCount()); + ConfigureEntriesForRestore(&entries_); + + set_max_restored_page_id(GetEntryCount()); + + last_committed_entry_index_ = selected_index; + + // Callers assume we have an active_contents after restoring, so set it now. + active_contents_ = + GetTabContentsCreateIfNecessary(parent_hwnd, *entries_[selected_index]); +} |