summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-21 00:51:20 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-21 00:51:20 +0000
commit765b3550e2164b7ccc5360b360ba940639be71c1 (patch)
treefe855f08e9d8a4b7d5384ddea9856584acb7ce73 /chrome
parentefa56b0361925d8a49bf1fc27021a03d24be9f75 (diff)
downloadchromium_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.vcproj8
-rw-r--r--chrome/browser/navigation_controller.cc382
-rw-r--r--chrome/browser/navigation_controller.h193
-rw-r--r--chrome/browser/navigation_controller_base.cc427
-rw-r--r--chrome/browser/navigation_controller_base.h236
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_