diff options
author | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-21 00:51:20 +0000 |
---|---|---|
committer | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-21 00:51:20 +0000 |
commit | 765b3550e2164b7ccc5360b360ba940639be71c1 (patch) | |
tree | fe855f08e9d8a4b7d5384ddea9856584acb7ce73 /chrome | |
parent | efa56b0361925d8a49bf1fc27021a03d24be9f75 (diff) | |
download | chromium_src-765b3550e2164b7ccc5360b360ba940639be71c1.zip chromium_src-765b3550e2164b7ccc5360b360ba940639be71c1.tar.gz chromium_src-765b3550e2164b7ccc5360b360ba940639be71c1.tar.bz2 |
Kill NavigationControllerBase. I merged the two into NavigationController.
This fixes a leak of NavigationEntry's by using the spiffy linked ptr. I had to
add a const to linked_ptr for the comparisons to work.
BUG=1319484
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1137 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/navigation_controller.cc | 382 | ||||
-rw-r--r-- | chrome/browser/navigation_controller.h | 193 | ||||
-rw-r--r-- | chrome/browser/navigation_controller_base.cc | 427 | ||||
-rw-r--r-- | chrome/browser/navigation_controller_base.h | 236 |
5 files changed, 536 insertions, 710 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index d6fd648..5fee2a1 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -1114,14 +1114,6 @@ > </File> <File - RelativePath=".\navigation_controller_base.cc" - > - </File> - <File - RelativePath=".\navigation_controller_base.h" - > - </File> - <File RelativePath=".\navigation_entry.cc" > </File> diff --git a/chrome/browser/navigation_controller.cc b/chrome/browser/navigation_controller.cc index 5100922..1b86157 100644 --- a/chrome/browser/navigation_controller.cc +++ b/chrome/browser/navigation_controller.cc @@ -46,6 +46,7 @@ #include "chrome/browser/tab_contents_delegate.h" #include "chrome/common/chrome_switches.h" #include "net/base/net_util.h" +#include "webkit/glue/webkit_glue.h" // TabContentsCollector --------------------------------------------------- @@ -86,6 +87,10 @@ class TabContentsCollector : public Task { // NavigationController --------------------------------------------------- +// The maximum number of entries that a navigation controller can store. +// static +const static size_t kMaxEntryCount = 50; + // static bool NavigationController::check_for_repost_ = true; @@ -93,7 +98,7 @@ bool NavigationController::check_for_repost_ = true; // the NavigationEntry to entries. This is used during session restore. static void CreateNavigationEntriesFromTabNavigations( const std::vector<TabNavigation>& navigations, - std::vector<NavigationEntry*>* entries) { + std::vector<linked_ptr<NavigationEntry> >* entries) { // Create a NavigationEntry for each of the navigations. for (std::vector<TabNavigation>::const_iterator i = navigations.begin(); i != navigations.end(); ++i) { @@ -116,27 +121,31 @@ static void CreateNavigationEntriesFromTabNavigations( entry->SetDisplayURL(navigation.url); entry->SetContentState(navigation.state); entry->SetHasPostData(navigation.type_mask & TabNavigation::HAS_POST_DATA); - entries->push_back(entry); + entries->push_back(linked_ptr<NavigationEntry>(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) { + std::vector<linked_ptr<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::SetContentStateIfEmpty((*entries)[i].get()); } } NavigationController::NavigationController(TabContents* contents, Profile* profile) : profile_(profile), + pending_entry_(NULL), + last_committed_entry_index_(-1), + pending_entry_index_(-1), + max_entry_count_(kMaxEntryCount), active_contents_(contents), alternate_nav_url_fetcher_entry_unique_id_(0), max_restored_page_id_(-1), @@ -155,6 +164,10 @@ NavigationController::NavigationController( int selected_navigation, HWND parent) : profile_(profile), + pending_entry_(NULL), + last_committed_entry_index_(-1), + pending_entry_index_(-1), + max_entry_count_(kMaxEntryCount), active_contents_(NULL), alternate_nav_url_fetcher_entry_unique_id_(0), max_restored_page_id_(-1), @@ -190,12 +203,6 @@ TabContents* NavigationController::GetTabContents(TabContentsType 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(); @@ -211,12 +218,163 @@ void NavigationController::Reload() { active_contents_->Activate(); RepostFormWarningDialog::RunRepostFormWarningDialog(this); } else { - NavigationControllerBase::Reload(); + // Base the navigation on where we are now... + int current_index = GetCurrentEntryIndex(); + + // If we are no where, then we can't reload. TODO(darin): We should add a + // CanReload method. + if (current_index == -1) + return; + + // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? + DiscardPendingEntryInternal(); + + pending_entry_index_ = current_index; + entries_[pending_entry_index_]->SetTransitionType(PageTransition::RELOAD); + NavigateToPendingEntry(true); + } +} + +NavigationEntry* NavigationController::GetEntryWithPageID( + TabContentsType type, SiteInstance* instance, int32 page_id) const { + int index = GetEntryIndexWithPageID(type, instance, page_id); + return (index != -1) ? entries_[index].get() : NULL; +} + +void NavigationController::LoadEntry(NavigationEntry* entry) { + // When navigating to a new page, we don't know for sure if we will actually + // end up leaving the current page. The new page load could for example + // result in a download or a 'no content' response (e.g., a mailto: URL). + + // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? + DiscardPendingEntryInternal(); + pending_entry_ = entry; + NotificationService::current()->Notify( + NOTIFY_NAV_ENTRY_PENDING, + Source<NavigationController>(this), + NotificationService::NoDetails()); + NavigateToPendingEntry(false); +} + +/* static */ +void NavigationController::SetContentStateIfEmpty( + NavigationEntry* entry) { + if (entry->GetContentState().empty() && + (entry->GetType() == TAB_CONTENTS_WEB || + entry->GetType() == TAB_CONTENTS_NEW_TAB_UI || + entry->GetType() == TAB_CONTENTS_ABOUT_UI || + entry->GetType() == TAB_CONTENTS_HTML_DIALOG)) { + // The state is empty and the url will be rendered by WebKit. An empty + // state is treated as a new navigation by WebKit, which would mean + // losing the navigation entries and generating a new navigation + // entry after this one. We don't want that. To avoid this we create + // a valid state which WebKit will not treat as a new navigation. + entry->SetContentState( + webkit_glue::CreateHistoryStateForURL(entry->GetURL())); } } +NavigationEntry* NavigationController::GetActiveEntry() const { + NavigationEntry* entry = pending_entry_; + if (!entry) + entry = GetLastCommittedEntry(); + return entry; +} + +int NavigationController::GetCurrentEntryIndex() const { + if (pending_entry_index_ != -1) + return pending_entry_index_; + return last_committed_entry_index_; +} + +NavigationEntry* NavigationController::GetLastCommittedEntry() const { + if (last_committed_entry_index_ == -1) + return NULL; + return entries_[last_committed_entry_index_].get(); +} + +NavigationEntry* NavigationController::GetEntryAtOffset(int offset) const { + int index = last_committed_entry_index_ + offset; + if (index < 0 || index >= GetEntryCount()) + return NULL; + + return entries_[index].get(); +} + +bool NavigationController::CanStop() const { + // TODO(darin): do we have something pending that we can stop? + return false; +} + +bool NavigationController::CanGoBack() const { + return entries_.size() > 1 && GetCurrentEntryIndex() > 0; +} + +bool NavigationController::CanGoForward() const { + int index = GetCurrentEntryIndex(); + return index >= 0 && index < (static_cast<int>(entries_.size()) - 1); +} + +void NavigationController::GoBack() { + if (!CanGoBack()) { + NOTREACHED(); + return; + } + + // Base the navigation on where we are now... + int current_index = GetCurrentEntryIndex(); + + DiscardPendingEntry(); + + pending_entry_index_ = current_index - 1; + NavigateToPendingEntry(false); +} + +void NavigationController::GoForward() { + if (!CanGoForward()) { + NOTREACHED(); + return; + } + + // Base the navigation on where we are now... + int current_index = GetCurrentEntryIndex(); + + DiscardPendingEntry(); + + pending_entry_index_ = current_index + 1; + NavigateToPendingEntry(false); +} + +void NavigationController::GoToIndex(int index) { + if (index < 0 || index >= static_cast<int>(entries_.size())) { + NOTREACHED(); + return; + } + + DiscardPendingEntry(); + + pending_entry_index_ = index; + NavigateToPendingEntry(false); +} + +void NavigationController::GoToOffset(int offset) { + int index = last_committed_entry_index_ + offset; + if (index < 0 || index >= GetEntryCount()) + return; + + GoToIndex(index); +} + +void NavigationController::Stop() { + DCHECK(CanStop()); + + // TODO(darin): we probably want to just call Stop on the active tab + // contents, but should we also call DiscardPendingEntry? + NOTREACHED() << "implement me"; +} + void NavigationController::ReloadDontCheckForRepost() { - NavigationControllerBase::Reload(); + Reload(); } void NavigationController::Destroy() { @@ -361,8 +519,74 @@ void NavigationController::DidNavigateToEntry(NavigationEntry* entry) { DCHECK(active_contents_); DCHECK(entry->GetType() == active_contents_->type()); - NavigationControllerBase::DidNavigateToEntry(entry); - // entry is now deleted + SetContentStateIfEmpty(entry); + + entry->set_restored(false); + + // If the entry is that of a page with PageID larger than any this Tab has + // seen before, then consider it a new navigation. Note that if the entry + // has a SiteInstance, it should be the same as the SiteInstance of the + // active WebContents, because we have just navigated to it. + if (entry->GetPageID() > GetMaxPageID()) { + InsertEntry(entry); + NotifyNavigationEntryCommitted(); + return; + } + + // Otherwise, we just need to update an existing entry with matching PageID. + // If the existing entry corresponds to the entry which is pending, then we + // must update the current entry index accordingly. When navigating to the + // same URL, a new PageID is not created. + + int existing_entry_index = GetEntryIndexWithPageID(entry->GetType(), + entry->site_instance(), + entry->GetPageID()); + NavigationEntry* existing_entry = (existing_entry_index != -1) ? + entries_[existing_entry_index].get() : NULL; + if (!existing_entry) { + // No existing entry, then simply ignore this navigation! + DLOG(WARNING) << "ignoring navigation for page: " << entry->GetPageID(); + } else if ((existing_entry != pending_entry_) && pending_entry_ && + (pending_entry_->GetPageID() == -1) && + (pending_entry_->GetURL() == existing_entry->GetURL())) { + // Not a new navigation. + existing_entry->set_unique_id(pending_entry_->unique_id()); + DiscardPendingEntry(); + } else { + DCHECK(existing_entry != entry); + // The given entry might provide a new URL... e.g., navigating back to a + // page in session history could have resulted in a new client redirect. + // The given entry might also provide a new title (typically an empty title + // to overwrite the existing title). + existing_entry->SetURL(entry->GetURL()); + existing_entry->SetTitle(entry->GetTitle()); + existing_entry->SetFavIconURL(entry->GetFavIconURL()); + existing_entry->SetFavIcon(entry->GetFavIcon()); + existing_entry->SetValidFavIcon(entry->IsValidFavIcon()); + existing_entry->SetContentState(entry->GetContentState()); + + // TODO(brettw) why only copy the security style and no other SSL stuff? + existing_entry->ssl().set_security_style(entry->ssl().security_style()); + + const int prev_entry_index = last_committed_entry_index_; + if (existing_entry == pending_entry_) { + DCHECK(pending_entry_index_ != -1); + last_committed_entry_index_ = pending_entry_index_; + // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? + DiscardPendingEntryInternal(); + } else { + // NOTE: Do not update the unique ID here, as we don't want infobars etc. + // to dismiss. + + // The navigation could have been issued by the renderer, so be sure that + // we update our current index. + last_committed_entry_index_ = existing_entry_index; + } + IndexOfActiveEntryChanged(prev_entry_index); + } + + delete entry; + NotifyNavigationEntryCommitted(); if (alternate_nav_url_fetcher_.get()) { // Because this call may synchronously show an infobar, we do it last, to @@ -385,8 +609,35 @@ void NavigationController::DidNavigateToEntry(NavigationEntry* entry) { } } + +int NavigationController::GetIndexOfEntry( + const NavigationEntry* entry) const { + const NavigationEntries::const_iterator i(std::find( + entries_.begin(), + entries_.end(), + entry)); + return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin()); +} + +void NavigationController::RemoveLastEntry() { + int current_size = static_cast<int>(entries_.size()); + + if (current_size > 0) { + if (pending_entry_ == entries_[current_size - 1] || + pending_entry_index_ == current_size - 1) + DiscardPendingEntryInternal(); + + entries_.pop_back(); + + if (last_committed_entry_index_ >= current_size - 1) + last_committed_entry_index_ = current_size - 2; + + NotifyPrunedEntries(); + } +} + void NavigationController::DiscardPendingEntry() { - NavigationControllerBase::DiscardPendingEntry(); + DiscardPendingEntryInternal(); // Synchronize the active_contents_ to the last committed entry. NavigationEntry* last_entry = GetLastCommittedEntry(); @@ -419,7 +670,37 @@ void NavigationController::DiscardPendingEntry() { } void NavigationController::InsertEntry(NavigationEntry* entry) { - NavigationControllerBase::InsertEntry(entry); + DCHECK(entry->GetTransitionType() != PageTransition::AUTO_SUBFRAME); + + // Copy the pending entry's unique ID to the committed entry. + // I don't know if pending_entry_index_ can be other than -1 here. + const NavigationEntry* const pending_entry = (pending_entry_index_ == -1) ? + pending_entry_ : entries_[pending_entry_index_].get(); + if (pending_entry) + entry->set_unique_id(pending_entry->unique_id()); + + DiscardPendingEntryInternal(); + + int current_size = static_cast<int>(entries_.size()); + + // Prune any entries which are in front of the current entry. + if (current_size > 0) { + bool pruned = false; + while (last_committed_entry_index_ < (current_size - 1)) { + pruned = true; + entries_.pop_back(); + current_size--; + } + if (pruned) // Only notify if we did prune something. + NotifyPrunedEntries(); + } + + if (entries_.size() >= max_entry_count_) + RemoveEntryAtIndex(0); + + entries_.push_back(linked_ptr<NavigationEntry>(entry)); + last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1; + active_contents_->NotifyDidNavigate(NAVIGATION_NEW, 0); } @@ -436,7 +717,7 @@ void NavigationController::NavigateToPendingEntry(bool reload) { // 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_]; + pending_entry_ = entries_[pending_entry_index_].get(); } // Reset the security states as any SSL error may have been resolved since we @@ -558,7 +839,7 @@ void NavigationController::NotifyEntryChangedByPageID( int32 page_id) { int index = GetEntryIndexWithPageID(type, instance, page_id); if (index != -1) - NotifyEntryChanged(entries_[index], index); + NotifyEntryChanged(entries_[index].get(), index); } // static @@ -589,6 +870,13 @@ void NavigationController::LoadIfNecessary() { NavigateToPendingEntry(false); } +void NavigationController::ResetInternal() { + // WARNING: this is invoked from the destructor, be sure not to invoke any + // virtual methods from this. + entries_.clear(); + DiscardPendingEntryInternal(); +} + void NavigationController::NotifyEntryChanged(const NavigationEntry* entry, int index) { EntryChangedDetails det; @@ -599,6 +887,28 @@ void NavigationController::NotifyEntryChanged(const NavigationEntry* entry, Details<EntryChangedDetails>(&det)); } +void NavigationController::RemoveEntryAtIndex(int index) { + // TODO(brettw) this is only called to remove the first one when we've got + // too many entries. It should probably be more specific for this case. + if (index >= static_cast<int>(entries_.size()) || + index == pending_entry_index_ || index == last_committed_entry_index_) { + NOTREACHED(); + return; + } + + entries_.erase(entries_.begin() + index); + + if (last_committed_entry_index_ >= index) { + if (!entries_.empty()) + last_committed_entry_index_--; + else + last_committed_entry_index_ = -1; + } + + // TODO(brettw) bug 1324021: we probably need some notification here so the + // session service can stay in sync. +} + int NavigationController::GetMaxPageID() const { return active_contents_->GetMaxPageID(); } @@ -612,8 +922,10 @@ NavigationController* NavigationController::Clone(HWND parent_hwnd) { 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))); + for (int i = 0, c = GetEntryCount(); i < c; ++i) { + nc->entries_.push_back(linked_ptr<NavigationEntry>( + new NavigationEntry(*GetEntryAtIndex(i)))); + } nc->FinishRestore(parent_hwnd, last_committed_entry_index_); @@ -660,3 +972,33 @@ void NavigationController::FinishRestore(HWND parent_hwnd, int selected_index) { active_contents_ = GetTabContentsCreateIfNecessary(parent_hwnd, *entries_[selected_index]); } + +void NavigationController::DiscardPendingEntryInternal() { + if (pending_entry_index_ == -1) + delete pending_entry_; + pending_entry_ = NULL; + pending_entry_index_ = -1; +} + +int NavigationController::GetEntryIndexWithPageID( + TabContentsType type, SiteInstance* instance, int32 page_id) const { + // The instance should only be specified for contents displaying web pages. + // TODO(evanm): checking against NEW_TAB_UI and HTML_DLG here is lame. + // It'd be nice for DomUIHost to just use SiteInstances for keeping content + // separated properly. + if (type != TAB_CONTENTS_WEB && + type != TAB_CONTENTS_NEW_TAB_UI && + type != TAB_CONTENTS_ABOUT_UI && + type != TAB_CONTENTS_HTML_DIALOG && + type != TAB_CONTENTS_VIEW_SOURCE && + type != TAB_CONTENTS_DEBUGGER) + DCHECK(instance == NULL); + + for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { + if ((entries_[i]->GetType() == type) && + (entries_[i]->site_instance() == instance) && + (entries_[i]->GetPageID() == page_id)) + return i; + } + return -1; +} diff --git a/chrome/browser/navigation_controller.h b/chrome/browser/navigation_controller.h index 4378b04..0198713 100644 --- a/chrome/browser/navigation_controller.h +++ b/chrome/browser/navigation_controller.h @@ -32,12 +32,13 @@ #include <hash_map> +#include "base/linked_ptr.h" #include "base/ref_counted.h" #include "chrome/browser/alternate_nav_url_fetcher.h" -#include "chrome/browser/navigation_controller_base.h" #include "chrome/browser/session_service.h" #include "chrome/browser/site_instance.h" #include "chrome/browser/ssl_manager.h" +#include "chrome/browser/tab_contents_type.h" class GURL; class Profile; @@ -58,10 +59,10 @@ class PrintViewManager; // NavigationController instance per tab. // // The NavigationController also owns all TabContents for the tab. This is to -// make sure that we have at most one TabContents instance per type +// make sure that we have at most one TabContents instance per type. // //////////////////////////////////////////////////////////////////////////////// -class NavigationController : public NavigationControllerBase { +class NavigationController { public: // Provides the details for a NOTIFY_NAV_ENTRY_CHANGED notification. struct EntryChangedDetails { @@ -83,13 +84,102 @@ class NavigationController : public NavigationControllerBase { HWND parent); ~NavigationController(); - // Overriden to prompt the user if reloading a URL with POST data and the - // active WebContents isn't showing the POST interstitial page. - virtual void Reload(); - // Same as Reload, but doesn't check if current entry has POST data. void ReloadDontCheckForRepost(); + // Returns the active entry, which is the pending entry if a navigation is in + // progress or the last committed entry otherwise. NOTE: This can be NULL!! + // + // If you are trying to get the current state of the NavigationControllerBase, + // this is the method you will typically want to call. + // + NavigationEntry* GetActiveEntry() const; + + // Returns the index from which we would go back/forward or reload. This is + // the last_committed_entry_index_ if pending_entry_index_ is -1. Otherwise, + // it is the pending_entry_index_. + int GetCurrentEntryIndex() const; + + // Returns the pending entry corresponding to the navigation that is + // currently in progress, or null if there is none. + NavigationEntry* GetPendingEntry() const { + return pending_entry_; + } + + // Returns the index of the pending entry or -1 if the pending entry + // corresponds to a new navigation (created via LoadURL). + int GetPendingEntryIndex() const { + return pending_entry_index_; + } + + // Returns the last committed entry, which may be null if there are no + // committed entries. + NavigationEntry* GetLastCommittedEntry() const; + + // Returns the index of the last committed entry. + int GetLastCommittedEntryIndex() const { + return last_committed_entry_index_; + } + + // Returns the number of entries in the NavigationControllerBase, excluding + // the pending entry if there is one. + int GetEntryCount() const { + return static_cast<int>(entries_.size()); + } + + NavigationEntry* GetEntryAtIndex(int index) const { + return entries_.at(index).get(); + } + + // Returns the entry at the specified offset from current. Returns NULL + // if out of bounds. + NavigationEntry* GetEntryAtOffset(int offset) const; + + bool CanStop() const; + + // Return whether this controller can go back. + bool CanGoBack() const; + + // Return whether this controller can go forward. + bool CanGoForward() const; + + // Causes the controller to go back. + void GoBack(); + + // Causes the controller to go forward. + void GoForward(); + + // Causes the controller to go to the specified index. + void GoToIndex(int index); + + // Causes the controller to go to the specified offset from current. Does + // nothing if out of bounds. + void GoToOffset(int offset); + + // Causes the controller to stop a pending navigation if any. + void Stop(); + + // Causes the controller to reload the current entry. Will prompt the user if + // reloading a URL with POST data and the active WebContents isn't showing the + // POST interstitial page. + void Reload(); + + // Return the entry with the corresponding type, instance, and page_id, or + // NULL if not found. Use a NULL instance if the type is not + // TAB_CONTENTS_WEB. + NavigationEntry* GetEntryWithPageID(TabContentsType type, + SiteInstance* instance, + int32 page_id) const; + + // Causes the controller to load the specified entry. The controller + // assumes ownership of the entry. + // NOTE: Do not pass an entry that the controller already owns! + void LoadEntry(NavigationEntry* entry); + + // Ensure the given NavigationEntry has a valid state, so that WebKit does + // not get confused. + static void SetContentStateIfEmpty(NavigationEntry* entry); + // Begin the destruction sequence for this NavigationController and all its // registered tabs. The sequence is as follows: // 1. All tabs are asked to Destroy themselves. @@ -139,12 +229,19 @@ class NavigationController : public NavigationControllerBase { // -------------------------------------------------------------------------- // For use by TabContents implementors: - virtual void DidNavigateToEntry(NavigationEntry* entry); + // Used to inform the NavigationControllerBase of a navigation being committed + // for a tab. The controller takes ownership of the entry. Any entry located + // forward to the current entry will be deleted. The new entry becomes the + // current entry. + void DidNavigateToEntry(NavigationEntry* entry); + // Calling this may cause the active tab contents to switch if the current // entry corresponds to a different tab contents type. - virtual void DiscardPendingEntry(); + void DiscardPendingEntry(); - virtual void InsertEntry(NavigationEntry* entry); + // Inserts an entry after the current position, removing all entries after it. + // The new entry will become the active one. + void InsertEntry(NavigationEntry* entry); // Returns the identifier used by session restore. const SessionID& session_id() const { return session_id_; } @@ -184,7 +281,16 @@ class NavigationController : public NavigationControllerBase { // if it was restored from a previous session. (-1 otherwise) int max_restored_page_id() const { return max_restored_page_id_; } + // Returns the index of the specified entry, or -1 if entry is not contained + // in this NavigationControllerBase. + int GetIndexOfEntry(const NavigationEntry* entry) const; + + // Removes the last committed entry. + void RemoveLastEntry(); + private: + FRIEND_TEST(NavigationControllerTest, EnforceMaxNavigationCount); + class RestoreHelper; friend class RestoreHelper; @@ -195,17 +301,26 @@ class NavigationController : public NavigationControllerBase { // For invoking GetMaxPageID. friend class printing::PrintViewManager; - virtual int GetMaxPageID() const; - virtual void NavigateToPendingEntry(bool reload); - virtual void NotifyNavigationEntryCommitted(); + // Returns the largest page ID seen. When PageIDs come in larger than + // this (via DidNavigateToEntry), we know that we've navigated to a new page. + int GetMaxPageID() const; + + // Actually issues the navigation held in pending_entry. + void NavigateToPendingEntry(bool reload); - // Lets the history database know navigation entries have been removed. - virtual void NotifyPrunedEntries(); + // Allows the derived class to issue notifications that a load has been + // committed. + void NotifyNavigationEntryCommitted(); - // Updates the history database with the active entry and index. - // Also asks the notifies the active TabContents to notify its - // delegate about the navigation. - virtual void IndexOfActiveEntryChanged(int prev_commited_index); + // Invoked when entries have been pruned, or removed. For example, if the + // current entries are [google, digg, yahoo], with the current entry google, + // and the user types in cnet, then digg and yahoo are pruned. + void NotifyPrunedEntries(); + + // Invoked when the index of the active entry may have changed. + // The prev_commited_index parameter specifies the previous value + // of the last commited index before this navigation event happened + void IndexOfActiveEntryChanged(int prev_commited_index); // Returns the TabContents for the |entry|'s type. If the TabContents // doesn't yet exist, it is created. If a new TabContents is created, its @@ -220,6 +335,13 @@ class NavigationController : public NavigationControllerBase { // Broadcasts a notification that the given entry changed. void NotifyEntryChanged(const NavigationEntry* entry, int index); + // Implementation of Reset and the destructor. Deletes entries + void ResetInternal(); + + // Removes the entry at the specified index. Note that you should not remove + // the pending entry or the last committed entry. + void RemoveEntryAtIndex(int index); + // Sets the max restored page ID this NavigationController has seen, if it // was restored from a previous session. void set_max_restored_page_id(int max_id) { max_restored_page_id_ = max_id; } @@ -240,9 +362,39 @@ class NavigationController : public NavigationControllerBase { // contents. void FinishRestore(HWND parent_hwnd, int selected_index); + // Discards the pending entry without updating active_contents_ + void DiscardPendingEntryInternal(); + + // Return the index of the entry with the corresponding type, instance, and + // page_id, or -1 if not found. Use a NULL instance if the type is not + // TAB_CONTENTS_WEB. + int GetEntryIndexWithPageID(TabContentsType type, + SiteInstance* instance, + int32 page_id) const; + // The user profile associated with this controller Profile* profile_; + // List of NavigationEntry for this tab + typedef std::vector<linked_ptr<NavigationEntry> > NavigationEntries; + NavigationEntries entries_; + + // An entry we haven't gotten a response for yet. This will be discarded + // when we navigate again. It's used only so we know what the currently + // displayed tab is. + // + // This may refer to an item in the entries_ list if the pending_entry_index_ + // == -1, or it may be its own entry that should be deleted. Be careful with + // the memory management. + NavigationEntry* pending_entry_; + + // currently visible entry + int last_committed_entry_index_; + + // index of pending entry if it is in entries_, or -1 if pending_entry_ is a + // new entry (created by LoadURL). + int pending_entry_index_; + // Tab contents. One entry per type used. The tab controller owns // every tab contents used. typedef stdext::hash_map<TabContentsType, TabContents*> TabContentsMap; @@ -288,6 +440,9 @@ class NavigationController : public NavigationControllerBase { // when testing. static bool check_for_repost_; + // The maximum number of entries that a navigation controller can store. + size_t max_entry_count_; + DISALLOW_COPY_AND_ASSIGN(NavigationController); }; diff --git a/chrome/browser/navigation_controller_base.cc b/chrome/browser/navigation_controller_base.cc deleted file mode 100644 index e086e82..0000000 --- a/chrome/browser/navigation_controller_base.cc +++ /dev/null @@ -1,427 +0,0 @@ -// 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_base.h" - -#include <algorithm> - -#include "base/logging.h" -#include "chrome/browser/navigation_entry.h" -#include "chrome/common/notification_service.h" -#include "chrome/common/notification_types.h" -#include "webkit/glue/webkit_glue.h" - -// The maximum number of entries that a navigation controller can store. -const static size_t kMaxEntryCount = 50; - -NavigationControllerBase::NavigationControllerBase() - : pending_entry_(NULL), - last_committed_entry_index_(-1), - pending_entry_index_(-1), - max_entry_count_(kMaxEntryCount) { -} - -NavigationControllerBase::~NavigationControllerBase() { - // NOTE: This does NOT invoke Reset as Reset is virtual. - //ResetInternal(); -} - -/*void NavigationControllerBase::Reset() { - ResetInternal(); - - last_committed_entry_index_ = -1; -}*/ - -NavigationEntry* NavigationControllerBase::GetActiveEntry() const { - NavigationEntry* entry = pending_entry_; - if (!entry) - entry = GetLastCommittedEntry(); - return entry; -} - -int NavigationControllerBase::GetCurrentEntryIndex() const { - if (pending_entry_index_ != -1) - return pending_entry_index_; - return last_committed_entry_index_; -} - -NavigationEntry* NavigationControllerBase::GetLastCommittedEntry() const { - if (last_committed_entry_index_ == -1) - return NULL; - return entries_[last_committed_entry_index_]; -} - -int NavigationControllerBase::GetEntryIndexWithPageID( - TabContentsType type, SiteInstance* instance, int32 page_id) const { - // The instance should only be specified for contents displaying web pages. - // TODO(evanm): checking against NEW_TAB_UI and HTML_DLG here is lame. - // It'd be nice for DomUIHost to just use SiteInstances for keeping content - // separated properly. - if (type != TAB_CONTENTS_WEB && - type != TAB_CONTENTS_NEW_TAB_UI && - type != TAB_CONTENTS_ABOUT_UI && - type != TAB_CONTENTS_HTML_DIALOG && - type != TAB_CONTENTS_VIEW_SOURCE && - type != TAB_CONTENTS_DEBUGGER) - DCHECK(instance == NULL); - - for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { - if ((entries_[i]->GetType() == type) && - (entries_[i]->site_instance() == instance) && - (entries_[i]->GetPageID() == page_id)) - return i; - } - return -1; -} - -NavigationEntry* NavigationControllerBase::GetEntryWithPageID( - TabContentsType type, SiteInstance* instance, int32 page_id) const { - int index = GetEntryIndexWithPageID(type, instance, page_id); - return (index != -1) ? entries_[index] : NULL; -} - -NavigationEntry* NavigationControllerBase::GetEntryAtOffset(int offset) const { - int index = last_committed_entry_index_ + offset; - if (index < 0 || index >= GetEntryCount()) - return NULL; - - return entries_[index]; -} - -bool NavigationControllerBase::CanStop() const { - // TODO(darin): do we have something pending that we can stop? - return false; -} - -bool NavigationControllerBase::CanGoBack() const { - return entries_.size() > 1 && GetCurrentEntryIndex() > 0; -} - -bool NavigationControllerBase::CanGoForward() const { - int index = GetCurrentEntryIndex(); - return index >= 0 && index < (static_cast<int>(entries_.size()) - 1); -} - -void NavigationControllerBase::GoBack() { - if (!CanGoBack()) { - NOTREACHED(); - return; - } - - // Base the navigation on where we are now... - int current_index = GetCurrentEntryIndex(); - - DiscardPendingEntry(); - - pending_entry_index_ = current_index - 1; - NavigateToPendingEntry(false); -} - -void NavigationControllerBase::GoForward() { - if (!CanGoForward()) { - NOTREACHED(); - return; - } - - // Base the navigation on where we are now... - int current_index = GetCurrentEntryIndex(); - - DiscardPendingEntry(); - - pending_entry_index_ = current_index + 1; - NavigateToPendingEntry(false); -} - -void NavigationControllerBase::GoToIndex(int index) { - if (index < 0 || index >= static_cast<int>(entries_.size())) { - NOTREACHED(); - return; - } - - DiscardPendingEntry(); - - pending_entry_index_ = index; - NavigateToPendingEntry(false); -} - -void NavigationControllerBase::GoToOffset(int offset) { - int index = last_committed_entry_index_ + offset; - if (index < 0 || index >= GetEntryCount()) - return; - - GoToIndex(index); -} - -void NavigationControllerBase::Stop() { - DCHECK(CanStop()); - - // TODO(darin): we probably want to just call Stop on the active tab - // contents, but should we also call DiscardPendingEntry? - NOTREACHED() << "implement me"; -} - -void NavigationControllerBase::Reload() { - // Base the navigation on where we are now... - int current_index = GetCurrentEntryIndex(); - - // If we are no where, then we can't reload. TODO(darin): We should add a - // CanReload method. - if (current_index == -1) - return; - - // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? - DiscardPendingEntryInternal(); - - pending_entry_index_ = current_index; - entries_[pending_entry_index_]->SetTransitionType(PageTransition::RELOAD); - NavigateToPendingEntry(true); -} - -void NavigationControllerBase::LoadEntry(NavigationEntry* entry) { - // When navigating to a new page, we don't know for sure if we will actually - // end up leaving the current page. The new page load could for example - // result in a download or a 'no content' response (e.g., a mailto: URL). - - // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? - DiscardPendingEntryInternal(); - pending_entry_ = entry; - // TODO(brettw) the reinterpret cast can be removed once we combine the - // NavigationController and the NavigationControllerBase. - NotificationService::current()->Notify( - NOTIFY_NAV_ENTRY_PENDING, - Source<NavigationController>(reinterpret_cast<NavigationController*>(this)), - NotificationService::NoDetails()); - NavigateToPendingEntry(false); -} - -/* static */ -void NavigationControllerBase::SetContentStateIfEmpty( - NavigationEntry* entry) { - if (entry->GetContentState().empty() && - (entry->GetType() == TAB_CONTENTS_WEB || - entry->GetType() == TAB_CONTENTS_NEW_TAB_UI || - entry->GetType() == TAB_CONTENTS_ABOUT_UI || - entry->GetType() == TAB_CONTENTS_HTML_DIALOG)) { - // The state is empty and the url will be rendered by WebKit. An empty - // state is treated as a new navigation by WebKit, which would mean - // losing the navigation entries and generating a new navigation - // entry after this one. We don't want that. To avoid this we create - // a valid state which WebKit will not treat as a new navigation. - entry->SetContentState( - webkit_glue::CreateHistoryStateForURL(entry->GetURL())); - } -} - -void NavigationControllerBase::DidNavigateToEntry(NavigationEntry* entry) { - SetContentStateIfEmpty(entry); - - entry->set_restored(false); - - // If the entry is that of a page with PageID larger than any this Tab has - // seen before, then consider it a new navigation. Note that if the entry - // has a SiteInstance, it should be the same as the SiteInstance of the - // active WebContents, because we have just navigated to it. - if (entry->GetPageID() > GetMaxPageID()) { - InsertEntry(entry); - NotifyNavigationEntryCommitted(); - return; - } - - // Otherwise, we just need to update an existing entry with matching PageID. - // If the existing entry corresponds to the entry which is pending, then we - // must update the current entry index accordingly. When navigating to the - // same URL, a new PageID is not created. - - int existing_entry_index = GetEntryIndexWithPageID(entry->GetType(), - entry->site_instance(), - entry->GetPageID()); - NavigationEntry* existing_entry = - (existing_entry_index != -1) ? entries_[existing_entry_index] : NULL; - if (!existing_entry) { - // No existing entry, then simply ignore this navigation! - DLOG(WARNING) << "ignoring navigation for page: " << entry->GetPageID(); - } else if ((existing_entry != pending_entry_) && pending_entry_ && - (pending_entry_->GetPageID() == -1) && - (pending_entry_->GetURL() == existing_entry->GetURL())) { - // Not a new navigation. - existing_entry->set_unique_id(pending_entry_->unique_id()); - DiscardPendingEntry(); - } else { - DCHECK(existing_entry != entry); - // The given entry might provide a new URL... e.g., navigating back to a - // page in session history could have resulted in a new client redirect. - // The given entry might also provide a new title (typically an empty title - // to overwrite the existing title). - existing_entry->SetURL(entry->GetURL()); - existing_entry->SetTitle(entry->GetTitle()); - existing_entry->SetFavIconURL(entry->GetFavIconURL()); - existing_entry->SetFavIcon(entry->GetFavIcon()); - existing_entry->SetValidFavIcon(entry->IsValidFavIcon()); - existing_entry->SetContentState(entry->GetContentState()); - - // TODO(brettw) why only copy the security style and no other SSL stuff? - existing_entry->ssl().set_security_style(entry->ssl().security_style()); - - const int prev_entry_index = last_committed_entry_index_; - if (existing_entry == pending_entry_) { - DCHECK(pending_entry_index_ != -1); - last_committed_entry_index_ = pending_entry_index_; - // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? - DiscardPendingEntryInternal(); - } else { - // NOTE: Do not update the unique ID here, as we don't want infobars etc. - // to dismiss. - - // The navigation could have been issued by the renderer, so be sure that - // we update our current index. - last_committed_entry_index_ = existing_entry_index; - } - IndexOfActiveEntryChanged(prev_entry_index); - } - - delete entry; - - NotifyNavigationEntryCommitted(); -} - -void NavigationControllerBase::DiscardPendingEntry() { - DiscardPendingEntryInternal(); - - // Derived classes may do additional things in this case. -} - -int NavigationControllerBase::GetIndexOfEntry( - const NavigationEntry* entry) const { - const NavigationEntries::const_iterator i(std::find(entries_.begin(), - entries_.end(), entry)); - return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin()); -} - -void NavigationControllerBase::DiscardPendingEntryInternal() { - if (pending_entry_index_ == -1) - delete pending_entry_; - pending_entry_ = NULL; - pending_entry_index_ = -1; -} - -void NavigationControllerBase::InsertEntry(NavigationEntry* entry) { - DCHECK(entry->GetTransitionType() != PageTransition::AUTO_SUBFRAME); - - // Copy the pending entry's unique ID to the committed entry. - // I don't know if pending_entry_index_ can be other than -1 here. - const NavigationEntry* const pending_entry = (pending_entry_index_ == -1) ? - pending_entry_ : entries_[pending_entry_index_]; - if (pending_entry) - entry->set_unique_id(pending_entry->unique_id()); - - DiscardPendingEntryInternal(); - - int current_size = static_cast<int>(entries_.size()); - - // Prune any entries which are in front of the current entry. - if (current_size > 0) { - bool pruned = false; - while (last_committed_entry_index_ < (current_size - 1)) { - pruned = true; - delete entries_[current_size - 1]; - entries_.pop_back(); - current_size--; - } - if (pruned) // Only notify if we did prune something. - NotifyPrunedEntries(); - } - - if (entries_.size() >= max_entry_count_) - RemoveEntryAtIndex(0); - - entries_.push_back(entry); - last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1; -} - -void NavigationControllerBase::RemoveLastEntry() { - int current_size = static_cast<int>(entries_.size()); - - if (current_size > 0) { - if (pending_entry_ == entries_[current_size - 1] || - pending_entry_index_ == current_size - 1) - DiscardPendingEntryInternal(); - - delete entries_[current_size - 1]; - entries_.pop_back(); - - if (last_committed_entry_index_ >= current_size - 1) - last_committed_entry_index_ = current_size - 2; - - NotifyPrunedEntries(); - } -} - -void NavigationControllerBase::RemoveEntryAtIndex(int index) { - // TODO(brettw) this is only called to remove the first one when we've got - // too many entries. It should probably be more specific for this case. - if (index >= static_cast<int>(entries_.size()) || - index == pending_entry_index_ || index == last_committed_entry_index_) { - NOTREACHED(); - return; - } - - delete entries_[index]; - entries_.erase(entries_.begin() + index); - - if (last_committed_entry_index_ >= index) { - if (!entries_.empty()) - last_committed_entry_index_--; - else - last_committed_entry_index_ = -1; - } - - // TODO(brettw) bug 1324021: we probably need some notification here so the - // session service can stay in sync. -} - -void NavigationControllerBase::ResetInternal() { - // WARNING: this is invoked from the destructor, be sure not to invoke any - // virtual methods from this. - for (int i = 0, c = static_cast<int>(entries_.size()); i < c; ++i) - delete entries_[i]; - entries_.clear(); - - DiscardPendingEntryInternal(); -} - -#ifndef NDEBUG - -void NavigationControllerBase::Dump() { - int i, c; - for (i = 1, c = static_cast<int>(entries_.size()); i < c; ++i) { - DLOG(INFO) << entries_[i]->GetURL().spec(); - } -} - -#endif diff --git a/chrome/browser/navigation_controller_base.h b/chrome/browser/navigation_controller_base.h deleted file mode 100644 index 0faf365..0000000 --- a/chrome/browser/navigation_controller_base.h +++ /dev/null @@ -1,236 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_NAVIGATION_CONTROLLER_BASE_H_ -#define CHROME_BROWSER_NAVIGATION_CONTROLLER_BASE_H_ - -#include <vector> - -#include "chrome/browser/tab_contents_type.h" -#include "chrome/common/page_transition_types.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -class NavigationEntry; -class SiteInstance; - -//////////////////////////////////////////////////////////////////////////////// -// -// NavigationControllerBase class -// -// A NavigationControllerBase maintains navigation data (like session history). -// -//////////////////////////////////////////////////////////////////////////////// -class NavigationControllerBase { - public: - NavigationControllerBase(); - virtual ~NavigationControllerBase(); - - // Returns the active entry, which is the pending entry if a navigation is in - // progress or the last committed entry otherwise. NOTE: This can be NULL!! - // - // If you are trying to get the current state of the NavigationControllerBase, - // this is the method you will typically want to call. - // - NavigationEntry* GetActiveEntry() const; - - // Returns the index from which we would go back/forward or reload. This is - // the last_committed_entry_index_ if pending_entry_index_ is -1. Otherwise, - // it is the pending_entry_index_. - int GetCurrentEntryIndex() const; - - // Returns the pending entry corresponding to the navigation that is - // currently in progress, or null if there is none. - NavigationEntry* GetPendingEntry() const { - return pending_entry_; - } - - // Returns the index of the pending entry or -1 if the pending entry - // corresponds to a new navigation (created via LoadURL). - int GetPendingEntryIndex() const { - return pending_entry_index_; - } - - // Returns the last committed entry, which may be null if there are no - // committed entries. - NavigationEntry* GetLastCommittedEntry() const; - - // Returns the index of the last committed entry. - int GetLastCommittedEntryIndex() const { - return last_committed_entry_index_; - } - - // Returns the number of entries in the NavigationControllerBase, excluding - // the pending entry if there is one. - int GetEntryCount() const { - return static_cast<int>(entries_.size()); - } - - NavigationEntry* GetEntryAtIndex(int index) const { - return entries_.at(index); - } - - // Returns the entry at the specified offset from current. Returns NULL - // if out of bounds. - NavigationEntry* GetEntryAtOffset(int offset) const; - - bool CanStop() const; - - // Return whether this controller can go back. - bool CanGoBack() const; - - // Return whether this controller can go forward. - bool CanGoForward() const; - - // Causes the controller to go back. - void GoBack(); - - // Causes the controller to go forward. - void GoForward(); - - // Causes the controller to go to the specified index. - void GoToIndex(int index); - - // Causes the controller to go to the specified offset from current. Does - // nothing if out of bounds. - void GoToOffset(int offset); - - // Causes the controller to stop a pending navigation if any. - void Stop(); - - // Causes the controller to reload the current entry. - void Reload(); - - // Causes the controller to load the specified entry. The controller - // assumes ownership of the entry. - // NOTE: Do not pass an entry that the controller already owns! - void LoadEntry(NavigationEntry* entry); - - // Return the entry with the corresponding type, instance, and page_id, or - // NULL if not found. Use a NULL instance if the type is not - // TAB_CONTENTS_WEB. - NavigationEntry* GetEntryWithPageID(TabContentsType type, - SiteInstance* instance, - int32 page_id) const; - - // Ensure the given NavigationEntry has a valid state, so that WebKit does - // not get confused. - static void SetContentStateIfEmpty(NavigationEntry* entry); - -#ifndef NDEBUG - void Dump(); -#endif - - // -------------------------------------------------------------------------- - // For use by NavigationControllerBase clients: - - // Used to inform the NavigationControllerBase of a navigation being committed - // for a tab. The controller takes ownership of the entry. Any entry located - // forward to the current entry will be deleted. The new entry becomes the - // current entry. - virtual void DidNavigateToEntry(NavigationEntry* entry); - - // Used to inform the NavigationControllerBase to discard its pending entry. - virtual void DiscardPendingEntry(); - - // Returns the index of the specified entry, or -1 if entry is not contained - // in this NavigationControllerBase. - int GetIndexOfEntry(const NavigationEntry* entry) const; - - // Removes the last committed entry. - void RemoveLastEntry(); - - protected: - // Returns the largest page ID seen. When PageIDs come in larger than - // this (via DidNavigateToEntry), we know that we've navigated to a new page. - virtual int GetMaxPageID() const = 0; - - // Actually issues the navigation held in pending_entry. - virtual void NavigateToPendingEntry(bool reload) = 0; - - // Allows the derived class to issue notifications that a load has been - // committed. - virtual void NotifyNavigationEntryCommitted() {} - - // Invoked when entries have been pruned, or removed. For example, if the - // current entries are [google, digg, yahoo], with the current entry google, - // and the user types in cnet, then digg and yahoo are pruned. - virtual void NotifyPrunedEntries() {} - - // Invoked when the index of the active entry may have changed. - // The prev_commited_index parameter specifies the previous value - // of the last commited index before this navigation event happened - virtual void IndexOfActiveEntryChanged(int prev_committed_index) {} - - // Inserts an entry after the current position, removing all entries after it. - // The new entry will become the active one. - virtual void InsertEntry(NavigationEntry* entry); - - // Discards the pending entry without updating active_contents_ - void DiscardPendingEntryInternal(); - - // Return the index of the entry with the corresponding type, instance, and - // page_id, or -1 if not found. Use a NULL instance if the type is not - // TAB_CONTENTS_WEB. - int GetEntryIndexWithPageID(TabContentsType type, - SiteInstance* instance, - int32 page_id) const; - - // List of NavigationEntry for this tab - typedef std::vector<NavigationEntry*> NavigationEntries; - NavigationEntries entries_; - - // An entry we haven't gotten a response for yet. This will be discarded - // when we navigate again. It's used only so we know what the currently - // displayed tab is. - NavigationEntry* pending_entry_; - - // currently visible entry - int last_committed_entry_index_; - - // index of pending entry if it is in entries_, or -1 if pending_entry_ is a - // new entry (created by LoadURL). - int pending_entry_index_; - - private: - FRIEND_TEST(NavigationControllerTest, EnforceMaxNavigationCount); - - // Implementation of Reset and the destructor. Deletes entries - void ResetInternal(); - - // Removes the entry at the specified index. Note that you should not remove - // the pending entry or the last committed entry. - void RemoveEntryAtIndex(int index); - - // The maximum number of entries that a navigation controller can store. - size_t max_entry_count_; - - DISALLOW_COPY_AND_ASSIGN(NavigationControllerBase); -}; - -#endif // CHROME_BROWSER_NAVIGATION_CONTROLLER_BASE_H_ |