summaryrefslogtreecommitdiffstats
path: root/chrome/browser/tab_contents
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-18 19:52:40 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-18 19:52:40 +0000
commit1ef5ad42064c8ef0d1503b68a7fbac01887ca093 (patch)
tree34a32b11a9db6f69fef27e7e81863d82a29bcd2d /chrome/browser/tab_contents
parent59b49a66c3cd959fcf9d7b4bd9c6d88c70b39919 (diff)
downloadchromium_src-1ef5ad42064c8ef0d1503b68a7fbac01887ca093.zip
chromium_src-1ef5ad42064c8ef0d1503b68a7fbac01887ca093.tar.gz
chromium_src-1ef5ad42064c8ef0d1503b68a7fbac01887ca093.tar.bz2
Reverting 14005.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14006 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/tab_contents')
-rw-r--r--chrome/browser/tab_contents/infobar_delegate.cc2
-rw-r--r--chrome/browser/tab_contents/interstitial_page.cc14
-rw-r--r--chrome/browser/tab_contents/navigation_controller.cc108
-rw-r--r--chrome/browser/tab_contents/navigation_controller.h44
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu.cc16
-rw-r--r--chrome/browser/tab_contents/render_view_host_delegate_helper.cc1
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.cc34
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.h8
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager_unittest.cc21
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc85
-rw-r--r--chrome/browser/tab_contents/tab_contents.h76
-rw-r--r--chrome/browser/tab_contents/web_contents.cc327
-rw-r--r--chrome/browser/tab_contents/web_contents.h9
-rw-r--r--chrome/browser/tab_contents/web_contents_unittest.cc160
14 files changed, 573 insertions, 332 deletions
diff --git a/chrome/browser/tab_contents/infobar_delegate.cc b/chrome/browser/tab_contents/infobar_delegate.cc
index 9a466fb..6925dda 100644
--- a/chrome/browser/tab_contents/infobar_delegate.cc
+++ b/chrome/browser/tab_contents/infobar_delegate.cc
@@ -29,7 +29,7 @@ InfoBarDelegate::InfoBarDelegate(TabContents* contents)
}
void InfoBarDelegate::StoreActiveEntryUniqueID(TabContents* contents) {
- NavigationEntry* active_entry = contents->controller().GetActiveEntry();
+ NavigationEntry* active_entry = contents->controller()->GetActiveEntry();
contents_unique_id_ = active_entry ? active_entry->unique_id() : 0;
}
diff --git a/chrome/browser/tab_contents/interstitial_page.cc b/chrome/browser/tab_contents/interstitial_page.cc
index 1ffff17..206bc34 100644
--- a/chrome/browser/tab_contents/interstitial_page.cc
+++ b/chrome/browser/tab_contents/interstitial_page.cc
@@ -121,7 +121,7 @@ InterstitialPage::InterstitialPage(WebContents* tab,
// (which is the case when the interstitial was triggered by a sub-resource on
// a page) when we have a pending entry (in the process of loading a new top
// frame).
- DCHECK(new_navigation || !tab->controller().pending_entry());
+ DCHECK(new_navigation || !tab->controller()->pending_entry());
}
InterstitialPage::~InterstitialPage() {
@@ -169,7 +169,7 @@ void InterstitialPage::Show() {
// Give sub-classes a chance to set some states on the navigation entry.
UpdateEntry(entry);
- tab_->controller().AddTransientEntry(entry);
+ tab_->controller()->AddTransientEntry(entry);
}
DCHECK(!render_view_host_);
@@ -183,9 +183,9 @@ void InterstitialPage::Show() {
notification_registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(tab_));
notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&tab_->controller()));
+ Source<NavigationController>(tab_->controller()));
notification_registrar_.Add(this, NotificationType::NAV_ENTRY_PENDING,
- Source<NavigationController>(&tab_->controller()));
+ Source<NavigationController>(tab_->controller()));
}
void InterstitialPage::Hide() {
@@ -194,7 +194,7 @@ void InterstitialPage::Hide() {
if (tab_->interstitial_page())
tab_->remove_interstitial_page();
// Let's revert to the original title if necessary.
- NavigationEntry* entry = tab_->controller().GetActiveEntry();
+ NavigationEntry* entry = tab_->controller()->GetActiveEntry();
if (!new_navigation_ && should_revert_tab_title_) {
entry->set_title(WideToUTF16Hack(original_tab_title_));
tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE);
@@ -321,7 +321,7 @@ void InterstitialPage::DontProceed() {
// explicitely. Note that by calling DiscardNonCommittedEntries() we also
// discard the pending entry, which is what we want, since the navigation is
// cancelled.
- tab_->controller().DiscardNonCommittedEntries();
+ tab_->controller()->DiscardNonCommittedEntries();
}
Hide();
@@ -383,7 +383,7 @@ void InterstitialPage::UpdateTitle(RenderViewHost* render_view_host,
int32 page_id,
const std::wstring& title) {
DCHECK(render_view_host == render_view_host_);
- NavigationEntry* entry = tab_->controller().GetActiveEntry();
+ NavigationEntry* entry = tab_->controller()->GetActiveEntry();
// If this interstitial is shown on an existing navigation entry, we'll need
// to remember its title so we can revert to it when hidden.
if (!new_navigation_ && !should_revert_tab_title_) {
diff --git a/chrome/browser/tab_contents/navigation_controller.cc b/chrome/browser/tab_contents/navigation_controller.cc
index 268eadb..77cf714 100644
--- a/chrome/browser/tab_contents/navigation_controller.cc
+++ b/chrome/browser/tab_contents/navigation_controller.cc
@@ -15,6 +15,7 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/repost_form_warning.h"
#include "chrome/browser/tab_contents/site_instance.h"
+#include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/navigation_types.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
@@ -120,34 +121,45 @@ NavigationController::NavigationController(TabContents* contents,
ALLOW_THIS_IN_INITIALIZER_LIST(ssl_manager_(this, NULL)),
needs_reload_(false),
load_pending_entry_when_active_(false) {
+ if (contents)
+ contents->set_controller(this);
DCHECK(profile_);
}
-NavigationController::~NavigationController() {
- DiscardNonCommittedEntriesInternal();
-
- NotificationService::current()->Notify(
- NotificationType::TAB_CLOSED,
- Source<NavigationController>(this),
- NotificationService::NoDetails());
-}
-
-void NavigationController::RestoreFromState(
+NavigationController::NavigationController(
+ Profile* profile,
const std::vector<TabNavigation>& navigations,
- int selected_navigation) {
- // Verify that this controller is unused and that the input is valid.
- DCHECK(entry_count() == 0 && !pending_entry());
+ int selected_navigation)
+ : profile_(profile),
+ pending_entry_(NULL),
+ last_committed_entry_index_(-1),
+ pending_entry_index_(-1),
+ transient_entry_index_(-1),
+ tab_contents_(NULL),
+ max_restored_page_id_(-1),
+ ALLOW_THIS_IN_INITIALIZER_LIST(ssl_manager_(this, NULL)),
+ needs_reload_(true),
+ load_pending_entry_when_active_(false) {
+ DCHECK(profile_);
DCHECK(selected_navigation >= 0 &&
selected_navigation < static_cast<int>(navigations.size()));
// Populate entries_ from the supplied TabNavigations.
- needs_reload_ = true;
CreateNavigationEntriesFromTabNavigations(navigations, &entries_);
// And finish the restore.
FinishRestore(selected_navigation);
}
+NavigationController::~NavigationController() {
+ DiscardNonCommittedEntriesInternal();
+
+ NotificationService::current()->Notify(
+ NotificationType::TAB_CLOSED,
+ Source<NavigationController>(this),
+ NotificationService::NoDetails());
+}
+
void NavigationController::Reload(bool check_for_repost) {
// Reloading a transient entry does nothing.
if (transient_entry_index_ != -1)
@@ -339,6 +351,19 @@ void NavigationController::RemoveEntryAtIndex(int index,
}
}
+void NavigationController::Destroy() {
+ // TODO(brettw) the destruction of TabContents/NavigationController makes no
+ // sense (see TabContentsWasDestroyed)
+ tab_contents_->Destroy();
+ // We are now deleted.
+}
+
+void NavigationController::TabContentsWasDestroyed() {
+ // TODO(brettw) the destruction of TabContents/NavigationController makes no
+ // sense (see Destroy).
+ delete this;
+}
+
NavigationEntry* NavigationController::CreateNavigationEntry(
const GURL& url, const GURL& referrer, PageTransition::Type transition) {
// Allow the browser URL handler to rewrite the URL. This will, for example,
@@ -396,7 +421,7 @@ void NavigationController::LoadURLLazily(const GURL& url,
load_pending_entry_when_active_ = true;
}
-bool NavigationController::LoadingURLLazily() const {
+bool NavigationController::LoadingURLLazily() {
return load_pending_entry_when_active_;
}
@@ -716,7 +741,6 @@ bool NavigationController::RendererDidNavigateAutoSubframe(
return false;
}
-// TODO(brettw) I think this function is unnecessary.
void NavigationController::CommitPendingEntry() {
DiscardTransientEntry();
@@ -779,22 +803,6 @@ bool NavigationController::IsURLInPageNavigation(const GURL& url) const {
return AreURLsInPageNavigation(last_committed->url(), url);
}
-void NavigationController::CopyStateFrom(const NavigationController& source) {
- // Verify that we look new.
- DCHECK(entry_count() == 0 && !pending_entry());
-
- if (source.entry_count() == 0)
- return; // Nothing new to do.
-
- needs_reload_ = true;
- for (int i = 0; i < source.entry_count(); i++) {
- entries_.push_back(linked_ptr<NavigationEntry>(
- new NavigationEntry(*source.entries_[i])));
- }
-
- FinishRestore(source.last_committed_entry_index_);
-}
-
void NavigationController::DiscardNonCommittedEntries() {
bool transient = transient_entry_index_ != -1;
DiscardNonCommittedEntriesInternal();
@@ -859,6 +867,9 @@ void NavigationController::NavigateToPendingEntry(bool reload) {
pending_entry_ = entries_[pending_entry_index_].get();
}
+ tab_contents_ = GetTabContentsCreateIfNecessary(*pending_entry_);
+
+ NavigationEntry temp_entry(*pending_entry_);
if (!tab_contents_->NavigateToPendingEntry(reload))
DiscardNonCommittedEntries();
}
@@ -878,6 +889,17 @@ void NavigationController::NotifyNavigationEntryCommitted(
Details<LoadCommittedDetails>(details));
}
+TabContents* NavigationController::GetTabContentsCreateIfNecessary(
+ const NavigationEntry& entry) {
+ if (tab_contents_)
+ return tab_contents_;
+
+ tab_contents_ = new WebContents(profile_, entry.site_instance(),
+ MSG_ROUTING_NONE, NULL);
+ tab_contents_->set_controller(this);
+ return tab_contents_; // TODO(brettw) it's stupid to both set and return it.
+}
+
// static
void NavigationController::DisablePromptOnRepost() {
check_for_repost_ = false;
@@ -916,6 +938,25 @@ void NavigationController::NotifyEntryChanged(const NavigationEntry* entry,
Details<EntryChangedDetails>(&det));
}
+NavigationController* NavigationController::Clone() {
+ NavigationController* nc = new NavigationController(NULL, profile_);
+
+ if (entry_count() == 0)
+ return nc;
+
+ nc->needs_reload_ = true;
+
+ nc->entries_.reserve(entries_.size());
+ for (int i = 0, c = entry_count(); i < c; ++i) {
+ nc->entries_.push_back(linked_ptr<NavigationEntry>(
+ new NavigationEntry(*GetEntryAtIndex(i))));
+ }
+
+ nc->FinishRestore(last_committed_entry_index_);
+
+ return nc;
+}
+
void NavigationController::FinishRestore(int selected_index) {
DCHECK(selected_index >= 0 && selected_index < entry_count());
ConfigureEntriesForRestore(&entries_);
@@ -923,6 +964,9 @@ void NavigationController::FinishRestore(int selected_index) {
set_max_restored_page_id(entry_count());
last_committed_entry_index_ = selected_index;
+
+ // Callers assume we have an active_contents after restoring, so set it now.
+ tab_contents_ = GetTabContentsCreateIfNecessary(*entries_[selected_index]);
}
void NavigationController::DiscardNonCommittedEntriesInternal() {
diff --git a/chrome/browser/tab_contents/navigation_controller.h b/chrome/browser/tab_contents/navigation_controller.h
index e42f4ad..af7cf60 100644
--- a/chrome/browser/tab_contents/navigation_controller.h
+++ b/chrome/browser/tab_contents/navigation_controller.h
@@ -123,21 +123,34 @@ class NavigationController {
// ---------------------------------------------------------------------------
- NavigationController(TabContents* tab_contents, Profile* profile);
+ NavigationController(TabContents* initial_contents, Profile* profile);
+
+ // Creates a NavigationController from the specified history. Processing
+ // for this is asynchronous and handled via the RestoreHelper (in
+ // navigation_controller.cc).
+ NavigationController(
+ Profile* profile,
+ const std::vector<TabNavigation>& navigations,
+ int selected_navigation);
~NavigationController();
+ // 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.
+ // 2. When each tab is finished Destroying, it will notify the controller.
+ // 3. Once all tabs are Destroyed, the NavigationController deletes itself.
+ // This ensures that all the TabContents outlive the NavigationController.
+ void Destroy();
+
+ // Clone the receiving navigation controller. Only the active tab contents is
+ // duplicated.
+ NavigationController* Clone();
+
// Returns the profile for this controller. It can never be NULL.
Profile* profile() const {
return profile_;
}
- // Initializes this NavigationController with the given saved navigations,
- // using selected_navigation as the currently loaded entry. Before this call
- // the controller should be unused (there should be no current entry). This is
- // used for session restore.
- void RestoreFromState(const std::vector<TabNavigation>& navigations,
- int selected_navigation);
-
// Active entry --------------------------------------------------------------
// Returns the active entry, which is the transient entry if any, the pending
@@ -282,6 +295,10 @@ class NavigationController {
// TabContents ---------------------------------------------------------------
+ // Notifies the controller that a TabContents that it owns has been destroyed.
+ // This is part of the NavigationController's Destroy sequence.
+ void TabContentsWasDestroyed();
+
// Returns the tab contents associated with this controller. Non-NULL except
// during set-up of the tab.
TabContents* tab_contents() const {
@@ -329,17 +346,13 @@ class NavigationController {
// refs without reload, only change to "#" which we don't count as empty).
bool IsURLInPageNavigation(const GURL& url) const;
- // Copies the navigation state from the given controller to this one. This
- // one should be empty (just created).
- void CopyStateFrom(const NavigationController& source);
-
// Random data ---------------------------------------------------------------
// Returns true if this NavigationController is is configured to load a URL
// lazily. If true, use GetLazyTitle() and GetLazyFavIcon() to discover the
// titles and favicons. Since no request was made, this is the only info
// we have about this page. This feature is used by web application clusters.
- bool LoadingURLLazily() const;
+ bool LoadingURLLazily();
const string16& GetLazyTitle() const;
const SkBitmap& GetLazyFavIcon() const;
@@ -412,6 +425,11 @@ class NavigationController {
// committed. This will fill in the active entry to the details structure.
void NotifyNavigationEntryCommitted(LoadCommittedDetails* details);
+ // 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
+ // parent is |parent|. Becomes part of |entry|'s SiteInstance.
+ TabContents* GetTabContentsCreateIfNecessary(const NavigationEntry& entry);
+
// 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; }
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index 698a65a..fd94e13 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -208,10 +208,10 @@ bool RenderViewContextMenu::IsItemCommandEnabled(int id) const {
switch (id) {
case IDS_CONTENT_CONTEXT_BACK:
- return source_web_contents_->controller().CanGoBack();
+ return source_web_contents_->controller()->CanGoBack();
case IDS_CONTENT_CONTEXT_FORWARD:
- return source_web_contents_->controller().CanGoForward();
+ return source_web_contents_->controller()->CanGoForward();
case IDS_CONTENT_CONTEXT_VIEWPAGESOURCE:
case IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE:
@@ -283,7 +283,7 @@ bool RenderViewContextMenu::IsItemCommandEnabled(int id) const {
return !params_.misspelled_word.empty();
case IDS_CONTENT_CONTEXT_VIEWPAGEINFO:
- return (source_web_contents_->controller().GetActiveEntry() != NULL);
+ return (source_web_contents_->controller()->GetActiveEntry() != NULL);
case IDS_CONTENT_CONTEXT_RELOAD:
case IDS_CONTENT_CONTEXT_COPYIMAGE:
@@ -393,11 +393,11 @@ void RenderViewContextMenu::ExecuteItemCommand(int id) {
break;
case IDS_CONTENT_CONTEXT_BACK:
- source_web_contents_->controller().GoBack();
+ source_web_contents_->controller()->GoBack();
break;
case IDS_CONTENT_CONTEXT_FORWARD:
- source_web_contents_->controller().GoForward();
+ source_web_contents_->controller()->GoForward();
break;
case IDS_CONTENT_CONTEXT_SAVEPAGEAS:
@@ -405,7 +405,7 @@ void RenderViewContextMenu::ExecuteItemCommand(int id) {
break;
case IDS_CONTENT_CONTEXT_RELOAD:
- source_web_contents_->controller().Reload(true);
+ source_web_contents_->controller()->Reload(true);
break;
case IDS_CONTENT_CONTEXT_PRINT:
@@ -424,7 +424,7 @@ void RenderViewContextMenu::ExecuteItemCommand(int id) {
case IDS_CONTENT_CONTEXT_VIEWPAGEINFO: {
#if defined(OS_WIN)
NavigationEntry* nav_entry =
- source_web_contents_->controller().GetActiveEntry();
+ source_web_contents_->controller()->GetActiveEntry();
PageInfoWindow::CreatePageInfo(
source_web_contents_->profile(),
nav_entry,
@@ -581,7 +581,7 @@ bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
return true;
NavigationEntry *active_entry =
- source_web_contents_->controller().GetActiveEntry();
+ source_web_contents_->controller()->GetActiveEntry();
if (!active_entry)
return false;
diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
index 9268850..9846a77 100644
--- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
+++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
@@ -29,6 +29,7 @@ void RenderViewHostDelegateViewHelper::CreateNewWindow(int route_id,
site,
route_id,
modal_dialog_event);
+ new_contents->SetupController(profile);
WebContentsView* new_view = new_contents->view();
// TODO(brettw) it seems bogus that we have to call this function on the
diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc
index 8b2c276..a178356 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager.cc
@@ -37,13 +37,9 @@ RenderViewHostManager::RenderViewHostManager(
}
RenderViewHostManager::~RenderViewHostManager() {
- if (pending_render_view_host_)
- CancelPending();
-
- // We should always have a main RenderViewHost.
- RenderViewHost* render_view_host = render_view_host_;
- render_view_host_ = NULL;
- render_view_host->Shutdown();
+ // Shutdown should have been called which should have cleaned these up.
+ DCHECK(!render_view_host_);
+ DCHECK(!pending_render_view_host_);
}
void RenderViewHostManager::Init(Profile* profile,
@@ -59,6 +55,16 @@ void RenderViewHostManager::Init(Profile* profile,
site_instance, render_view_delegate_, routing_id, modal_dialog_event);
}
+void RenderViewHostManager::Shutdown() {
+ if (pending_render_view_host_)
+ CancelPending();
+
+ // We should always have a main RenderViewHost.
+ RenderViewHost* render_view_host = render_view_host_;
+ render_view_host_ = NULL;
+ render_view_host->Shutdown();
+}
+
RenderViewHost* RenderViewHostManager::Navigate(const NavigationEntry& entry) {
// This will possibly create (set to NULL) a DOM UI object for the pending
// page. We'll use this later to give the page special access. This must
@@ -99,7 +105,7 @@ RenderViewHost* RenderViewHostManager::Navigate(const NavigationEntry& entry) {
NotificationService::current()->Notify(
NotificationType::RENDER_VIEW_HOST_CHANGED,
Source<NavigationController>(
- &delegate_->GetControllerForRenderManager()),
+ delegate_->GetControllerForRenderManager()),
Details<RenderViewHostSwitchedDetails>(&details));
}
}
@@ -350,12 +356,12 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
// For now, though, we're in a hybrid model where you only switch
// SiteInstances if you type in a cross-site URL. This means we have to
// compare the entry's URL to the last committed entry's URL.
- NavigationController& controller = delegate_->GetControllerForRenderManager();
- NavigationEntry* curr_entry = controller.GetLastCommittedEntry();
+ NavigationController* controller = delegate_->GetControllerForRenderManager();
+ NavigationEntry* curr_entry = controller->GetLastCommittedEntry();
if (interstitial_page_) {
// The interstitial is currently the last committed entry, but we want to
// compare against the last non-interstitial entry.
- curr_entry = controller.GetEntryAtOffset(-1);
+ curr_entry = controller->GetEntryAtOffset(-1);
}
// If there is no last non-interstitial entry (and curr_instance already
// has a site), then we must have been opened from another tab. We want
@@ -380,7 +386,7 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
// that page, we want to explicity ignore that BrowsingInstance and make a
// new process.
return SiteInstance::CreateSiteInstance(
- delegate_->GetControllerForRenderManager().profile());
+ delegate_->GetControllerForRenderManager()->profile());
} else {
// Start the new renderer in a new SiteInstance, but in the current
// BrowsingInstance. It is important to immediately give this new
@@ -393,7 +399,7 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
bool RenderViewHostManager::CreatePendingRenderView(SiteInstance* instance) {
NavigationEntry* curr_entry =
- delegate_->GetControllerForRenderManager().GetLastCommittedEntry();
+ delegate_->GetControllerForRenderManager()->GetLastCommittedEntry();
if (curr_entry) {
DCHECK(!curr_entry->content_state().empty());
// TODO(creis): Should send a message to the RenderView to let it know
@@ -460,7 +466,7 @@ void RenderViewHostManager::CommitPending() {
details.old_host = old_render_view_host;
NotificationService::current()->Notify(
NotificationType::RENDER_VIEW_HOST_CHANGED,
- Source<NavigationController>(&delegate_->GetControllerForRenderManager()),
+ Source<NavigationController>(delegate_->GetControllerForRenderManager()),
Details<RenderViewHostSwitchedDetails>(&details));
old_render_view_host->Shutdown();
diff --git a/chrome/browser/tab_contents/render_view_host_manager.h b/chrome/browser/tab_contents/render_view_host_manager.h
index 15ee081..b3a5b25 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.h
+++ b/chrome/browser/tab_contents/render_view_host_manager.h
@@ -47,7 +47,7 @@ class RenderViewHostManager : public NotificationObserver {
RenderViewHost* render_view_host) = 0;
virtual void UpdateRenderViewSizeForRenderManager() = 0;
virtual void NotifySwappedFromRenderManager() = 0;
- virtual NavigationController& GetControllerForRenderManager() = 0;
+ virtual NavigationController* GetControllerForRenderManager() = 0;
// Creates a DOMUI object for the given URL if one applies. Ownership of the
// returned pointer will be passed to the caller. If no DOMUI applies,
@@ -64,7 +64,8 @@ class RenderViewHostManager : public NotificationObserver {
// They must outlive this class. The RenderViewHostDelegate is what will be
// installed into all RenderViewHosts that are created.
//
- // You must call Init() before using this class.
+ // You must call Init() before using this class and Shutdown() before
+ // deleting it.
RenderViewHostManager(RenderViewHostDelegate* render_view_delegate,
Delegate* delegate);
~RenderViewHostManager();
@@ -75,6 +76,9 @@ class RenderViewHostManager : public NotificationObserver {
int routing_id,
base::WaitableEvent* modal_dialog_event);
+ // Schedules all RenderViewHosts for destruction.
+ void Shutdown();
+
// Returns the currently actuive RenderViewHost.
//
// This will be non-NULL between Init() and Shutdown(). You may want to NULL
diff --git a/chrome/browser/tab_contents/render_view_host_manager_unittest.cc b/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
index f0caccd..02f5473 100644
--- a/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
@@ -23,22 +23,27 @@ TEST_F(RenderViewHostManagerTest, NewTabPageProcesses) {
NavigateAndCommit(dest);
// Make a second tab.
- TestWebContents contents2(profile_.get(), NULL);
+ WebContents* contents2 = new TestWebContents(profile_.get(), NULL);
+ NavigationController* controller2 =
+ new NavigationController(contents2, profile_.get());
+ contents2->set_controller(controller2);
// Load the two URLs in the second tab. Note that the first navigation creates
// a RVH that's not pending (since there is no cross-site transition), so
// we use the committed one, but the second one is the opposite.
- contents2.controller().LoadURL(ntp, GURL(), PageTransition::LINK);
- static_cast<TestRenderViewHost*>(contents2.render_manager()->
+ contents2->controller()->LoadURL(ntp, GURL(), PageTransition::LINK);
+ static_cast<TestRenderViewHost*>(contents2->render_manager()->
current_host())->SendNavigate(100, ntp);
- contents2.controller().LoadURL(dest, GURL(), PageTransition::LINK);
- static_cast<TestRenderViewHost*>(contents2.render_manager()->
+ contents2->controller()->LoadURL(dest, GURL(), PageTransition::LINK);
+ static_cast<TestRenderViewHost*>(contents2->render_manager()->
pending_render_view_host())->SendNavigate(101, dest);
// The two RVH's should be different in every way.
- EXPECT_NE(rvh()->process(), contents2.render_view_host()->process());
+ EXPECT_NE(rvh()->process(), contents2->render_view_host()->process());
EXPECT_NE(rvh()->site_instance(),
- contents2.render_view_host()->site_instance());
+ contents2->render_view_host()->site_instance());
EXPECT_NE(rvh()->site_instance()->browsing_instance(),
- contents2.render_view_host()->site_instance()->browsing_instance());
+ contents2->render_view_host()->site_instance()->browsing_instance());
+
+ contents2->CloseContents();
}
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 226ce5b..ea5a9b5 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -24,9 +24,9 @@
#include "chrome/views/controls/scrollbar/native_scroll_bar.h"
#endif
-TabContents::TabContents(Profile* profile)
+TabContents::TabContents()
: delegate_(NULL),
- controller_(this, profile),
+ controller_(NULL),
is_loading_(false),
is_crashed_(false),
waiting_for_response_(false),
@@ -45,13 +45,71 @@ void TabContents::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kBlockPopups, false);
}
+void TabContents::CloseContents() {
+ // Destroy our NavigationController, which will Destroy all tabs it owns.
+ controller_->Destroy();
+ // Note that the controller may have deleted us at this point,
+ // so don't touch any member variables here.
+}
+
+void TabContents::Destroy() {
+ DCHECK(!is_being_destroyed_);
+ is_being_destroyed_ = true;
+
+ // First cleanly close all child windows.
+ // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
+ // some of these to close. CloseWindows is async, so it might get called
+ // twice before it runs.
+ int size = static_cast<int>(child_windows_.size());
+ for (int i = size - 1; i >= 0; --i) {
+ ConstrainedWindow* window = child_windows_[i];
+ if (window)
+ window->CloseConstrainedWindow();
+ }
+
+ // Notify any lasting InfobarDelegates that have not yet been removed that
+ // whatever infobar they were handling in this TabContents has closed,
+ // because the TabContents is going away entirely.
+ for (int i = 0; i < infobar_delegate_count(); ++i) {
+ InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
+ delegate->InfoBarClosed();
+ }
+ infobar_delegates_.clear();
+
+ // Notify any observer that have a reference on this tab contents.
+ NotificationService::current()->Notify(
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(this),
+ NotificationService::NoDetails());
+
+#if defined(OS_WIN)
+ // If we still have a window handle, destroy it. GetNativeView can return
+ // NULL if this contents was part of a window that closed.
+ if (GetNativeView())
+ ::DestroyWindow(GetNativeView());
+#endif
+
+ // Notify our NavigationController. Make sure we are deleted first, so
+ // that the controller is the last to die.
+ NavigationController* controller = controller_;
+
+ delete this;
+
+ controller->TabContentsWasDestroyed();
+}
+
+void TabContents::SetupController(Profile* profile) {
+ DCHECK(!controller_);
+ controller_ = new NavigationController(this, profile);
+}
+
bool TabContents::SupportsURL(GURL* url) {
return true;
}
const GURL& TabContents::GetURL() const {
// We may not have a navigation entry yet
- NavigationEntry* entry = controller_.GetActiveEntry();
+ NavigationEntry* entry = controller_->GetActiveEntry();
return entry ? entry->display_url() : GURL::EmptyGURL();
}
@@ -82,22 +140,22 @@ const std::wstring TabContents::GetDefaultTitle() const {
SkBitmap TabContents::GetFavIcon() const {
// Like GetTitle(), we also want to use the favicon for the last committed
// entry rather than a pending navigation entry.
- NavigationEntry* entry = controller_.GetTransientEntry();
+ NavigationEntry* entry = controller_->GetTransientEntry();
if (entry)
return entry->favicon().bitmap();
- entry = controller_.GetLastCommittedEntry();
+ entry = controller_->GetLastCommittedEntry();
if (entry)
return entry->favicon().bitmap();
- else if (controller_.LoadingURLLazily())
- return controller_.GetLazyFavIcon();
+ else if (controller_->LoadingURLLazily())
+ return controller_->GetLazyFavIcon();
return SkBitmap();
}
#if defined(OS_WIN)
SecurityStyle TabContents::GetSecurityStyle() const {
// We may not have a navigation entry yet.
- NavigationEntry* entry = controller_.GetActiveEntry();
+ NavigationEntry* entry = controller_->GetActiveEntry();
return entry ? entry->ssl().security_style() : SECURITY_STYLE_UNKNOWN;
}
@@ -107,7 +165,7 @@ bool TabContents::GetSSLEVText(std::wstring* ev_text,
ev_text->clear();
ev_tooltip_text->clear();
- NavigationEntry* entry = controller_.GetActiveEntry();
+ NavigationEntry* entry = controller_->GetActiveEntry();
if (!entry ||
net::IsCertStatusError(entry->ssl().cert_status()) ||
((entry->ssl().cert_status() & net::CERT_STATUS_IS_EV) == 0))
@@ -153,8 +211,8 @@ void TabContents::OpenURL(const GURL& url, const GURL& referrer,
bool TabContents::NavigateToPendingEntry(bool reload) {
// Our benavior is just to report that the entry was committed.
string16 default_title = WideToUTF16Hack(GetDefaultTitle());
- controller_.pending_entry()->set_title(default_title);
- controller_.CommitPendingEntry();
+ controller()->pending_entry()->set_title(default_title);
+ controller()->CommitPendingEntry();
return true;
}
@@ -244,8 +302,9 @@ void TabContents::AddInfoBar(InfoBarDelegate* delegate) {
// added. We use this notification to expire InfoBars that need to expire on
// page transitions.
if (infobar_delegates_.size() == 1) {
+ DCHECK(controller());
registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&controller_));
+ Source<NavigationController>(controller()));
}
}
@@ -263,7 +322,7 @@ void TabContents::RemoveInfoBar(InfoBarDelegate* delegate) {
// Remove ourselves as an observer if we are tracking no more InfoBars.
if (infobar_delegates_.empty()) {
registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&controller_));
+ Source<NavigationController>(controller()));
}
}
}
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index aa636f3..26dda95 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -44,8 +44,23 @@ class SkBitmap;
class SiteInstance;
class WebContents;
-// Describes what goes in the main content area of a tab. WebContents is
-// the only type of TabContents, and these should be merged together.
+// Describes what goes in the main content area of a tab. For example,
+// the WebContents is one such thing.
+//
+// When instantiating a new TabContents explicitly, the TabContents will not
+// have an associated NavigationController. To setup a NavigationController
+// for the TabContents, its SetupController method should be called.
+//
+// Once they reside within a NavigationController, TabContents objects are
+// owned by that NavigationController. When the active TabContents within that
+// NavigationController is closed, that TabContents destroys the
+// NavigationController, which then destroys all of the TabContentses in it.
+//
+// NOTE: When the NavigationController is navigated to an URL corresponding to
+// a different type of TabContents (see the TabContents::TypeForURL method),
+// the NavigationController makes the active TabContents inactive, notifies the
+// TabContentsDelegate that the TabContents is being replaced, and then
+// activates the new TabContents.
class TabContents : public PageNavigator,
public NotificationObserver {
public:
@@ -62,10 +77,23 @@ class TabContents : public PageNavigator,
INVALIDATE_EVERYTHING = 0xFFFFFFFF
};
- virtual ~TabContents();
-
static void RegisterUserPrefs(PrefService* prefs);
+ // Creation & destruction ----------------------------------------------------
+
+ // Request this tab to shut down. This kills the tab's NavigationController,
+ // which then Destroy()s all tabs it controls.
+ void CloseContents();
+
+ // Unregister/shut down any pending tasks involving this tab.
+ // This is called as the tab is shutting down, before the
+ // NavigationController (and consequently profile) are gone.
+ //
+ // If you override this, be sure to call this implementation at the end
+ // of yours.
+ // See also Close().
+ virtual void Destroy() = 0;
+
// Intrinsic tab state -------------------------------------------------------
// Returns the property bag for this tab contents, where callers can add
@@ -88,13 +116,27 @@ class TabContents : public PageNavigator,
TabContentsDelegate* delegate() const { return delegate_; }
void set_delegate(TabContentsDelegate* d) { delegate_ = d; }
- // Gets the controller for this tab contents.
- NavigationController& controller() { return controller_; }
- const NavigationController& controller() const { return controller_; }
+ // This can only be null if the TabContents has been created but
+ // SetupController has not been called. The controller should always outlive
+ // its TabContents.
+ NavigationController* controller() const { return controller_; }
+ void set_controller(NavigationController* c) { controller_ = c; }
+
+ // Sets up a new NavigationController for this TabContents.
+ // |profile| is the user profile that should be associated with
+ // the new controller.
+ //
+ // TODO(brettw) this seems bogus and I couldn't find any legitimate need for
+ // it. I think it should be passed in the constructor.
+ void SetupController(Profile* profile);
// Returns the user profile associated with this TabContents (via the
- // NavigationController).
- Profile* profile() const { return controller_.profile(); }
+ // NavigationController). This will return NULL if there isn't yet a
+ // NavigationController on this TabContents.
+ // TODO(darin): make it so that controller_ can never be null
+ Profile* profile() const {
+ return controller_ ? controller_->profile() : NULL;
+ }
// Returns whether this tab contents supports the provided URL.This method
// matches the tab contents type with the result of TypeForURL(). |url| points
@@ -231,10 +273,6 @@ class TabContents : public PageNavigator,
// Called on a TabContents when it isn't a popup, but a new window.
virtual void DisassociateFromPopupCount() = 0;
- // Creates a new TabContents with the same state as this one. The returned
- // heap-allocated pointer is owned by the caller.
- virtual TabContents* Clone() = 0;
-
// Window management ---------------------------------------------------------
#if defined(OS_WIN)
@@ -348,7 +386,15 @@ class TabContents : public PageNavigator,
// automation purposes.
friend class AutomationProvider;
- TabContents(Profile* profile);
+ TabContents();
+
+ // NOTE: the TabContents destructor can run after the NavigationController
+ // has gone away, so any complicated unregistering that expects the profile
+ // or other shared objects to still be around does not belong in a
+ // destructor.
+ // For those purposes, instead see Destroy().
+ // Protected so that others don't try to delete this directly.
+ virtual ~TabContents();
// Changes the IsLoading state and notifies delegate as needed
// |details| is used to provide details on the load that just finished
@@ -386,7 +432,7 @@ class TabContents : public PageNavigator,
// Data ----------------------------------------------------------------------
TabContentsDelegate* delegate_;
- NavigationController controller_;
+ NavigationController* controller_;
PropertyBag property_bag_;
diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc
index 8592522..bf70542 100644
--- a/chrome/browser/tab_contents/web_contents.cc
+++ b/chrome/browser/tab_contents/web_contents.cc
@@ -203,8 +203,7 @@ WebContents::WebContents(Profile* profile,
SiteInstance* site_instance,
int routing_id,
base::WaitableEvent* modal_dialog_event)
- : TabContents(profile),
- view_(WebContentsView::Create(this)),
+ : view_(WebContentsView::Create(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(render_manager_(this, this)),
printing_(*this),
notify_disconnection_(false),
@@ -235,12 +234,14 @@ WebContents::WebContents(Profile* profile,
}
// Register for notifications about URL starredness changing on any profile.
- registrar_.Add(this, NotificationType::URLS_STARRED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DESTROYED,
- NotificationService::AllSources());
+ NotificationService::current()->AddObserver(
+ this, NotificationType::URLS_STARRED, NotificationService::AllSources());
+ NotificationService::current()->AddObserver(
+ this, NotificationType::BOOKMARK_MODEL_LOADED,
+ NotificationService::AllSources());
+ NotificationService::current()->AddObserver(
+ this, NotificationType::RENDER_WIDGET_HOST_DESTROYED,
+ NotificationService::AllSources());
// Keep a global copy of the previous search string (if any).
static string16 global_last_search = string16();
@@ -248,60 +249,11 @@ WebContents::WebContents(Profile* profile,
}
WebContents::~WebContents() {
- is_being_destroyed_ = true;
-
- // We don't want any notifications while we're runnign our destructor.
- registrar_.RemoveAll();
-
- // Unregister the notifications of all observed prefs change.
- PrefService* prefs = profile()->GetPrefs();
- if (prefs) {
- for (int i = 0; i < kPrefsToObserveLength; ++i)
- prefs->RemovePrefObserver(kPrefsToObserve[i], this);
- }
-
- // Clean up subwindows like plugins and the find in page bar.
- view_->OnContentsDestroy();
-
- NotifyDisconnected();
- HungRendererWarning::HideForWebContents(this);
-
if (pending_install_.callback_functor)
pending_install_.callback_functor->Cancel();
-
- // First cleanly close all child windows.
- // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
- // some of these to close. CloseWindows is async, so it might get called
- // twice before it runs.
- int size = static_cast<int>(child_windows_.size());
- for (int i = size - 1; i >= 0; --i) {
- ConstrainedWindow* window = child_windows_[i];
- if (window)
- window->CloseConstrainedWindow();
- }
-
- // Notify any lasting InfobarDelegates that have not yet been removed that
- // whatever infobar they were handling in this TabContents has closed,
- // because the TabContents is going away entirely.
- for (int i = 0; i < infobar_delegate_count(); ++i) {
- InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
- delegate->InfoBarClosed();
- }
- infobar_delegates_.clear();
-
- // Notify any observer that have a reference on this tab contents.
- NotificationService::current()->Notify(
- NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(this),
- NotificationService::NoDetails());
-
- // TODO(brettw) this should be moved to the view.
-#if defined(OS_WIN)
- // If we still have a window handle, destroy it. GetNativeView can return
- // NULL if this contents was part of a window that closed.
- if (GetNativeView())
- ::DestroyWindow(GetNativeView());
-#endif
+ NotificationService::current()->RemoveObserver(
+ this, NotificationType::RENDER_WIDGET_HOST_DESTROYED,
+ NotificationService::AllSources());
}
// static
@@ -378,6 +330,78 @@ PluginInstaller* WebContents::GetPluginInstaller() {
return plugin_installer_.get();
}
+void WebContents::Destroy() {
+ DCHECK(!is_being_destroyed_);
+ is_being_destroyed_ = true;
+
+ // Tell the notification service we no longer want notifications.
+ NotificationService::current()->RemoveObserver(
+ this, NotificationType::URLS_STARRED, NotificationService::AllSources());
+ NotificationService::current()->RemoveObserver(
+ this, NotificationType::BOOKMARK_MODEL_LOADED,
+ NotificationService::AllSources());
+
+ // Destroy the print manager right now since a Print command may be pending.
+ printing_.Destroy();
+
+ // Unregister the notifications of all observed prefs change.
+ PrefService* prefs = profile()->GetPrefs();
+ if (prefs) {
+ for (int i = 0; i < kPrefsToObserveLength; ++i)
+ prefs->RemovePrefObserver(kPrefsToObserve[i], this);
+ }
+
+ cancelable_consumer_.CancelAllRequests();
+
+ // Clean up subwindows like plugins and the find in page bar.
+ view_->OnContentsDestroy();
+
+ NotifyDisconnected();
+ HungRendererWarning::HideForWebContents(this);
+ render_manager_.Shutdown();
+
+ // First cleanly close all child windows.
+ // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
+ // some of these to close. CloseWindows is async, so it might get called
+ // twice before it runs.
+ int size = static_cast<int>(child_windows_.size());
+ for (int i = size - 1; i >= 0; --i) {
+ ConstrainedWindow* window = child_windows_[i];
+ if (window)
+ window->CloseConstrainedWindow();
+ }
+
+ // Notify any lasting InfobarDelegates that have not yet been removed that
+ // whatever infobar they were handling in this TabContents has closed,
+ // because the TabContents is going away entirely.
+ for (int i = 0; i < infobar_delegate_count(); ++i) {
+ InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
+ delegate->InfoBarClosed();
+ }
+ infobar_delegates_.clear();
+
+ // Notify any observer that have a reference on this tab contents.
+ NotificationService::current()->Notify(
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(this),
+ NotificationService::NoDetails());
+
+#if defined(OS_WIN)
+ // If we still have a window handle, destroy it. GetNativeView can return
+ // NULL if this contents was part of a window that closed.
+ if (GetNativeView())
+ ::DestroyWindow(GetNativeView());
+#endif
+
+ // Notify our NavigationController. Make sure we are deleted first, so
+ // that the controller is the last to die.
+ NavigationController* controller = controller_;
+
+ delete this;
+
+ controller->TabContentsWasDestroyed();
+}
+
const string16& WebContents::GetTitle() const {
DOMUI* our_dom_ui = render_manager_.pending_dom_ui() ?
render_manager_.pending_dom_ui() : render_manager_.dom_ui();
@@ -394,15 +418,15 @@ const string16& WebContents::GetTitle() const {
// title.
// The exception is with transient pages, for which we really want to use
// their title, as they are not committed.
- NavigationEntry* entry = controller_.GetTransientEntry();
+ NavigationEntry* entry = controller_->GetTransientEntry();
if (entry)
- return entry->GetTitleForDisplay(&controller_);
+ return entry->GetTitleForDisplay(controller_);
- entry = controller_.GetLastCommittedEntry();
+ entry = controller_->GetLastCommittedEntry();
if (entry)
- return entry->GetTitleForDisplay(&controller_);
- else if (controller_.LoadingURLLazily())
- return controller_.GetLazyTitle();
+ return entry->GetTitleForDisplay(controller_);
+ else if (controller_->LoadingURLLazily())
+ return controller_->GetLazyTitle();
return EmptyString16();
}
@@ -419,7 +443,7 @@ bool WebContents::ShouldDisplayURL() {
bool WebContents::ShouldDisplayFavIcon() {
// Always display a throbber during pending loads.
- if (controller_.GetLastCommittedEntry() && controller_.pending_entry())
+ if (controller()->GetLastCommittedEntry() && controller()->pending_entry())
return true;
DOMUI* dom_ui = GetDOMUIForCurrentState();
@@ -456,7 +480,7 @@ std::wstring WebContents::GetStatusText() const {
}
bool WebContents::NavigateToPendingEntry(bool reload) {
- const NavigationEntry& entry = *controller_.pending_entry();
+ const NavigationEntry& entry = *controller()->pending_entry();
RenderViewHost* dest_render_view_host = render_manager_.Navigate(entry);
if (!dest_render_view_host)
@@ -519,19 +543,15 @@ void WebContents::DisassociateFromPopupCount() {
render_view_host()->DisassociateFromPopupCount();
}
-TabContents* WebContents::Clone() {
- // We create a new SiteInstance so that the new tab won't share processes
- // with the old one. This can be changed in the future if we need it to share
- // processes for some reason.
- TabContents* tc = new WebContents(profile(),
- SiteInstance::CreateSiteInstance(profile()),
- MSG_ROUTING_NONE, NULL);
- tc->controller().CopyStateFrom(controller_);
- return tc;
-}
-
void WebContents::DidBecomeSelected() {
- controller_.SetActive(true);
+ if (controller_)
+ controller_->SetActive(true);
+
+#if defined(OS_WIN)
+ // Invalidate all descendants. (take care to exclude invalidating ourselves!)
+ // TODO(brettw) this should be moved to the view!
+// EnumChildWindows(GetNativeView(), InvalidateWindow, 0);
+#endif
if (render_widget_host_view())
render_widget_host_view()->DidBecomeSelected();
@@ -592,7 +612,7 @@ bool WebContents::IsBookmarkBarAlwaysVisible() {
// See GetDOMUIForCurrentState() comment for more info. This case is very
// similar, but for non-first loads, we want to use the committed entry. This
// is so the bookmarks bar disappears at the same time the page does.
- if (controller_.GetLastCommittedEntry()) {
+ if (controller()->GetLastCommittedEntry()) {
// Not the first load, always use the committed DOM UI.
if (render_manager_.dom_ui())
return render_manager_.dom_ui()->force_bookmark_bar_visible();
@@ -657,7 +677,7 @@ void WebContents::GetContainerBounds(gfx::Rect *out) const {
}
void WebContents::CreateShortcut() {
- NavigationEntry* entry = controller_.GetLastCommittedEntry();
+ NavigationEntry* entry = controller()->GetLastCommittedEntry();
if (!entry)
return;
@@ -775,7 +795,7 @@ bool WebContents::PrintNow() {
}
bool WebContents::IsActiveEntry(int32 page_id) {
- NavigationEntry* active_entry = controller_.GetActiveEntry();
+ NavigationEntry* active_entry = controller()->GetActiveEntry();
return (active_entry != NULL &&
active_entry->site_instance() == GetSiteInstance() &&
active_entry->page_id() == page_id);
@@ -815,7 +835,7 @@ void WebContents::SetIsLoading(bool is_loading,
if (details)
det = Details<LoadNotificationDetails>(details);
NotificationService::current()->Notify(type,
- Source<NavigationController>(&controller_),
+ Source<NavigationController>(this->controller()),
det);
}
@@ -832,7 +852,9 @@ Profile* WebContents::GetProfile() const {
}
void WebContents::RenderViewCreated(RenderViewHost* render_view_host) {
- NavigationEntry* entry = controller_.GetActiveEntry();
+ if (!controller())
+ return;
+ NavigationEntry* entry = controller()->GetActiveEntry();
if (!entry)
return;
@@ -884,6 +906,10 @@ void WebContents::DidNavigate(RenderViewHost* rvh,
if (PageTransition::IsMainFrame(params.transition))
render_manager_.DidNavigateMainFrame(rvh);
+ // We can't do anything about navigations when we're inactive.
+ if (!controller())
+ return;
+
// Update the site of the SiteInstance if it doesn't have one yet.
if (!GetSiteInstance()->has_site())
GetSiteInstance()->SetSite(params.url);
@@ -900,7 +926,7 @@ void WebContents::DidNavigate(RenderViewHost* rvh,
contents_mime_type_ = params.contents_mime_type;
NavigationController::LoadCommittedDetails details;
- if (!controller_.RendererDidNavigate(params, &details))
+ if (!controller()->RendererDidNavigate(params, &details))
return; // No navigation happened.
// DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
@@ -918,6 +944,8 @@ void WebContents::UpdateState(RenderViewHost* rvh,
int32 page_id,
const std::string& state) {
DCHECK(rvh == render_view_host());
+ if (!controller())
+ return;
// We must be prepared to handle state updates for any page, these occur
// when the user is scrolling and entering form data, as well as when we're
@@ -925,43 +953,49 @@ void WebContents::UpdateState(RenderViewHost* rvh,
// the next page. The navigation controller will look up the appropriate
// NavigationEntry and update it when it is notified via the delegate.
- int entry_index = controller_.GetEntryIndexWithPageID(
+ int entry_index = controller()->GetEntryIndexWithPageID(
GetSiteInstance(), page_id);
if (entry_index < 0)
return;
- NavigationEntry* entry = controller_.GetEntryAtIndex(entry_index);
+ NavigationEntry* entry = controller()->GetEntryAtIndex(entry_index);
if (state == entry->content_state())
return; // Nothing to update.
entry->set_content_state(state);
- controller_.NotifyEntryChanged(entry, entry_index);
+ controller()->NotifyEntryChanged(entry, entry_index);
}
void WebContents::UpdateTitle(RenderViewHost* rvh,
int32 page_id, const std::wstring& title) {
+ if (!controller())
+ return;
+
// If we have a title, that's a pretty good indication that we've started
// getting useful data.
SetNotWaitingForResponse();
DCHECK(rvh == render_view_host());
- NavigationEntry* entry = controller_.GetEntryWithPageID(GetSiteInstance(),
+ NavigationEntry* entry = controller()->GetEntryWithPageID(GetSiteInstance(),
page_id);
if (!entry || !UpdateTitleForEntry(entry, title))
return;
// Broadcast notifications when the UI should be updated.
- if (entry == controller_.GetEntryAtOffset(0))
+ if (entry == controller()->GetEntryAtOffset(0))
NotifyNavigationStateChanged(INVALIDATE_TITLE);
}
void WebContents::UpdateFeedList(
RenderViewHost* rvh, const ViewHostMsg_UpdateFeedList_Params& params) {
+ if (!controller())
+ return;
+
// We might have an old RenderViewHost sending messages, and we should ignore
// those messages.
if (rvh != render_view_host())
return;
- NavigationEntry* entry = controller_.GetEntryWithPageID(GetSiteInstance(),
+ NavigationEntry* entry = controller()->GetEntryWithPageID(GetSiteInstance(),
params.page_id);
if (!entry)
return;
@@ -969,7 +1003,7 @@ void WebContents::UpdateFeedList(
entry->set_feedlist(params.feedlist);
// Broadcast notifications when the UI should be updated.
- if (entry == controller_.GetEntryAtOffset(0))
+ if (entry == controller()->GetEntryAtOffset(0))
NotifyNavigationStateChanged(INVALIDATE_FEEDLIST);
}
@@ -1011,23 +1045,24 @@ void WebContents::DidStartLoading(RenderViewHost* rvh, int32 page_id) {
void WebContents::DidStopLoading(RenderViewHost* rvh, int32 page_id) {
scoped_ptr<LoadNotificationDetails> details;
-
- NavigationEntry* entry = controller_.GetActiveEntry();
- // An entry may not exist for a stop when loading an initial blank page or
- // if an iframe injected by script into a blank page finishes loading.
- if (entry) {
- scoped_ptr<base::ProcessMetrics> metrics(
- base::ProcessMetrics::CreateProcessMetrics(
- process()->process().handle()));
-
- TimeDelta elapsed = TimeTicks::Now() - current_load_start_;
-
- details.reset(new LoadNotificationDetails(
- entry->display_url(),
- entry->transition_type(),
- elapsed,
- &controller_,
- controller_.GetCurrentEntryIndex()));
+ if (controller()) {
+ NavigationEntry* entry = controller()->GetActiveEntry();
+ // An entry may not exist for a stop when loading an initial blank page or
+ // if an iframe injected by script into a blank page finishes loading.
+ if (entry) {
+ scoped_ptr<base::ProcessMetrics> metrics(
+ base::ProcessMetrics::CreateProcessMetrics(
+ process()->process().handle()));
+
+ TimeDelta elapsed = TimeTicks::Now() - current_load_start_;
+
+ details.reset(new LoadNotificationDetails(
+ entry->display_url(),
+ entry->transition_type(),
+ elapsed,
+ controller(),
+ controller()->GetCurrentEntryIndex()));
+ }
}
// Tell PasswordManager we've finished a page load, which serves as a
@@ -1042,11 +1077,11 @@ void WebContents::DidStartProvisionalLoadForFrame(
bool is_main_frame,
const GURL& url) {
ProvisionalLoadDetails details(is_main_frame,
- controller_.IsURLInPageNavigation(url),
+ controller()->IsURLInPageNavigation(url),
url, std::string(), false);
NotificationService::current()->Notify(
NotificationType::FRAME_PROVISIONAL_LOAD_START,
- Source<NavigationController>(&controller_),
+ Source<NavigationController>(controller()),
Details<ProvisionalLoadDetails>(&details));
}
@@ -1055,9 +1090,9 @@ void WebContents::DidRedirectProvisionalLoad(int32 page_id,
const GURL& target_url) {
NavigationEntry* entry;
if (page_id == -1)
- entry = controller_.pending_entry();
+ entry = controller()->pending_entry();
else
- entry = controller_.GetEntryWithPageID(GetSiteInstance(), page_id);
+ entry = controller()->GetEntryWithPageID(GetSiteInstance(), page_id);
if (!entry || entry->url() != source_url)
return;
entry->set_url(target_url);
@@ -1068,6 +1103,9 @@ void WebContents::DidLoadResourceFromMemoryCache(
const std::string& frame_origin,
const std::string& main_frame_origin,
const std::string& security_info) {
+ if (!controller())
+ return;
+
// Send out a notification that we loaded a resource from our memory cache.
int cert_id = 0, cert_status = 0, security_bits = 0;
SSLManager::DeserializeSecurityInfo(security_info,
@@ -1078,7 +1116,7 @@ void WebContents::DidLoadResourceFromMemoryCache(
NotificationService::current()->Notify(
NotificationType::LOAD_FROM_MEMORY_CACHE,
- Source<NavigationController>(&controller_),
+ Source<NavigationController>(controller()),
Details<LoadFromMemoryCacheDetails>(&details));
}
@@ -1088,6 +1126,9 @@ void WebContents::DidFailProvisionalLoadWithError(
int error_code,
const GURL& url,
bool showing_repost_interstitial) {
+ if (!controller())
+ return;
+
if (net::ERR_ABORTED == error_code) {
// EVIL HACK ALERT! Ignore failed loads when we're showing interstitials.
// This means that the interstitial won't be torn down properly, which is
@@ -1116,22 +1157,22 @@ void WebContents::DidFailProvisionalLoadWithError(
// decided to download the file instead of load it). Only discard the
// pending entry if the URLs match, otherwise the user initiated a navigate
// before the page loaded so that the discard would discard the wrong entry.
- NavigationEntry* pending_entry = controller_.pending_entry();
+ NavigationEntry* pending_entry = controller()->pending_entry();
if (pending_entry && pending_entry->url() == url)
- controller_.DiscardNonCommittedEntries();
+ controller()->DiscardNonCommittedEntries();
render_manager_.RendererAbortedProvisionalLoad(render_view_host);
}
// Send out a notification that we failed a provisional load with an error.
ProvisionalLoadDetails details(is_main_frame,
- controller_.IsURLInPageNavigation(url),
+ controller()->IsURLInPageNavigation(url),
url, std::string(), false);
details.set_error_code(error_code);
NotificationService::current()->Notify(
NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
- Source<NavigationController>(&controller_),
+ Source<NavigationController>(controller()),
Details<ProvisionalLoadDetails>(&details));
}
@@ -1203,14 +1244,21 @@ void WebContents::ProcessExternalHostMessage(const std::string& message,
}
void WebContents::GoToEntryAtOffset(int offset) {
- controller_.GoToOffset(offset);
+ if (!controller())
+ return;
+ controller()->GoToOffset(offset);
}
void WebContents::GetHistoryListCount(int* back_list_count,
int* forward_list_count) {
- int current_index = controller_.last_committed_entry_index();
- *back_list_count = current_index;
- *forward_list_count = controller_.entry_count() - current_index - 1;
+ *back_list_count = 0;
+ *forward_list_count = 0;
+
+ if (controller()) {
+ int current_index = controller()->last_committed_entry_index();
+ *back_list_count = current_index;
+ *forward_list_count = controller()->entry_count() - current_index - 1;
+ }
}
void WebContents::RunFileChooser(bool multiple_files,
@@ -1306,7 +1354,7 @@ void WebContents::PageHasOSDD(RenderViewHost* render_view_host,
bool autodetected) {
// Make sure page_id is the current page, and the TemplateURLModel is loaded.
DCHECK(url.is_valid());
- if (!IsActiveEntry(page_id))
+ if (!controller() || !IsActiveEntry(page_id))
return;
TemplateURLModel* url_model = profile()->GetTemplateURLModel();
if (!url_model)
@@ -1321,18 +1369,18 @@ void WebContents::PageHasOSDD(RenderViewHost* render_view_host,
if (profile()->IsOffTheRecord())
return;
- const NavigationEntry* entry = controller_.GetLastCommittedEntry();
+ const NavigationEntry* entry = controller()->GetLastCommittedEntry();
DCHECK(entry);
const NavigationEntry* base_entry = entry;
if (IsFormSubmit(base_entry)) {
// If the current page is a form submit, find the last page that was not
// a form submit and use its url to generate the keyword from.
- int index = controller_.last_committed_entry_index() - 1;
- while (index >= 0 && IsFormSubmit(controller_.GetEntryAtIndex(index)))
+ int index = controller()->last_committed_entry_index() - 1;
+ while (index >= 0 && IsFormSubmit(controller()->GetEntryAtIndex(index)))
index--;
if (index >= 0)
- base_entry = controller_.GetEntryAtIndex(index);
+ base_entry = controller()->GetEntryAtIndex(index);
else
base_entry = NULL;
}
@@ -1585,7 +1633,9 @@ DOMUI* WebContents::CreateDOMUIForRenderManager(const GURL& url) {
NavigationEntry*
WebContents::GetLastCommittedNavigationEntryForRenderManager() {
- return controller_.GetLastCommittedEntry();
+ if (!controller())
+ return NULL;
+ return controller()->GetLastCommittedEntry();
}
bool WebContents::CreateRenderViewForRenderManager(
@@ -1644,7 +1694,7 @@ void WebContents::Observe(NotificationType type,
break;
case NotificationType::NAV_ENTRY_COMMITTED: {
- DCHECK(&controller_ == Source<NavigationController>(source).ptr());
+ DCHECK(controller() == Source<NavigationController>(source).ptr());
NavigationController::LoadCommittedDetails& committed_details =
*(Details<NavigationController::LoadCommittedDetails>(details).ptr());
@@ -1778,7 +1828,7 @@ void WebContents::UpdateWebPreferences() {
void WebContents::OnGearsCreateShortcutDone(
const GearsShortcutData2& shortcut_data, bool success) {
- NavigationEntry* current_entry = controller_.GetLastCommittedEntry();
+ NavigationEntry* current_entry = controller()->GetLastCommittedEntry();
bool same_page =
current_entry && pending_install_.page_id == current_entry->page_id();
@@ -1802,7 +1852,7 @@ void WebContents::UpdateMaxPageIDIfNecessary(SiteInstance* site_instance,
// Note that it is ok for conflicting page IDs to exist in another tab
// (i.e., NavigationController), but if any page ID is larger than the max,
// the back/forward list will get confused.
- int max_restored_page_id = controller_.max_restored_page_id();
+ int max_restored_page_id = controller()->max_restored_page_id();
if (max_restored_page_id > 0) {
int curr_max_page_id = site_instance->max_page_id();
if (max_restored_page_id > curr_max_page_id) {
@@ -1917,13 +1967,14 @@ void WebContents::NotifyDisconnected() {
void WebContents::GenerateKeywordIfNecessary(
const ViewHostMsg_FrameNavigate_Params& params) {
+ DCHECK(controller());
if (!params.searchable_form_url.is_valid())
return;
if (profile()->IsOffTheRecord())
return;
- int last_index = controller_.last_committed_entry_index();
+ int last_index = controller()->last_committed_entry_index();
// When there was no previous page, the last index will be 0. This is
// normally due to a form submit that opened in a new tab.
// TODO(brettw) bug 916126: we should support keywords when form submits
@@ -1931,7 +1982,7 @@ void WebContents::GenerateKeywordIfNecessary(
if (last_index <= 0)
return;
const NavigationEntry* previous_entry =
- controller_.GetEntryAtIndex(last_index - 1);
+ controller()->GetEntryAtIndex(last_index - 1);
if (IsFormSubmit(previous_entry)) {
// Only generate a keyword if the previous page wasn't itself a form
// submit.
@@ -1972,9 +2023,9 @@ void WebContents::GenerateKeywordIfNecessary(
new_url->set_short_name(keyword);
new_url->SetURL(url, 0, 0);
new_url->add_input_encoding(params.searchable_form_encoding);
- DCHECK(controller_.GetLastCommittedEntry());
+ DCHECK(controller()->GetLastCommittedEntry());
const GURL& favicon_url =
- controller_.GetLastCommittedEntry()->favicon().url();
+ controller()->GetLastCommittedEntry()->favicon().url();
if (favicon_url.is_valid()) {
new_url->SetFavIconURL(favicon_url);
} else {
@@ -2022,8 +2073,8 @@ DOMUI* WebContents::GetDOMUIForCurrentState() {
//
// - Normal state with no load: committed nav entry + no pending nav entry:
// -> Use committed DOM UI.
- if (controller_.pending_entry() &&
- (controller_.GetLastCommittedEntry() ||
+ if (controller()->pending_entry() &&
+ (controller()->GetLastCommittedEntry() ||
render_manager_.pending_dom_ui()))
return render_manager_.pending_dom_ui();
return render_manager_.dom_ui();
diff --git a/chrome/browser/tab_contents/web_contents.h b/chrome/browser/tab_contents/web_contents.h
index 9128868..b89efd3 100644
--- a/chrome/browser/tab_contents/web_contents.h
+++ b/chrome/browser/tab_contents/web_contents.h
@@ -73,8 +73,6 @@ class WebContents : public TabContents,
int routing_id,
base::WaitableEvent* modal_dialog_event);
- virtual ~WebContents();
-
static void RegisterUserPrefs(PrefService* prefs);
// Getters -------------------------------------------------------------------
@@ -128,6 +126,7 @@ class WebContents : public TabContents,
// TabContents (public overrides) --------------------------------------------
+ virtual void Destroy();
virtual WebContents* AsWebContents() { return this; }
const string16& GetTitle() const;
virtual SiteInstance* GetSiteInstance() const;
@@ -140,7 +139,6 @@ class WebContents : public TabContents,
virtual void Copy();
virtual void Paste();
virtual void DisassociateFromPopupCount();
- virtual TabContents* Clone();
virtual void DidBecomeSelected();
virtual void WasHidden();
virtual void ShowContents();
@@ -294,6 +292,9 @@ class WebContents : public TabContents,
}
protected:
+ // Should be deleted via CloseContents.
+ virtual ~WebContents();
+
RenderWidgetHostView* render_widget_host_view() const {
return render_manager_.current_view();
}
@@ -452,7 +453,7 @@ class WebContents : public TabContents,
virtual void NotifySwappedFromRenderManager() {
NotifySwapped();
}
- virtual NavigationController& GetControllerForRenderManager() {
+ virtual NavigationController* GetControllerForRenderManager() {
return controller();
}
virtual DOMUI* CreateDOMUIForRenderManager(const GURL& url);
diff --git a/chrome/browser/tab_contents/web_contents_unittest.cc b/chrome/browser/tab_contents/web_contents_unittest.cc
index 207a724..c5e58e1 100644
--- a/chrome/browser/tab_contents/web_contents_unittest.cc
+++ b/chrome/browser/tab_contents/web_contents_unittest.cc
@@ -206,7 +206,7 @@ TEST_F(WebContentsTest, UpdateTitle) {
InitNavigateParams(&params, 0, GURL("about:blank"));
NavigationController::LoadCommittedDetails details;
- controller().RendererDidNavigate(params, &details);
+ controller()->RendererDidNavigate(params, &details);
contents()->UpdateTitle(rvh(), 0, L" Lots O' Whitespace\n");
EXPECT_EQ(std::wstring(L"Lots O' Whitespace"),
@@ -221,12 +221,12 @@ TEST_F(WebContentsTest, SimpleNavigation) {
// Navigate to URL
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
EXPECT_EQ(instance1, orig_rvh->site_instance());
// Controller's pending entry will have a NULL site instance until we assign
// it in DidNavigate.
- EXPECT_TRUE(controller().GetActiveEntry()->site_instance() == NULL);
+ EXPECT_TRUE(controller()->GetActiveEntry()->site_instance() == NULL);
// DidNavigate from the page
ViewHostMsg_FrameNavigate_Params params;
@@ -237,7 +237,7 @@ TEST_F(WebContentsTest, SimpleNavigation) {
EXPECT_EQ(instance1, orig_rvh->site_instance());
// Controller's entry should now have the SiteInstance, or else we won't be
// able to find it later.
- EXPECT_EQ(instance1, controller().GetActiveEntry()->site_instance());
+ EXPECT_EQ(instance1, controller()->GetActiveEntry()->site_instance());
}
// Test that navigating across a site boundary creates a new RenderViewHost
@@ -251,7 +251,7 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) {
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents()->TestDidNavigate(orig_rvh, params1);
@@ -261,7 +261,7 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) {
// Navigate to new site
const GURL url2("http://www.yahoo.com");
- controller().LoadURL(url2, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
EXPECT_TRUE(contents()->cross_navigation_pending());
TestRenderViewHost* pending_rvh = contents()->pending_rvh();
int pending_rvh_delete_count = 0;
@@ -281,7 +281,7 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) {
// Going back should switch SiteInstances again. The first SiteInstance is
// stored in the NavigationEntry, so it should be the same as at the start.
- controller().GoBack();
+ controller()->GoBack();
TestRenderViewHost* goback_rvh = contents()->pending_rvh();
EXPECT_TRUE(contents()->cross_navigation_pending());
@@ -304,7 +304,7 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) {
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents()->TestDidNavigate(orig_rvh, params1);
@@ -317,7 +317,7 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) {
// Navigate to new site. We should not go into PENDING.
const GURL url2("http://www.yahoo.com");
- controller().LoadURL(url2, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
TestRenderViewHost* new_rvh = rvh();
EXPECT_FALSE(contents()->cross_navigation_pending());
EXPECT_TRUE(contents()->pending_rvh() == NULL);
@@ -345,23 +345,24 @@ TEST_F(WebContentsTest, NavigateTwoTabsCrossSite) {
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents()->TestDidNavigate(orig_rvh, params1);
// Open a new tab with the same SiteInstance, navigated to the same site.
- TestWebContents contents2(profile(), instance1);
+ TestWebContents* contents2 = new TestWebContents(profile(), instance1);
params1.page_id = 2; // Need this since the site instance is the same (which
// is the scope of page IDs) and we want to consider
// this a new page.
- contents2.transition_cross_site = true;
- contents2.controller().LoadURL(url, GURL(), PageTransition::TYPED);
- contents2.TestDidNavigate(contents2.render_view_host(), params1);
+ contents2->transition_cross_site = true;
+ contents2->SetupController(profile());
+ contents2->controller()->LoadURL(url, GURL(), PageTransition::TYPED);
+ contents2->TestDidNavigate(contents2->render_view_host(), params1);
// Navigate first tab to a new site
const GURL url2a("http://www.yahoo.com");
- controller().LoadURL(url2a, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url2a, GURL(), PageTransition::TYPED);
TestRenderViewHost* pending_rvh_a = contents()->pending_rvh();
ViewHostMsg_FrameNavigate_Params params2a;
InitNavigateParams(&params2a, 1, url2a);
@@ -371,10 +372,10 @@ TEST_F(WebContentsTest, NavigateTwoTabsCrossSite) {
// Navigate second tab to the same site as the first tab
const GURL url2b("http://mail.yahoo.com");
- contents2.controller().LoadURL(url2b, GURL(), PageTransition::TYPED);
- TestRenderViewHost* pending_rvh_b = contents2.pending_rvh();
+ contents2->controller()->LoadURL(url2b, GURL(), PageTransition::TYPED);
+ TestRenderViewHost* pending_rvh_b = contents2->pending_rvh();
EXPECT_TRUE(pending_rvh_b != NULL);
- EXPECT_TRUE(contents2.cross_navigation_pending());
+ EXPECT_TRUE(contents2->cross_navigation_pending());
// NOTE(creis): We used to be in danger of showing a sad tab page here if the
// second tab hadn't navigated somewhere first (bug 1145430). That case is
@@ -382,12 +383,14 @@ TEST_F(WebContentsTest, NavigateTwoTabsCrossSite) {
ViewHostMsg_FrameNavigate_Params params2b;
InitNavigateParams(&params2b, 2, url2b);
- contents2.TestDidNavigate(pending_rvh_b, params2b);
- SiteInstance* instance2b = contents2.GetSiteInstance();
+ contents2->TestDidNavigate(pending_rvh_b, params2b);
+ SiteInstance* instance2b = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2b);
// Both tabs should now be in the same SiteInstance.
EXPECT_EQ(instance2a, instance2b);
+
+ contents2->CloseContents();
}
// Tests that WebContents uses the current URL, not the SiteInstance's site, to
@@ -399,27 +402,28 @@ TEST_F(WebContentsTest, CrossSiteComparesAgainstCurrentPage) {
// Navigate to URL.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents()->TestDidNavigate(orig_rvh, params1);
// Open a related tab to a second site.
- TestWebContents contents2(profile(), instance1);
- contents2.transition_cross_site = true;
+ TestWebContents* contents2 = new TestWebContents(profile(), instance1);
+ contents2->transition_cross_site = true;
+ contents2->SetupController(profile());
const GURL url2("http://www.yahoo.com");
- contents2.controller().LoadURL(url2, GURL(), PageTransition::TYPED);
+ contents2->controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
// The first RVH in contents2 isn't live yet, so we shortcut the cross site
// pending.
TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
- contents2.render_view_host());
- EXPECT_FALSE(contents2.cross_navigation_pending());
+ contents2->render_view_host());
+ EXPECT_FALSE(contents2->cross_navigation_pending());
ViewHostMsg_FrameNavigate_Params params2;
InitNavigateParams(&params2, 2, url2);
- contents2.TestDidNavigate(rvh2, params2);
- SiteInstance* instance2 = contents2.GetSiteInstance();
+ contents2->TestDidNavigate(rvh2, params2);
+ SiteInstance* instance2 = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2);
- EXPECT_FALSE(contents2.cross_navigation_pending());
+ EXPECT_FALSE(contents2->cross_navigation_pending());
// Simulate a link click in first tab to second site. Doesn't switch
// SiteInstances, because we don't intercept WebKit navigations.
@@ -433,13 +437,15 @@ TEST_F(WebContentsTest, CrossSiteComparesAgainstCurrentPage) {
// Navigate to the new site. Doesn't switch SiteInstancees, because we
// compare against the current URL, not the SiteInstance's site.
const GURL url3("http://mail.yahoo.com");
- controller().LoadURL(url3, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url3, GURL(), PageTransition::TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
ViewHostMsg_FrameNavigate_Params params4;
InitNavigateParams(&params4, 3, url3);
contents()->TestDidNavigate(orig_rvh, params4);
SiteInstance* instance4 = contents()->GetSiteInstance();
EXPECT_EQ(instance1, instance4);
+
+ contents2->CloseContents();
}
// Test that the onbeforeunload and onunload handlers run when navigating
@@ -451,7 +457,7 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) {
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents()->TestDidNavigate(orig_rvh, params1);
@@ -460,13 +466,13 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) {
// Navigate to new site, but simulate an onbeforeunload denial.
const GURL url2("http://www.yahoo.com");
- controller().LoadURL(url2, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false));
EXPECT_FALSE(contents()->cross_navigation_pending());
EXPECT_EQ(orig_rvh, contents()->render_view_host());
// Navigate again, but simulate an onbeforeunload approval.
- controller().LoadURL(url2, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
EXPECT_TRUE(contents()->cross_navigation_pending());
TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
@@ -494,34 +500,34 @@ TEST_F(WebContentsTest, NavigationEntryContentState) {
// Navigate to URL. There should be no committed entry yet.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
- NavigationEntry* entry = controller().GetLastCommittedEntry();
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
+ NavigationEntry* entry = controller()->GetLastCommittedEntry();
EXPECT_TRUE(entry == NULL);
// Committed entry should have content state after DidNavigate.
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents()->TestDidNavigate(orig_rvh, params1);
- entry = controller().GetLastCommittedEntry();
+ entry = controller()->GetLastCommittedEntry();
EXPECT_FALSE(entry->content_state().empty());
// Navigate to same site.
const GURL url2("http://images.google.com");
- controller().LoadURL(url2, GURL(), PageTransition::TYPED);
- entry = controller().GetLastCommittedEntry();
+ controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
+ entry = controller()->GetLastCommittedEntry();
EXPECT_FALSE(entry->content_state().empty());
// Committed entry should have content state after DidNavigate.
ViewHostMsg_FrameNavigate_Params params2;
InitNavigateParams(&params2, 2, url2);
contents()->TestDidNavigate(orig_rvh, params2);
- entry = controller().GetLastCommittedEntry();
+ entry = controller()->GetLastCommittedEntry();
EXPECT_FALSE(entry->content_state().empty());
// Now go back. Committed entry should still have content state.
- controller().GoBack();
+ controller()->GoBack();
contents()->TestDidNavigate(orig_rvh, params1);
- entry = controller().GetLastCommittedEntry();
+ entry = controller()->GetLastCommittedEntry();
EXPECT_FALSE(entry->content_state().empty());
}
@@ -539,7 +545,7 @@ TEST_F(WebContentsTest, NavigationEntryContentStateNewWindow) {
contents()->TestDidNavigate(orig_rvh, params1);
// Should have a content state here.
- NavigationEntry* entry = controller().GetLastCommittedEntry();
+ NavigationEntry* entry = controller()->GetLastCommittedEntry();
EXPECT_FALSE(entry->content_state().empty());
}
@@ -571,10 +577,10 @@ TEST_F(WebContentsTest,
// Navigate to a page.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Initiate a browser navigation that will trigger the interstitial
- controller().LoadURL(GURL("http://www.evil.com"), GURL(),
+ controller()->LoadURL(GURL("http://www.evil.com"), GURL(),
PageTransition::TYPED);
// Show an interstitial.
@@ -595,7 +601,7 @@ TEST_F(WebContentsTest,
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == interstitial);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url2);
@@ -605,10 +611,10 @@ TEST_F(WebContentsTest,
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- entry = controller().GetActiveEntry();
+ entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
}
// Test navigating to a page (with the navigation initiated from the renderer,
@@ -619,7 +625,7 @@ TEST_F(WebContentsTest,
// Navigate to a page.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial (no pending entry, the interstitial would have been
// triggered by clicking on a link).
@@ -640,7 +646,7 @@ TEST_F(WebContentsTest,
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == interstitial);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url2);
@@ -650,10 +656,10 @@ TEST_F(WebContentsTest,
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- entry = controller().GetActiveEntry();
+ entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
}
// Test navigating to a page that shows an interstitial without creating a new
@@ -663,7 +669,7 @@ TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -683,7 +689,7 @@ TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationDontProceed) {
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == interstitial);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
// The URL specified to the interstitial should have been ignored.
EXPECT_TRUE(entry->url() == url1);
@@ -694,10 +700,10 @@ TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationDontProceed) {
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- entry = controller().GetActiveEntry();
+ entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
}
// Test navigating to a page (with the navigation initiated from the browser,
@@ -708,10 +714,10 @@ TEST_F(WebContentsTest,
// Navigate to a page.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Initiate a browser navigation that will trigger the interstitial
- controller().LoadURL(GURL("http://www.evil.com"), GURL(),
+ controller()->LoadURL(GURL("http://www.evil.com"), GURL(),
PageTransition::TYPED);
// Show an interstitial.
@@ -732,7 +738,7 @@ TEST_F(WebContentsTest,
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == interstitial);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url2);
@@ -752,11 +758,11 @@ TEST_F(WebContentsTest,
EXPECT_TRUE(deleted);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- entry = controller().GetActiveEntry();
+ entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url3);
- EXPECT_EQ(2, controller().entry_count());
+ EXPECT_EQ(2, controller()->entry_count());
}
// Test navigating to a page (with the navigation initiated from the renderer,
@@ -767,7 +773,7 @@ TEST_F(WebContentsTest,
// Navigate to a page.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -787,7 +793,7 @@ TEST_F(WebContentsTest,
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == interstitial);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url2);
@@ -807,11 +813,11 @@ TEST_F(WebContentsTest,
EXPECT_TRUE(deleted);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- entry = controller().GetActiveEntry();
+ entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url3);
- EXPECT_EQ(2, controller().entry_count());
+ EXPECT_EQ(2, controller()->entry_count());
}
// Test navigating to a page that shows an interstitial without creating a new
@@ -821,7 +827,7 @@ TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationProceed) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -841,7 +847,7 @@ TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationProceed) {
EXPECT_TRUE(interstitial->is_showing());
EXPECT_TRUE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == interstitial);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
// The URL specified to the interstitial should have been ignored.
EXPECT_TRUE(entry->url() == url1);
@@ -854,11 +860,11 @@ TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationProceed) {
EXPECT_EQ(TestInterstitialPage::OKED, state);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- entry = controller().GetActiveEntry();
+ entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
}
// Test navigating to a page that shows an interstitial, then navigating away.
@@ -896,7 +902,7 @@ TEST_F(WebContentsTest, ShowInterstitialThenCloseTab) {
interstitial->TestDidNavigate(1, url);
// Now close the tab.
- delete contents();
+ contents()->CloseContents();
ContentsCleanedUp();
EXPECT_TRUE(deleted);
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
@@ -908,7 +914,7 @@ TEST_F(WebContentsTest, ShowInterstitialProceedMultipleCommands) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
rvh()->SendNavigate(1, url1);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -942,7 +948,7 @@ TEST_F(WebContentsTest, ShowInterstitialOnInterstitial) {
// Navigate to a page so we have a navigation entry in the controller.
GURL start_url("http://www.google.com");
rvh()->SendNavigate(1, start_url);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial.
TestInterstitialPage::InterstitialState state1 =
@@ -980,10 +986,10 @@ TEST_F(WebContentsTest, ShowInterstitialOnInterstitial) {
EXPECT_TRUE(deleted2);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == landing_url);
- EXPECT_EQ(2, controller().entry_count());
+ EXPECT_EQ(2, controller()->entry_count());
}
// Test showing an interstitial, proceeding and then navigating to another
@@ -992,7 +998,7 @@ TEST_F(WebContentsTest, ShowInterstitialProceedShowInterstitial) {
// Navigate to a page so we have a navigation entry in the controller.
GURL start_url("http://www.google.com");
rvh()->SendNavigate(1, start_url);
- EXPECT_EQ(1, controller().entry_count());
+ EXPECT_EQ(1, controller()->entry_count());
// Show an interstitial.
TestInterstitialPage::InterstitialState state1 =
@@ -1035,10 +1041,10 @@ TEST_F(WebContentsTest, ShowInterstitialProceedShowInterstitial) {
EXPECT_TRUE(deleted2);
EXPECT_FALSE(contents()->showing_interstitial_page());
EXPECT_TRUE(contents()->interstitial_page() == NULL);
- NavigationEntry* entry = controller().GetActiveEntry();
+ NavigationEntry* entry = controller()->GetActiveEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_TRUE(entry->url() == landing_url);
- EXPECT_EQ(2, controller().entry_count());
+ EXPECT_EQ(2, controller()->entry_count());
}
// Test that navigating away from an interstitial while it's loading cause it
@@ -1058,7 +1064,7 @@ TEST_F(WebContentsTest, NavigateBeforeInterstitialShows) {
// Let's simulate a navigation initiated from the browser before the
// interstitial finishes loading.
const GURL url("http://www.google.com");
- controller().LoadURL(url, GURL(), PageTransition::TYPED);
+ controller()->LoadURL(url, GURL(), PageTransition::TYPED);
ASSERT_FALSE(deleted);
EXPECT_FALSE(interstitial->is_showing());