diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-18 19:52:40 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-18 19:52:40 +0000 |
commit | 1ef5ad42064c8ef0d1503b68a7fbac01887ca093 (patch) | |
tree | 34a32b11a9db6f69fef27e7e81863d82a29bcd2d /chrome/browser/tab_contents | |
parent | 59b49a66c3cd959fcf9d7b4bd9c6d88c70b39919 (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | chrome/browser/tab_contents/interstitial_page.cc | 14 | ||||
-rw-r--r-- | chrome/browser/tab_contents/navigation_controller.cc | 108 | ||||
-rw-r--r-- | chrome/browser/tab_contents/navigation_controller.h | 44 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_context_menu.cc | 16 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_host_delegate_helper.cc | 1 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_host_manager.cc | 34 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_host_manager.h | 8 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_host_manager_unittest.cc | 21 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 85 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 76 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_contents.cc | 327 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_contents.h | 9 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_contents_unittest.cc | 160 |
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(¶ms, 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(¶ms1, 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(¶ms1, 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(¶ms1, 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(¶ms2a, 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(¶ms2b, 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(¶ms1, 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(¶ms2, 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(¶ms4, 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(¶ms1, 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(¶ms1, 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(¶ms2, 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()); |