diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-17 19:36:52 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-17 19:36:52 +0000 |
commit | a0729671be0628b5d2c45ef9c19a51c53bfa65b5 (patch) | |
tree | 5e4fadde19f6c5702a799cc3b786fee48fc4c9c0 /chrome/browser | |
parent | 39ae0a282dc3c1b9e1aea492e11c4d1439ac6921 (diff) | |
download | chromium_src-a0729671be0628b5d2c45ef9c19a51c53bfa65b5.zip chromium_src-a0729671be0628b5d2c45ef9c19a51c53bfa65b5.tar.gz chromium_src-a0729671be0628b5d2c45ef9c19a51c53bfa65b5.tar.bz2 |
Revamp of the interstitial pages.
The interstitial is now a RVH that is displayed on top of the WebContents with no interaction with the WebContents' RenderViewHostManager.
This simplifies the states that the RenderViewHostManager has. The interstitial is responsible for hiding and deleting itself when told to proceed/not proceed or when a navigation occurs or the tab is closed.
The interstitial now uses a data URL (instead of loading some alternate HTML), which allowed me to remove some interstitial flags from NavigationController::LoadCommittedDetails and ProvisionalLoadDetails.
Also changed tab_utils::GetTabContentsByID to return a WebContents since only WebContents have a RVH associated with them.
TEST=Run all ui tests and unit tests.
Review URL: http://codereview.chromium.org/13764
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7149 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
35 files changed, 1107 insertions, 1606 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 2f2b6b5..3a36b52 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -588,7 +588,7 @@ class DocumentPrintedNotificationObserver : public NotificationObserver { class AutomationInterstitialPage : public InterstitialPage { public: - AutomationInterstitialPage(TabContents* tab, + AutomationInterstitialPage(WebContents* tab, const GURL& url, const std::string& contents) : InterstitialPage(tab, true, url), @@ -1990,7 +1990,7 @@ void AutomationProvider::ShowInterstitialPage(const IPC::Message& message, new AutomationInterstitialPage(web_contents, GURL("about:interstitial"), html_text); - web_contents->ShowInterstitialPage(interstitial); + interstitial->Show(); return; } } @@ -2001,8 +2001,8 @@ void AutomationProvider::ShowInterstitialPage(const IPC::Message& message, void AutomationProvider::HideInterstitialPage(const IPC::Message& message, int tab_handle) { WebContents* web_contents = GetWebContentsForHandle(tab_handle, NULL); - if (web_contents) { - web_contents->HideInterstitialPage(false, false); + if (web_contents && web_contents->interstitial_page()) { + web_contents->interstitial_page()->DontProceed(); Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(), true)); return; @@ -2161,7 +2161,7 @@ void AutomationProvider::ActionOnSSLBlockingPage(const IPC::Message& message, if (entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE) { TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB); InterstitialPage* ssl_blocking_page = - InterstitialPage::GetInterstitialPage(tab_contents); + InterstitialPage::GetInterstitialPage(tab_contents->AsWebContents()); if (ssl_blocking_page) { if (proceed) { AddNavigationStatusListener(tab, diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 87b3e9e..862398d 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -558,8 +558,11 @@ void Browser::GoBack() { // If we are showing an interstitial, just hide it. TabContents* current_tab = GetSelectedTabContents(); WebContents* web_contents = current_tab->AsWebContents(); - if (web_contents && web_contents->showing_interstitial_page()) { - // Pressing back on an interstitial page means "don't proceed". + if (web_contents && web_contents->interstitial_page()) { + // The GoBack() case is a special case when an interstitial is shown because + // the "previous" page is still available, just hidden by the interstitial. + // We treat the back as a "Don't proceed", this hides the interstitial and + // reveals the previous page. web_contents->interstitial_page()->DontProceed(); return; } diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc index f921661..2a5e612 100644 --- a/chrome/browser/download/download_file.cc +++ b/chrome/browser/download/download_file.cc @@ -16,8 +16,8 @@ #include "chrome/browser/download/download_manager.h" #include "chrome/browser/profile.h" #include "chrome/browser/resource_dispatcher_host.h" -#include "chrome/browser/tab_contents.h" #include "chrome/browser/tab_util.h" +#include "chrome/browser/web_contents.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/stl_util-inl.h" #include "chrome/common/win_util.h" @@ -458,9 +458,9 @@ void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { // static DownloadManager* DownloadFileManager::DownloadManagerFromRenderIds( int render_process_id, int render_view_id) { - TabContents* contents = tab_util::GetTabContentsByID(render_process_id, + WebContents* contents = tab_util::GetWebContentsByID(render_process_id, render_view_id); - if (contents && contents->type() == TAB_CONTENTS_WEB) { + if (contents) { Profile* profile = contents->profile(); if (profile) return profile->GetDownloadManager(); diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc index 5328807..adf62d3 100644 --- a/chrome/browser/download/download_manager.cc +++ b/chrome/browser/download/download_manager.cc @@ -618,7 +618,7 @@ void DownloadManager::OnPathExistenceAvailable(DownloadCreateInfo* info) { if (!select_file_dialog_.get()) select_file_dialog_ = SelectFileDialog::Create(this); - TabContents* contents = tab_util::GetTabContentsByID( + WebContents* contents = tab_util::GetWebContentsByID( info->render_process_id, info->render_view_id); std::wstring filter = win_util::GetFileFilterFromPath(info->suggested_path); HWND owning_hwnd = @@ -1308,7 +1308,7 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info, // this start completion event. If it does, tell the origin WebContents to // display its download shelf. TabContents* contents = - tab_util::GetTabContentsByID(info.render_process_id, info.render_view_id); + tab_util::GetWebContentsByID(info.render_process_id, info.render_view_id); // If the contents no longer exists or is no longer active, we start the // download in the last active browser. This is not ideal but better than diff --git a/chrome/browser/download/download_request_manager.cc b/chrome/browser/download/download_request_manager.cc index 6869d6e..ac4cdb5 100644 --- a/chrome/browser/download/download_request_manager.cc +++ b/chrome/browser/download/download_request_manager.cc @@ -9,9 +9,9 @@ #include "chrome/browser/navigation_controller.h" #include "chrome/browser/navigation_entry.h" #include "chrome/browser/constrained_window.h" -#include "chrome/browser/tab_contents.h" #include "chrome/browser/tab_contents_delegate.h" #include "chrome/browser/tab_util.h" +#include "chrome/browser/web_contents.h" #include "chrome/common/l10n_util.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" @@ -409,8 +409,8 @@ void DownloadRequestManager::CanDownload(int render_process_host_id, Callback* callback) { DCHECK(!ui_loop_ || MessageLoop::current() == ui_loop_); - TabContents* originating_tab = - tab_util::GetTabContentsByID(render_process_host_id, render_view_id); + WebContents* originating_tab = + tab_util::GetWebContentsByID(render_process_host_id, render_view_id); if (!originating_tab) { // The tab was closed, don't allow the download. ScheduleNotification(callback, false); diff --git a/chrome/browser/download/save_file_manager.cc b/chrome/browser/download/save_file_manager.cc index 940e878..631b55d 100644 --- a/chrome/browser/download/save_file_manager.cc +++ b/chrome/browser/download/save_file_manager.cc @@ -215,14 +215,10 @@ void SaveFileManager::RemoveSaveFile(int save_id, const std::wstring& save_url, // only on the UI thread. SavePackage* SaveFileManager::GetSavePackageFromRenderIds( int render_process_id, int render_view_id) { - TabContents* contents = tab_util::GetTabContentsByID(render_process_id, + WebContents* contents = tab_util::GetWebContentsByID(render_process_id, render_view_id); - if (contents && contents->type() == TAB_CONTENTS_WEB) { - // Convert const pointer of WebContents to pointer of WebContents. - const WebContents* web_contents = contents->AsWebContents(); - if (web_contents) - return web_contents->save_package(); - } + if (contents) + return contents->save_package(); return NULL; } diff --git a/chrome/browser/interstitial_page.cc b/chrome/browser/interstitial_page.cc index 5cbc37e..6fee67f 100644 --- a/chrome/browser/interstitial_page.cc +++ b/chrome/browser/interstitial_page.cc @@ -5,98 +5,237 @@ #include "chrome/browser/interstitial_page.h" #include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" #include "chrome/browser/browser_resources.h" #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/navigation_controller.h" #include "chrome/browser/navigation_entry.h" -#include "chrome/browser/tab_contents.h" +#include "chrome/browser/render_widget_host_view_win.h" #include "chrome/browser/web_contents.h" +#include "chrome/browser/web_contents_view_win.h" +#include "chrome/views/window.h" +#include "chrome/views/window_delegate.h" +#include "net/base/escape.h" // static InterstitialPage::InterstitialPageMap* InterstitialPage::tab_to_interstitial_page_ = NULL; -InterstitialPage::InterstitialPage(TabContents* tab, - bool create_navigation_entry, +InterstitialPage::InterstitialPage(WebContents* tab, + bool new_navigation, const GURL& url) : tab_(tab), url_(url), - delegate_has_been_notified_(false), - create_navigation_entry_(create_navigation_entry) { + action_taken_(false), + enabled_(true), + new_navigation_(new_navigation), + render_view_host_(NULL), + should_revert_tab_title_(false) { InitInterstitialPageMap(); - - // If there's already an interstitial in this tab, then we're about to - // replace it. We should be ok with just deleting the previous - // InterstitialPage (not hiding it first), since we're about to be shown. - InterstitialPageMap::const_iterator iter = - tab_to_interstitial_page_->find(tab_); - if (iter != tab_to_interstitial_page_->end()) { - // Deleting the InterstitialPage will also remove it from the map. - delete iter->second; - } - (*tab_to_interstitial_page_)[tab_] = this; - - // Register for DOM operations, this is how the page notifies us of the user - // selection. - notification_registrar_.Add(this, NOTIFY_DOM_OPERATION_RESPONSE, - Source<TabContents>(tab_)); + // It would be inconsistent to create an interstitial with no new navigation + // (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()->GetPendingEntry()); } InterstitialPage::~InterstitialPage() { InterstitialPageMap::iterator iter = tab_to_interstitial_page_->find(tab_); DCHECK(iter != tab_to_interstitial_page_->end()); tab_to_interstitial_page_->erase(iter); + DCHECK(!render_view_host_); } void InterstitialPage::Show() { - DCHECK(tab_->type() == TAB_CONTENTS_WEB); - WebContents* tab = tab_->AsWebContents(); + // If an interstitial is already showing, close it before showing the new one. + if (tab_->interstitial_page()) + tab_->interstitial_page()->DontProceed(); - if (create_navigation_entry_) { - NavigationEntry* entry = new NavigationEntry(TAB_CONTENTS_WEB); - entry->set_url(url_); - entry->set_display_url(url_); - entry->set_page_type(NavigationEntry::INTERSTITIAL_PAGE); + // Update the tab_to_interstitial_page_ map. + InterstitialPageMap::const_iterator iter = + tab_to_interstitial_page_->find(tab_); + DCHECK(iter == tab_to_interstitial_page_->end()); + (*tab_to_interstitial_page_)[tab_] = this; - // Give sub-classes a chance to set some states on the navigation entry. - UpdateEntry(entry); + if (new_navigation_) {
+ NavigationEntry* entry = new NavigationEntry(TAB_CONTENTS_WEB);
+ entry->set_url(url_);
+ entry->set_display_url(url_);
+ entry->set_page_type(NavigationEntry::INTERSTITIAL_PAGE);
+
+ // Give sub-classes a chance to set some states on the navigation entry.
+ UpdateEntry(entry);
+
+ tab_->controller()->AddTransientEntry(entry);
+ }
+ + DCHECK(!render_view_host_); + render_view_host_ = CreateRenderViewHost(); + + std::string data_url = "data:text/html;charset=utf-8," + + EscapePath(GetHTMLContents()); + render_view_host_->NavigateToURL(GURL(data_url)); + + notification_registrar_.Add(this, NOTIFY_TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab_)); + notification_registrar_.Add(this, NOTIFY_NAV_ENTRY_COMMITTED, + Source<NavigationController>(tab_->controller())); + notification_registrar_.Add(this, NOTIFY_NAV_ENTRY_PENDING, + Source<NavigationController>(tab_->controller())); +} - tab_->controller()->AddTransientEntry(entry); +void InterstitialPage::Hide() { + render_view_host_->Shutdown(); + render_view_host_ = NULL; + if (tab_->interstitial_page()) + tab_->remove_interstitial_page(); + // Let's revert to the original title if necessary. + NavigationEntry* entry = tab_->controller()->GetActiveEntry(); + if (!new_navigation_ && should_revert_tab_title_) { + entry->set_title(original_tab_title_); + tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE); } - - tab->ShowInterstitialPage(this); + delete this; } void InterstitialPage::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - DCHECK(type == NOTIFY_DOM_OPERATION_RESPONSE); - std::string json = Details<DomOperationNotificationDetails>(details)->json(); - CommandReceived(json); + if (type == NOTIFY_NAV_ENTRY_PENDING) { + // We are navigating away from the interstitial. Make sure clicking on the + // interstitial will have no effect. + Disable(); + return; + } + DCHECK(type == NOTIFY_TAB_CONTENTS_DESTROYED || + type == NOTIFY_NAV_ENTRY_COMMITTED); + if (!action_taken_) { + // We are navigating away from the interstitial or closing a tab with an + // interstitial. Default to DontProceed(). We don't just call Hide as + // subclasses will almost certainly override DontProceed to do some work + // (ex: close pending connections). + DontProceed(); + } else { + // User decided to proceed and either the navigation was committed or the + // tab was closed before that. + Hide(); + // WARNING: we are now deleted! + } } -void InterstitialPage::InterstitialClosed() {
- delete this;
-}
+RenderViewHost* InterstitialPage::CreateRenderViewHost() { + RenderViewHost* render_view_host = new RenderViewHost( + SiteInstance::CreateSiteInstance(tab()->profile()), + this, MSG_ROUTING_NONE, NULL); + RenderWidgetHostViewWin* view = + new RenderWidgetHostViewWin(render_view_host); + render_view_host->set_view(view); + view->Create(tab_->GetContentHWND()); + view->set_parent_hwnd(tab_->GetContentHWND()); + WebContentsViewWin* web_contents_view = + static_cast<WebContentsViewWin*>(tab_->view()); + render_view_host->CreateRenderView(); + // SetSize must be called after CreateRenderView or the HWND won't show. + view->SetSize(web_contents_view->GetContainerSize()); + + render_view_host->AllowDomAutomationBindings(); + return render_view_host; +} void InterstitialPage::Proceed() { - DCHECK(tab_->type() == TAB_CONTENTS_WEB); - tab_->AsWebContents()->HideInterstitialPage(true, true); + DCHECK(!action_taken_); + Disable(); + action_taken_ = true; + + // Resumes the throbber. + tab_->SetIsLoading(true, NULL); + + // No need to hide if we are a new navigation, we'll get hidden when the + // navigation is committed. + if (!new_navigation_) { + Hide(); + // WARNING: we are now deleted! + } } void InterstitialPage::DontProceed() { - if (create_navigation_entry_) { + DCHECK(!action_taken_); + Disable(); + action_taken_ = true; + + if (new_navigation_) { // Since no navigation happens we have to discard the transient entry // 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_->AsWebContents()->HideInterstitialPage(false, false); + Hide(); // WARNING: we are now deleted! } +void InterstitialPage::SetSize(const gfx::Size& size) { + render_view_host_->view()->SetSize(size); +} + +Profile* InterstitialPage::GetProfile() const { + return tab_->profile(); +} + +void InterstitialPage::DidNavigate( + RenderViewHost* render_view_host, + const ViewHostMsg_FrameNavigate_Params& params) { + // A fast user could have navigated away from the page that triggered the + // interstitial while the interstitial was loading, that would have disabled + // us. In that case we can dismiss ourselves. + if (!enabled_){ + DontProceed(); + return; + } + + // The RenderViewHost has loaded its contents, we can show it now. + render_view_host_->view()->Show(); + tab_->set_interstitial_page(this); + + // Notify the tab we are not loading so the throbber is stopped. It also + // causes a NOTIFY_LOAD_STOP notification, that the AutomationProvider (used + // by the UI tests) expects to consider a navigation as complete. Without this, + // navigating in a UI test to a URL that triggers an interstitial would hang. + tab_->SetIsLoading(false, NULL); +} + +void InterstitialPage::RendererGone(RenderViewHost* render_view_host) { + // Our renderer died. This should not happen in normal cases. + // Just dismiss the interstitial. + DontProceed(); +} + +void InterstitialPage::DomOperationResponse(const std::string& json_string, + int automation_id) { + if (enabled_) + CommandReceived(json_string); +} + +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(); + // 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_) { + original_tab_title_ = entry->title(); + should_revert_tab_title_ = true; + } + entry->set_title(title); + tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE); +} + +void InterstitialPage::Disable() { + enabled_ = false; +} + // static void InterstitialPage::InitInterstitialPageMap() { if (!tab_to_interstitial_page_) @@ -105,10 +244,10 @@ void InterstitialPage::InitInterstitialPageMap() { // static InterstitialPage* InterstitialPage::GetInterstitialPage( - TabContents* tab_contents) { + WebContents* web_contents) { InitInterstitialPageMap(); InterstitialPageMap::const_iterator iter = - tab_to_interstitial_page_->find(tab_contents); + tab_to_interstitial_page_->find(web_contents); if (iter == tab_to_interstitial_page_->end()) return NULL; diff --git a/chrome/browser/interstitial_page.h b/chrome/browser/interstitial_page.h index ce17818..ab8967f 100644 --- a/chrome/browser/interstitial_page.h +++ b/chrome/browser/interstitial_page.h @@ -7,16 +7,16 @@ #include <string> +#include "chrome/browser/web_contents_view_win.h" #include "chrome/common/notification_registrar.h" -#include "chrome/common/notification_service.h" #include "googleurl/src/gurl.h" class NavigationEntry; -class TabContents; +class WebContents; // This class is a base class for interstitial pages, pages that show some // informative message asking for user validation before reaching the target -// page. (Navigating to a page served over bad HTTPS or a page contining +// page. (Navigating to a page served over bad HTTPS or a page containing // malware are typical cases where an interstitial is required.) // // If specified in its constructor, this class creates a navigation entry so @@ -26,27 +26,27 @@ class TabContents; // through a navigation, the WebContents closing them or the tab containing them // being closed. -class InterstitialPage : public NotificationObserver { +class InterstitialPage : public NotificationObserver, + public RenderViewHostDelegate { public: - // Creates an interstitial page to show in |tab|. If |create_navigation_entry| - // is true, a temporary navigation entry is created with the URL |url| and + // Creates an interstitial page to show in |tab|. |new_navigation| should be + // set to true when the interstitial is caused by loading a new page, in which + // case a temporary navigation entry is created with the URL |url| and // added to the navigation controller (so the interstitial page appears as a - // new navigation entry). - InterstitialPage(TabContents* tab, - bool create_navigation_entry, - const GURL& url); + // new navigation entry). |new_navigation| should be false when the + // interstitial was triggered by a loading a sub-resource in a page. + InterstitialPage(WebContents* tab, bool new_navigation, const GURL& url); virtual ~InterstitialPage(); // Shows the interstitial page in the tab. - void Show(); + virtual void Show(); - // Invoked by the tab showing the interstitial to notify that the interstitial
- // page was closed.
- virtual void InterstitialClosed();
+ // Hides the interstitial page. Warning: this deletes the InterstitialPage. + void Hide(); // Retrieves the InterstitialPage if any associated with the specified // |tab_contents| (used by ui tests). - static InterstitialPage* GetInterstitialPage(TabContents* tab_contents); + static InterstitialPage* GetInterstitialPage(WebContents* web_contents); // Sub-classes should return the HTML that should be displayed in the page. virtual std::string GetHTMLContents() { return std::string(); } @@ -57,7 +57,34 @@ class InterstitialPage : public NotificationObserver { // Warning: 'this' has been deleted when this method returns. virtual void DontProceed(); + // Sub-classes should call this method when the user has chosen to proceed to + // the target URL. + // Warning: 'this' has been deleted when this method returns. + virtual void Proceed(); + + // Sizes the RenderViewHost showing the actual interstitial page contents. + void SetSize(const gfx::Size& size); + protected: + // NotificationObserver method: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // RenderViewHostDelegate implementation: + virtual Profile* GetProfile() const; + virtual WebPreferences GetWebkitPrefs() { + return WebPreferences(); + } + virtual void DidNavigate(RenderViewHost* render_view_host, + const ViewHostMsg_FrameNavigate_Params& params); + virtual void RendererGone(RenderViewHost* render_view_host); + virtual void DomOperationResponse(const std::string& json_string, + int automation_id); + virtual void UpdateTitle(RenderViewHost* render_view_host, + int32 page_id, + const std::wstring& title); + // Invoked when the page sent a command through DOMAutomation. virtual void CommandReceived(const std::string& command) { } @@ -68,47 +95,61 @@ class InterstitialPage : public NotificationObserver { // |create_navigation_entry| set to true. virtual void UpdateEntry(NavigationEntry* entry) { } - // Sub-classes should call this method when the user has chosen to proceed to - // the target URL. - // Warning: 'this' has been deleted when this method returns. - virtual void Proceed(); - - TabContents* tab() const { return tab_; } + WebContents* tab() const { return tab_; } const GURL& url() const { return url_; } + RenderViewHost* render_view_host() const { return render_view_host_; } + + // Creates and shows the RenderViewHost containing the interstitial content. + // Overriden in unit tests. + virtual RenderViewHost* CreateRenderViewHost(); private: // AutomationProvider needs access to Proceed and DontProceed to simulate // user actions. friend class AutomationProvider; - // NotificationObserver method. - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - // Initializes tab_to_interstitial_page_ in a thread-safe manner. // Should be called before accessing tab_to_interstitial_page_. static void InitInterstitialPageMap(); - // A flag to indicate if we've notified |delegate_| of the user's decision. - bool delegate_has_been_notified_; + // Disable the interstitial: + // - if it is not yet showing, then it won't be shown. + // - any command sent by the RenderViewHost will be ignored. + void Disable(); // The tab in which we are displayed. - TabContents* tab_; + WebContents* tab_; // The URL that is shown when the interstitial is showing. GURL url_; - // Whether a transient navigation entry should be created when the page is - // shown. - bool create_navigation_entry_; + // Whether this interstitial is shown as a result of a new navigation (in + // which case a transient navigation entry is created). + bool new_navigation_; + + // Whether this interstitial is enabled. See Disable() for more info. + bool enabled_; + + // Whether the Proceed or DontProceed have been called yet. + bool action_taken_; + + // Notification magic.
+ NotificationRegistrar notification_registrar_;
+ + // The RenderViewHost displaying the interstitial contents. + RenderViewHost* render_view_host_; + + // Whether or not we should change the title of the tab when hidden (to revert + // it to its original value). + bool should_revert_tab_title_; - // Notification magic. - NotificationRegistrar notification_registrar_; + // The original title of the tab that should be reverted to when the + // interstitial is hidden. + std::wstring original_tab_title_; // We keep a map of the various blocking pages shown as the UI tests need to // be able to retrieve them. - typedef std::map<TabContents*,InterstitialPage*> InterstitialPageMap; + typedef std::map<WebContents*,InterstitialPage*> InterstitialPageMap; static InterstitialPageMap* tab_to_interstitial_page_; DISALLOW_COPY_AND_ASSIGN(InterstitialPage); diff --git a/chrome/browser/login_prompt.cc b/chrome/browser/login_prompt.cc index 1e95b0c..db9d775 100644 --- a/chrome/browser/login_prompt.cc +++ b/chrome/browser/login_prompt.cc @@ -84,11 +84,11 @@ class LoginHandlerImpl : public LoginHandler, SendNotifications(); } - // Returns the TabContents that needs authentication. - TabContents* GetTabContentsForLogin() { + // Returns the WebContents that needs authentication. + WebContents* GetWebContentsForLogin() { DCHECK(MessageLoop::current() == ui_loop_); - return tab_util::GetTabContentsByID(render_process_host_id_, + return tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_); } @@ -238,7 +238,7 @@ class LoginHandlerImpl : public LoginHandler, DCHECK(MessageLoop::current() == ui_loop_); NotificationService* service = NotificationService::current(); - TabContents* requesting_contents = GetTabContentsForLogin(); + WebContents* requesting_contents = GetWebContentsForLogin(); if (!requesting_contents) return; @@ -311,7 +311,7 @@ class LoginDialogTask : public Task { } void Run() { - TabContents* parent_contents = handler_->GetTabContentsForLogin(); + WebContents* parent_contents = handler_->GetWebContentsForLogin(); if (!parent_contents) { // The request was probably cancelled. return; diff --git a/chrome/browser/navigation_controller.cc b/chrome/browser/navigation_controller.cc index 2b3f96e..35aec38 100644 --- a/chrome/browser/navigation_controller.cc +++ b/chrome/browser/navigation_controller.cc @@ -212,13 +212,10 @@ void NavigationController::Reload(bool check_for_repost) { DiscardNonCommittedEntriesInternal(); int current_index = GetCurrentEntryIndex(); if (check_for_repost_ && check_for_repost && current_index != -1 && - GetEntryAtIndex(current_index)->has_post_data() && - active_contents_->AsWebContents() && - !active_contents_->AsWebContents()->showing_repost_interstitial()) { - // The user is asking to reload a page with POST data and we're not showing - // the POST interstitial. Prompt to make sure they really want to do this. - // If they do, RepostFormWarningDialog calls us back with - // ReloadDontCheckForRepost. + GetEntryAtIndex(current_index)->has_post_data()) { + // The user is asking to reload a page with POST data. Prompt to make sure + // they really want to do this. If they do, RepostFormWarningDialog calls us + // back with ReloadDontCheckForRepost. active_contents_->Activate(); RepostFormWarningDialog::RunRepostFormWarningDialog(this); } else { @@ -538,7 +535,6 @@ const SkBitmap& NavigationController::GetLazyFavIcon() const { bool NavigationController::RendererDidNavigate( const ViewHostMsg_FrameNavigate_Params& params, - bool is_interstitial, LoadCommittedDetails* details) { // Save the previous state before we clobber it. if (GetLastCommittedEntry()) { @@ -613,7 +609,6 @@ bool NavigationController::RendererDidNavigate( details->entry = GetActiveEntry(); details->is_in_page = IsURLInPageNavigation(params.url); details->is_main_frame = PageTransition::IsMainFrame(params.transition); - details->is_interstitial = is_interstitial; details->serialized_security_info = params.security_info; details->is_content_filtered = params.is_content_filtered; NotifyNavigationEntryCommitted(details); diff --git a/chrome/browser/navigation_controller.h b/chrome/browser/navigation_controller.h index bd1d2aa..ce5a20f 100644 --- a/chrome/browser/navigation_controller.h +++ b/chrome/browser/navigation_controller.h @@ -51,8 +51,7 @@ class NavigationController { : entry(NULL), is_auto(false), is_in_page(false), - is_main_frame(true), - is_interstitial(false) { + is_main_frame(true) { } // The committed entry. This will be the active entry in the controller. @@ -85,10 +84,6 @@ class NavigationController { // sub-frame. bool is_main_frame; - // True when this navigation is for an interstitial page. Many consumers - // won't care about interstitial loads. - bool is_interstitial; - // Whether the content of this frame has been altered/blocked because it was // unsafe. bool is_content_filtered; @@ -325,7 +320,6 @@ class NavigationController { // In the case that nothing has changed, the details structure is undefined // and it will return false. bool RendererDidNavigate(const ViewHostMsg_FrameNavigate_Params& params, - bool is_interstitial, LoadCommittedDetails* details); // Notifies us that we just became active. This is used by the TabContents diff --git a/chrome/browser/navigation_controller_unittest.cc b/chrome/browser/navigation_controller_unittest.cc index 08b43a0..26fd338 100644 --- a/chrome/browser/navigation_controller_unittest.cc +++ b/chrome/browser/navigation_controller_unittest.cc @@ -794,8 +794,7 @@ TEST_F(NavigationControllerTest, NewSubframe) { params.is_post = false; NavigationController::LoadCommittedDetails details; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(url1, details.previous_url); EXPECT_FALSE(details.is_auto); @@ -829,8 +828,7 @@ TEST_F(NavigationControllerTest, SubframeOnEmptyPage) { params.is_post = false; NavigationController::LoadCommittedDetails details; - EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_EQ(0, notifications.size()); } @@ -855,8 +853,7 @@ TEST_F(NavigationControllerTest, AutoSubframe) { // Navigating should do nothing. NavigationController::LoadCommittedDetails details; - EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_EQ(0, notifications.size()); // There should still be only one entry. @@ -885,8 +882,7 @@ TEST_F(NavigationControllerTest, BackSubframe) { // This should generate a new entry. NavigationController::LoadCommittedDetails details; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(2, contents->controller()->GetEntryCount()); @@ -894,8 +890,7 @@ TEST_F(NavigationControllerTest, BackSubframe) { const GURL url3(scheme1() + ":foo3"); params.page_id = 2; params.url = url3; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(3, contents->controller()->GetEntryCount()); EXPECT_EQ(2, contents->controller()->GetCurrentEntryIndex()); @@ -904,8 +899,7 @@ TEST_F(NavigationControllerTest, BackSubframe) { contents->controller()->GoBack(); params.url = url2; params.page_id = 1; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(3, contents->controller()->GetEntryCount()); EXPECT_EQ(1, contents->controller()->GetCurrentEntryIndex()); @@ -914,8 +908,7 @@ TEST_F(NavigationControllerTest, BackSubframe) { contents->controller()->GoBack(); params.url = url1; params.page_id = 0; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(3, contents->controller()->GetEntryCount()); EXPECT_EQ(0, contents->controller()->GetCurrentEntryIndex()); @@ -966,8 +959,7 @@ TEST_F(NavigationControllerTest, InPage) { // This should generate a new entry. NavigationController::LoadCommittedDetails details; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false, - &details)); + EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(2, contents->controller()->GetEntryCount()); @@ -976,7 +968,7 @@ TEST_F(NavigationControllerTest, InPage) { contents->controller()->GoBack(); back_params.url = url1; back_params.page_id = 0; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params, false, + EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(2, contents->controller()->GetEntryCount()); @@ -988,7 +980,7 @@ TEST_F(NavigationControllerTest, InPage) { contents->controller()->GoForward(); forward_params.url = url2; forward_params.page_id = 1; - EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params, false, + EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params, &details)); EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED)); EXPECT_EQ(2, contents->controller()->GetEntryCount()); @@ -1001,10 +993,10 @@ TEST_F(NavigationControllerTest, InPage) { // one identified by an existing page ID. This would result in the second URL // losing the reference fragment when you navigate away from it and then back. contents->controller()->GoBack(); - EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params, false, + EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params, &details)); contents->controller()->GoForward(); - EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params, false, + EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params, &details)); EXPECT_EQ(forward_params.url, contents->controller()->GetActiveEntry()->url()); @@ -1250,7 +1242,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) { params.gesture = NavigationGestureUser; params.is_post = false; NavigationController::LoadCommittedDetails details; - controller->RendererDidNavigate(params, false, &details); + controller->RendererDidNavigate(params, &details); // There should be no longer any pending entry and one committed one. This // means that we were able to locate the entry, assign its site instance, and diff --git a/chrome/browser/provisional_load_details.cc b/chrome/browser/provisional_load_details.cc index f7a9f89..ffc85a0 100644 --- a/chrome/browser/provisional_load_details.cc +++ b/chrome/browser/provisional_load_details.cc @@ -8,13 +8,11 @@ #include "chrome/browser/ssl_manager.h" ProvisionalLoadDetails::ProvisionalLoadDetails(bool is_main_frame, - bool is_interstitial_page, bool is_in_page_navigation, const GURL& url, const std::string& security_info, bool is_content_filtered) : is_main_frame_(is_main_frame), - is_interstitial_page_(is_interstitial_page), is_in_page_navigation_(is_in_page_navigation), url_(url), error_code_(net::OK), diff --git a/chrome/browser/provisional_load_details.h b/chrome/browser/provisional_load_details.h index 9f63acb..5cb9501 100644 --- a/chrome/browser/provisional_load_details.h +++ b/chrome/browser/provisional_load_details.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_PROVISIONAL_LOAD_DETAILS_H__ -#define CHROME_BROWSER_PROVISIONAL_LOAD_DETAILS_H__ +#ifndef CHROME_BROWSER_PROVISIONAL_LOAD_DETAILS_H_ +#define CHROME_BROWSER_PROVISIONAL_LOAD_DETAILS_H_ #include "base/basictypes.h" #include "googleurl/src/gurl.h" @@ -20,7 +20,6 @@ class ProvisionalLoadDetails { public: ProvisionalLoadDetails(bool main_frame, - bool interstitial_page, bool in_page_navigation, const GURL& url, const std::string& security_info, @@ -34,8 +33,6 @@ class ProvisionalLoadDetails { bool main_frame() const { return is_main_frame_; } - bool interstitial_page() const { return is_interstitial_page_; } - bool in_page_navigation() const { return is_in_page_navigation_; } int ssl_cert_id() const { return ssl_cert_id_; } @@ -50,15 +47,14 @@ class ProvisionalLoadDetails { int error_code_; GURL url_; bool is_main_frame_; - bool is_interstitial_page_; bool is_in_page_navigation_; int ssl_cert_id_; int ssl_cert_status_; int ssl_security_bits_; bool is_content_filtered_; - DISALLOW_EVIL_CONSTRUCTORS(ProvisionalLoadDetails); + DISALLOW_COPY_AND_ASSIGN(ProvisionalLoadDetails); }; -#endif // CHROME_BROWSER_PROVISIONAL_LOAD_DETAILS_H__ +#endif // CHROME_BROWSER_PROVISIONAL_LOAD_DETAILS_H_ diff --git a/chrome/browser/render_view_host_manager.cc b/chrome/browser/render_view_host_manager.cc index 81e95aa..5ad576b 100644 --- a/chrome/browser/render_view_host_manager.cc +++ b/chrome/browser/render_view_host_manager.cc @@ -6,7 +6,6 @@ #include "base/command_line.h" #include "base/logging.h" -#include "chrome/browser/interstitial_page.h" #include "chrome/browser/navigation_controller.h" #include "chrome/browser/navigation_entry.h" #include "chrome/browser/render_widget_host_view.h" @@ -16,37 +15,23 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_service.h" -// Destroys the given |**render_view_host| and NULLs out |*render_view_host| -// and then NULLs the field. Callers should only pass pointers to the -// pending_render_view_host_, interstitial_render_view_host_, or -// original_render_view_host_ fields of this object. -static void CancelRenderView(RenderViewHost** render_view_host) { - (*render_view_host)->Shutdown(); - (*render_view_host) = NULL; -} - RenderViewHostManager::RenderViewHostManager( RenderViewHostFactory* render_view_factory, RenderViewHostDelegate* render_view_delegate, Delegate* delegate) : delegate_(delegate), - renderer_state_(NORMAL), + cross_navigation_pending_(false), render_view_factory_(render_view_factory), render_view_delegate_(render_view_delegate), render_view_host_(NULL), - original_render_view_host_(NULL), - interstitial_render_view_host_(NULL), pending_render_view_host_(NULL), - interstitial_page_(NULL), - showing_repost_interstitial_(false) { + interstitial_page_(NULL) { } RenderViewHostManager::~RenderViewHostManager() { // Shutdown should have been called which should have cleaned these up. DCHECK(!render_view_host_); DCHECK(!pending_render_view_host_); - DCHECK(!original_render_view_host_); - DCHECK(!interstitial_render_view_host_); } void RenderViewHostManager::Init(Profile* profile, @@ -63,21 +48,8 @@ void RenderViewHostManager::Init(Profile* profile, } void RenderViewHostManager::Shutdown() { - if (showing_interstitial_page()) { - // The tab is closed while the interstitial page is showing, hide and - // destroy it. - HideInterstitialPage(false, false); - } - DCHECK(!interstitial_render_view_host_) << "Should have been deleted by Hide"; - - if (pending_render_view_host_) { - pending_render_view_host_->Shutdown(); - pending_render_view_host_ = NULL; - } - if (original_render_view_host_) { - original_render_view_host_->Shutdown(); - original_render_view_host_ = NULL; - } + if (pending_render_view_host_) + CancelPendingRenderView(); // We should always have a main RenderViewHost. render_view_host_->Shutdown(); @@ -123,29 +95,17 @@ RenderViewHost* RenderViewHostManager::Navigate(const NavigationEntry& entry) { } } - showing_repost_interstitial_ = false; return dest_render_view_host; } void RenderViewHostManager::Stop() { render_view_host_->Stop(); - // If we aren't in the NORMAL renderer state, we should stop the pending - // renderers. This will lead to a DidFailProvisionalLoad, which will - // properly destroy them. - if (renderer_state_ == PENDING) { + // If we are cross-navigating, we should stop the pending renderers. This + // will lead to a DidFailProvisionalLoad, which will properly destroy them. + if (cross_navigation_pending_) { pending_render_view_host_->Stop(); - } else if (renderer_state_ == ENTERING_INTERSTITIAL) { - interstitial_render_view_host_->Stop(); - if (pending_render_view_host_) { - pending_render_view_host_->Stop(); - } - - } else if (renderer_state_ == LEAVING_INTERSTITIAL) { - if (pending_render_view_host_) { - pending_render_view_host_->Stop(); - } } } @@ -153,12 +113,10 @@ void RenderViewHostManager::SetIsLoading(bool is_loading) { render_view_host_->SetIsLoading(is_loading); if (pending_render_view_host_) pending_render_view_host_->SetIsLoading(is_loading); - if (original_render_view_host_) - original_render_view_host_->SetIsLoading(is_loading); } bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { - if (renderer_state_ != PENDING) + if (!cross_navigation_pending_) return true; // If the tab becomes unresponsive during unload while doing a @@ -178,119 +136,31 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { void RenderViewHostManager::DidNavigateMainFrame( RenderViewHost* render_view_host) { - if (renderer_state_ == NORMAL) { + if (!cross_navigation_pending_) { // We should only hear this from our current renderer. DCHECK(render_view_host == render_view_host_); return; - } else if (renderer_state_ == PENDING) { - if (render_view_host == pending_render_view_host_) { - // The pending cross-site navigation completed, so show the renderer. - SwapToRenderView(&pending_render_view_host_, true); - renderer_state_ = NORMAL; - } else if (render_view_host == render_view_host_) { - // A navigation in the original page has taken place. Cancel the pending - // one. - CancelRenderView(&pending_render_view_host_); - renderer_state_ = NORMAL; - } else { - // No one else should be sending us DidNavigate in this state. - DCHECK(false); - return; - } - - } else if (renderer_state_ == ENTERING_INTERSTITIAL) { - if (render_view_host == interstitial_render_view_host_) { - // The interstitial renderer is ready, so show it, and keep the old - // RenderViewHost around. - original_render_view_host_ = render_view_host_; - SwapToRenderView(&interstitial_render_view_host_, false); - renderer_state_ = INTERSTITIAL; - } else if (render_view_host == render_view_host_) { - // We shouldn't get here, because the original render view was the one - // that caused the ShowInterstitial. - // However, until we intercept navigation events from JavaScript, it is - // possible to get here, if another tab tells render_view_host_ to - // navigate. To be safe, we'll cancel the interstitial and show the - // page that caused the DidNavigate. - CancelRenderView(&interstitial_render_view_host_); - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - renderer_state_ = NORMAL; - } else if (render_view_host == pending_render_view_host_) { - // We shouldn't get here, because the original render view was the one - // that caused the ShowInterstitial. - // However, until we intercept navigation events from JavaScript, it is - // possible to get here, if another tab tells pending_render_view_host_ - // to navigate. To be safe, we'll cancel the interstitial and show the - // page that caused the DidNavigate. - CancelRenderView(&interstitial_render_view_host_); - SwapToRenderView(&pending_render_view_host_, true); - renderer_state_ = NORMAL; - } else { - // No one else should be sending us DidNavigate in this state. - DCHECK(false); - return; - } - - } else if (renderer_state_ == INTERSTITIAL) { - if (render_view_host == original_render_view_host_) { - // We shouldn't get here, because the original render view was the one - // that caused the ShowInterstitial. - // However, until we intercept navigation events from JavaScript, it is - // possible to get here, if another tab tells render_view_host_ to - // navigate. To be safe, we'll cancel the interstitial and show the - // page that caused the DidNavigate. - SwapToRenderView(&original_render_view_host_, true); - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - renderer_state_ = NORMAL; - } else if (render_view_host == pending_render_view_host_) { - // No one else should be sending us DidNavigate in this state. - // However, until we intercept navigation events from JavaScript, it is - // possible to get here, if another tab tells pending_render_view_host_ - // to navigate. To be safe, we'll cancel the interstitial and show the - // page that caused the DidNavigate. - SwapToRenderView(&pending_render_view_host_, true); - CancelRenderView(&original_render_view_host_); - renderer_state_ = NORMAL; - } else { - // No one else should be sending us DidNavigate in this state. - DCHECK(false); - return; - } - InterstitialPageGone(); - - } else if (renderer_state_ == LEAVING_INTERSTITIAL) { - if (render_view_host == original_render_view_host_) { - // We navigated to something in the original renderer, so show it. - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - SwapToRenderView(&original_render_view_host_, true); - renderer_state_ = NORMAL; - } else if (render_view_host == pending_render_view_host_) { - // We navigated to something in the pending renderer. - CancelRenderView(&original_render_view_host_); - SwapToRenderView(&pending_render_view_host_, true); - renderer_state_ = NORMAL; - } else { - // No one else should be sending us DidNavigate in this state. - DCHECK(false); - return; - } - InterstitialPageGone(); + } + if (render_view_host == pending_render_view_host_) { + // The pending cross-site navigation completed, so show the renderer. + SwapToRenderView(&pending_render_view_host_, true); + cross_navigation_pending_ = false; + } else if (render_view_host == render_view_host_) { + // A navigation in the original page has taken place. Cancel the pending + // one. + CancelPendingRenderView(); + cross_navigation_pending_ = false; } else { - // No such state. + // No one else should be sending us DidNavigate in this state. DCHECK(false); - return; } } void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, int new_request_id) { - // Should only see this while we have a pending renderer, possibly during an - // interstitial. Otherwise, we should ignore. - if (renderer_state_ != PENDING && renderer_state_ != LEAVING_INTERSTITIAL) + // Should only see this while we have a pending renderer. + if (!cross_navigation_pending_) return; DCHECK(pending_render_view_host_); @@ -298,14 +168,7 @@ void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, // will send a ClosePage_ACK to the ResourceDispatcherHost with the given // IDs (of the pending RVH's request), allowing the pending RVH's response to // resume. - if (showing_interstitial_page()) { - DCHECK(original_render_view_host_); - original_render_view_host_->ClosePage(new_render_process_host_id, - new_request_id); - } else { - render_view_host_->ClosePage(new_render_process_host_id, - new_request_id); - } + render_view_host_->ClosePage(new_render_process_host_id, new_request_id); // ResourceDispatcherHost has told us to run the onunload handler, which // means it is not a download or unsafe page, and we are going to perform the @@ -327,50 +190,6 @@ void RenderViewHostManager::RendererAbortedProvisionalLoad( // navigation events. (That's necessary to support onunload anyway.) Once // we've made that change, we won't create a pending renderer until we know // the response is not a download. - - if (renderer_state_ == ENTERING_INTERSTITIAL) { - if ((pending_render_view_host_ && - (pending_render_view_host_ == render_view_host)) || - (!pending_render_view_host_ && - (render_view_host_ == render_view_host))) { - // The abort came from the RenderViewHost that triggered the - // interstitial. (e.g., User clicked stop after ShowInterstitial but - // before the interstitial was visible.) We should go back to NORMAL. - // Note that this is an uncommon case, because we are only in the - // ENTERING_INTERSTITIAL state in the small time window while the - // interstitial's RenderViewHost is being created. - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - CancelRenderView(&interstitial_render_view_host_); - renderer_state_ = NORMAL; - } - - // We can get here, at least in the following case. - // We show an interstitial, then navigate to a URL that leads to another - // interstitial. Now there's a race. The new interstitial will be - // created and we will go to ENTERING_INTERSTITIAL, but the old one will - // meanwhile destroy itself and fire DidFailProvisionalLoad. That puts - // us here. Should be safe to ignore the DidFailProvisionalLoad, from - // the perspective of the renderer state. - } else if (renderer_state_ == LEAVING_INTERSTITIAL) { - // If we've left the interstitial by seeing a download (or otherwise - // aborting a load), we should get back to the original page, because - // interstitial page doesn't make sense anymore. (For example, we may - // have clicked Proceed on a download URL.) - - // TODO(creis): This causes problems in the old process model when - // visiting a new URL from an interstitial page. - // This is because we receive a DidFailProvisionalLoad from cancelling - // the first request, which is indistinguishable from a - // DidFailProvisionalLoad from the second request (if it is a download). - // We need to find a way to distinguish these cases, because it doesn't - // make sense to keep showing the interstitial after a download. - // if (pending_render_view_host_) - // CancelRenderView(&pending_render_view_host_); - // SwapToRenderView(&original_render_view_host_, true); - // renderer_state_ = NORMAL; - // delegate_->InterstitialPageGoneFromRenderManager(); - } } void RenderViewHostManager::ShouldClosePage(bool proceed) { @@ -388,226 +207,21 @@ void RenderViewHostManager::ShouldClosePage(bool proceed) { return; } - DCHECK(renderer_state_ != ENTERING_INTERSTITIAL); - DCHECK(renderer_state_ != INTERSTITIAL); if (proceed) { // Ok to unload the current page, so proceed with the cross-site navigate. pending_render_view_host_->SetNavigationsSuspended(false); } else { // Current page says to cancel. - CancelRenderView(&pending_render_view_host_); - renderer_state_ = NORMAL; + CancelPendingRenderView(); + cross_navigation_pending_ = false; } } -void RenderViewHostManager::ShowInterstitialPage( - InterstitialPage* interstitial_page) { - // Note that it is important that the interstitial page render view host is - // in the same process as the normal render view host for the tab, so they - // use page ids from the same pool. If they came from different processes, - // page ids may collide causing confusion in the controller (existing - // navigation entries in the controller history could get overridden with the - // interstitial entry). - SiteInstance* interstitial_instance = NULL; - - if (renderer_state_ == NORMAL) { - // render_view_host_ will not be deleted before the end of this method, so - // we don't have to worry about this SiteInstance's ref count dropping to - // zero. - interstitial_instance = render_view_host_->site_instance(); - - } else if (renderer_state_ == PENDING) { - // pending_render_view_host_ will not be deleted before the end of this - // method (when we are in this state), so we don't have to worry about this - // SiteInstance's ref count dropping to zero. - interstitial_instance = pending_render_view_host_->site_instance(); - - } else if (renderer_state_ == ENTERING_INTERSTITIAL) { - // We should never get here if we're in the process of showing an - // interstitial. - // However, until we intercept navigation events from JavaScript, it is - // possible to get here, if another tab tells render_view_host_ to - // navigate to a URL that causes an interstitial. To be safe, we'll cancel - // the first interstitial. - CancelRenderView(&interstitial_render_view_host_); - renderer_state_ = NORMAL; - - // We'd like to now show the new interstitial, but if there's a - // pending_render_view_host_, we can't tell if this JavaScript navigation - // occurred in the original or the pending renderer. That means we won't - // know where to proceed, so we can't show the interstitial. This is - // really just meant to avoid a crash until we can intercept JavaScript - // navigation events, so for now we'll kill the interstitial and go back - // to the last known good page. - if (pending_render_view_host_) { - CancelRenderView(&pending_render_view_host_); - return; - } - // Should be safe to show the interstitial for the new page. - // render_view_host_ will not be deleted before the end of this method, so - // we don't have to worry about this SiteInstance's ref count dropping to - // zero. - interstitial_instance = render_view_host_->site_instance(); - - } else if (renderer_state_ == INTERSTITIAL) { - // We should never get here if we're already showing an interstitial. - // However, until we intercept navigation events from JavaScript, it is - // possible to get here, if another tab tells render_view_host_ to - // navigate to a URL that causes an interstitial. To be safe, we'll go - // back to normal first. - if (pending_render_view_host_ != NULL) { - // There was a pending RVH. We don't know which RVH caused this call - // to ShowInterstitial, so we can't really proceed. We'll have to stay - // in the NORMAL state, showing the last good page. This is only a - // temporary fix anyway, to stave off a crash. - HideInterstitialPage(false, false); - return; - } - // Should be safe to show the interstitial for the new page. - // render_view_host_ will not be deleted before the end of this method, so - // we don't have to worry about this SiteInstance's ref count dropping to - // zero. - SwapToRenderView(&original_render_view_host_, true); - interstitial_instance = render_view_host_->site_instance(); - - } else if (renderer_state_ == LEAVING_INTERSTITIAL) { - SwapToRenderView(&original_render_view_host_, true); - interstitial_instance = NULL; - if (pending_render_view_host_) { - // We're now effectively in PENDING. - // pending_render_view_host_ will not be deleted before the end of this - // method, so we don't have to worry about this SiteInstance's ref count - // dropping to zero. - interstitial_instance = pending_render_view_host_->site_instance(); - } else { - // We're now effectively in NORMAL. - // render_view_host_ will not be deleted before the end of this method, - // so we don't have to worry about this SiteInstance's ref count dropping - // to zero. - interstitial_instance = render_view_host_->site_instance(); - } - - } else { - // No such state. - DCHECK(false); - return; - } - - // Create a pending renderer and move to ENTERING_INTERSTITIAL. - interstitial_render_view_host_ = - CreateRenderViewHost(interstitial_instance, MSG_ROUTING_NONE, NULL); - interstitial_page_ = interstitial_page; - bool success = delegate_->CreateRenderViewForRenderManager( - interstitial_render_view_host_); - if (!success) { - // TODO(creis): If this fails, should we load the interstitial in - // render_view_host_? We shouldn't just skip the interstitial... - CancelRenderView(&interstitial_render_view_host_); - return; - } - - // Don't show the view yet. - interstitial_render_view_host_->view()->Hide(); - - renderer_state_ = ENTERING_INTERSTITIAL; - - // We allow the DOM bindings as a way to get the page to talk back to us. - interstitial_render_view_host_->AllowDomAutomationBindings(); - - interstitial_render_view_host_->LoadAlternateHTMLString( - interstitial_page->GetHTMLContents(), false, - GURL::EmptyGURL(), - std::string()); -} - -void RenderViewHostManager::HideInterstitialPage(bool wait_for_navigation, - bool proceed) { - if (renderer_state_ == NORMAL || renderer_state_ == PENDING) { - // Shouldn't get here, since there's no interstitial showing. - DCHECK(false); - return; - - } else if (renderer_state_ == ENTERING_INTERSTITIAL) { - // Unclear if it is possible to get here. (Can you hide the interstitial - // before it is shown?) If so, we should go back to NORMAL. - CancelRenderView(&interstitial_render_view_host_); - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - renderer_state_ = NORMAL; - return; - } - - DCHECK(showing_interstitial_page()); - DCHECK(render_view_host_ && original_render_view_host_ && - !interstitial_render_view_host_); - - if (renderer_state_ == INTERSTITIAL) { - // Disable the Proceed button on the interstitial, because the destination - // renderer might get replaced. - DisableInterstitialProceed(false); - - } else if (renderer_state_ == LEAVING_INTERSTITIAL) { - // We have already given up the ability to proceed by starting a new - // navigation. If this is a request to proceed, we must ignore it. - // (Hopefully we will have disabled the Proceed button by now, but it's - // possible to get here before that happens.) - if (proceed) - return; - } - - if (wait_for_navigation) { - // We are resuming the loading. We need to set the state to loading again - // as it was set to false when the interstitial stopped loading (so the - // throbber runs). - delegate_->DidStartLoadingFromRenderManager(render_view_host_, NULL); - } - - if (proceed) { - // Now we will resume loading automatically, either in - // original_render_view_host_ or in pending_render_view_host_. When it - // completes, we will display the renderer in DidNavigate. - renderer_state_ = LEAVING_INTERSTITIAL; - - } else { - // Don't proceed. Go back to the previously showing page. - if (renderer_state_ == LEAVING_INTERSTITIAL) { - // We said DontProceed after starting to leave the interstitial. - // Abandon whatever we were in the process of doing. - original_render_view_host_->Stop(); - } - SwapToRenderView(&original_render_view_host_, true); - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - renderer_state_ = NORMAL; - InterstitialPageGone(); - } -} - -bool RenderViewHostManager::IsRenderViewInterstitial( - const RenderViewHost* render_view_host) const { - if (showing_interstitial_page()) - return render_view_host_ == render_view_host; - if (renderer_state_ == ENTERING_INTERSTITIAL) - return interstitial_render_view_host_ == render_view_host; - return false; -} - void RenderViewHostManager::OnJavaScriptMessageBoxClosed( IPC::Message* reply_msg, bool success, const std::wstring& prompt) { - RenderViewHost* rvh = render_view_host_; - if (showing_interstitial_page()) { - // No JavaScript message boxes are ever shown by interstitial pages, but - // they can be shown by the original RVH while an interstitial page is - // showing (e.g., from an onunload event handler). We should send this to - // the original RVH and not the interstitial's RVH. - // TODO(creis): Perhaps the JavascriptMessageBoxHandler should store which - // RVH created it, so that it can tell this method which RVH to reply to. - DCHECK(original_render_view_host_); - rvh = original_render_view_host_; - } - rvh->JavaScriptMessageBoxClosed(reply_msg, success, prompt); + render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, prompt); } @@ -676,7 +290,7 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( // compare the entry's URL to the last committed entry's URL. NavigationController* controller = delegate_->GetControllerForRenderManager(); NavigationEntry* curr_entry = controller->GetLastCommittedEntry(); - if (showing_interstitial_page()) { + 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); @@ -725,7 +339,7 @@ bool RenderViewHostManager::CreatePendingRenderView(SiteInstance* instance) { // Don't show the view until we get a DidNavigate from it. pending_render_view_host_->view()->Hide(); } else { - CancelRenderView(&pending_render_view_host_); + CancelPendingRenderView(); } return success; } @@ -794,37 +408,18 @@ void RenderViewHostManager::SwapToRenderView( RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate( const NavigationEntry& entry) { - // If we are in PENDING or ENTERING_INTERSTITIAL, then we want to get back - // to NORMAL and navigate as usual. - if (renderer_state_ == PENDING || renderer_state_ == ENTERING_INTERSTITIAL) { + // If we are cross-navigating, then we want to get back to normal and navigate + // as usual. + if (cross_navigation_pending_) { if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - if (interstitial_render_view_host_) - CancelRenderView(&interstitial_render_view_host_); - renderer_state_ = NORMAL; + CancelPendingRenderView(); + cross_navigation_pending_ = false; } // render_view_host_ will not be deleted before the end of this method, so we // don't have to worry about this SiteInstance's ref count dropping to zero. SiteInstance* curr_instance = render_view_host_->site_instance(); - if (showing_interstitial_page()) { - // Must disable any ability to proceed from the interstitial, because we're - // about to navigate somewhere else. - DisableInterstitialProceed(true); - - if (pending_render_view_host_) - CancelRenderView(&pending_render_view_host_); - - renderer_state_ = LEAVING_INTERSTITIAL; - - // We want to compare against where we were, because we just cancelled - // where we were going. The original_render_view_host_ won't be deleted - // before the end of this method, so we don't have to worry about this - // SiteInstance's ref count dropping to zero. - curr_instance = original_render_view_host_->site_instance(); - } - // Determine if we need a new SiteInstance for this entry. // Again, new_instance won't be deleted before the end of this method, so it // is safe to use a normal pointer here. @@ -834,8 +429,7 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate( if (new_instance != curr_instance) { // New SiteInstance. - DCHECK(renderer_state_ == NORMAL || - renderer_state_ == LEAVING_INTERSTITIAL); + DCHECK(!cross_navigation_pending_); // Create a pending RVH and navigate it. bool success = CreatePendingRenderView(new_instance); @@ -844,36 +438,14 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate( // Check if our current RVH is live before we set up a transition. if (!render_view_host_->IsRenderViewLive()) { - if (renderer_state_ == NORMAL) { + if (!cross_navigation_pending_) { // The current RVH is not live. There's no reason to sit around with a // sad tab or a newly created RVH while we wait for the pending RVH to - // navigate. Just switch to the pending RVH now and go back to NORMAL, - // without requiring a cross-site transition. (Note that we don't care - // about on{before}unload handlers if the current RVH isn't live.) + // navigate. Just switch to the pending RVH now and go back to non + // cross-navigating (Note that we don't care about on{before}unload + // handlers if the current RVH isn't live.) SwapToRenderView(&pending_render_view_host_, true); return render_view_host_; - - } else if (renderer_state_ == LEAVING_INTERSTITIAL) { - // Cancel the interstitial, since it has died and we're navigating away - // anyway. - DCHECK(original_render_view_host_); - if (original_render_view_host_->IsRenderViewLive()) { - // Swap back to the original and act like a pending request (using - // the logic below). - SwapToRenderView(&original_render_view_host_, true); - renderer_state_ = NORMAL; - InterstitialPageGone(); - // Continue with the pending cross-site transition logic below. - } else { - // Both the interstitial and original are dead. Just like the NORMAL - // case, let's skip the cross-site transition entirely. We also have - // to clean up the interstitial state. - SwapToRenderView(&pending_render_view_host_, true); - CancelRenderView(&original_render_view_host_); - renderer_state_ = NORMAL; - InterstitialPageGone(); - return render_view_host_; - } } else { NOTREACHED(); return render_view_host_; @@ -895,12 +467,9 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate( // old page's onunload handler before it sends the response. pending_render_view_host_->SetHasPendingCrossSiteRequest(true, -1); - // We now have a pending RVH. If we were in NORMAL, we should now be in - // PENDING. If we were in LEAVING_INTERSTITIAL, we should stay there. - if (renderer_state_ == NORMAL) - renderer_state_ = PENDING; - else - DCHECK(renderer_state_ == LEAVING_INTERSTITIAL); + // We now have a pending RVH. + DCHECK(!cross_navigation_pending_); + cross_navigation_pending_ = true; // Tell the old render view to run its onbeforeunload handler, since it // doesn't otherwise know that the cross-site request is happening. This @@ -910,38 +479,14 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate( return pending_render_view_host_; } - // Same SiteInstance can be used. Navigate render_view_host_ if we are in - // the NORMAL state, and original_render_view_host_ if an interstitial is - // showing. - if (renderer_state_ == NORMAL) - return render_view_host_; - - DCHECK(renderer_state_ == LEAVING_INTERSTITIAL); - return original_render_view_host_; -} - -void RenderViewHostManager::DisableInterstitialProceed(bool stop_request) { - // TODO(creis): Make sure the interstitial page disables any ability to - // proceed at this point, because we're about to abort the original request. - // This can be done by adding a new event to the NotificationService. - // We should also disable the button on the page itself, but it's ok if that - // doesn't happen immediately. - - // Stopping the request is necessary if we are navigating away, because the - // user could be requesting the same URL again, causing the HttpCache to - // ignore it. (Fixes bug 1079784.) - if (stop_request) { - original_render_view_host_->Stop(); - if (pending_render_view_host_) - pending_render_view_host_->Stop(); - } + // Same SiteInstance can be used. Navigate render_view_host_ if we are not + // cross navigating. + DCHECK(!cross_navigation_pending_); + return render_view_host_; } -void RenderViewHostManager::InterstitialPageGone() { - DCHECK(!showing_interstitial_page()); - if (interstitial_page_) { - interstitial_page_->InterstitialClosed(); - interstitial_page_ = NULL; - } +void RenderViewHostManager::CancelPendingRenderView() { + pending_render_view_host_->Shutdown(); + pending_render_view_host_ = NULL; } diff --git a/chrome/browser/render_view_host_manager.h b/chrome/browser/render_view_host_manager.h index 371c398..40eabce 100644 --- a/chrome/browser/render_view_host_manager.h +++ b/chrome/browser/render_view_host_manager.h @@ -22,8 +22,8 @@ class RenderWidgetHostView; class SiteInstance; // Manages RenderViewHosts for a WebContents. Normally there is only one and -// it is easy to do. But we can also have interstitial pages and transitions -// of processes (and hence RenderViewHosts) that can get very complex. +// it is easy to do. But we can also have transitions of processes (and hence +// RenderViewHosts) that can get complex. class RenderViewHostManager { public: // Functions implemented by our owner that we need. @@ -101,9 +101,9 @@ class RenderViewHostManager { // page to stop loading. void Stop(); - // Notifies all RenderViewHosts (regular, interstitials, etc.) that a load is - // or is not happening. Even though the message is only for one of them, we - // don't know which one so we tell them all. + // Notifies the regular and pending RenderViewHosts that a load is or is not + // happening. Even though the message is only for one of them, we don't know + // which one so we tell both. void SetIsLoading(bool is_loading); // Whether to close the tab or not when there is a hang during an unload @@ -111,8 +111,7 @@ class RenderViewHostManager { // with the navigation instead of closing the tab. bool ShouldCloseTabOnUnresponsiveRenderer(); - // Called when a renderer's main frame navigates. This handles all the logic - // associated with interstitial management. + // Called when a renderer's main frame navigates. void DidNavigateMainFrame(RenderViewHost* render_view_host); // Allows the WebContents to react when a cross-site response is ready to be @@ -128,49 +127,28 @@ class RenderViewHostManager { // WebContents. void ShouldClosePage(bool proceed); - // Displays an interstitial page in the current page. This method can be used - // to show temporary pages (such as security error pages). It can be hidden - // by calling HideInterstitialPage, in which case the original page is - // restored. The passed InterstitialPage is owned by the caller and must - // remain valid while the interstitial page is shown. - void ShowInterstitialPage(InterstitialPage* interstitial_page); - - // Reverts from the interstitial page to the original page. - // If |wait_for_navigation| is true, the interstitial page is removed when - // the original page has transitioned to the new contents. This is useful - // when you want to hide the interstitial page as you navigate to a new page. - // Hiding the interstitial page right away would show the previous displayed - // page. If |proceed| is true, the WebContents will expect the navigation - // to complete. If not, it will revert to the last shown page. - void HideInterstitialPage(bool wait_for_navigation, - bool proceed); - - // Returns true if the given render view host is an interstitial. - bool IsRenderViewInterstitial(const RenderViewHost* render_view_host) const; - - // Forwards the message to the RenderViewHost, which is the original one, - // not any interstitial that may be showing. + // Forwards the message to the RenderViewHost, which is the original one. void OnJavaScriptMessageBoxClosed(IPC::Message* reply_msg, bool success, const std::wstring& prompt); - // Are we showing the POST interstitial page? - // - // NOTE: the POST interstitial does NOT result in a separate RenderViewHost. - bool showing_repost_interstitial() const { - return showing_repost_interstitial_; - } - void set_showing_repost_interstitial(bool showing) { - showing_repost_interstitial_ = showing; + // Sets the passed passed interstitial as the currently showing interstitial. + // |interstitial_page| should be non NULL (use the remove_interstitial_page + // method to unset the interstitial) and no interstitial page should be set + // when there is already a non NULL interstitial page set. + void set_interstitial_page(InterstitialPage* interstitial_page) { + DCHECK(!interstitial_page_ && interstitial_page); + interstitial_page_ = interstitial_page; } - // Returns whether we are currently showing an interstitial page. - bool showing_interstitial_page() const { - return (renderer_state_ == INTERSTITIAL) || - (renderer_state_ == LEAVING_INTERSTITIAL); + // Unsets the currently showing interstitial. + void remove_interstitial_page() { + DCHECK(interstitial_page_); + interstitial_page_ = NULL; } - // Accessors to the the interstitial page. + // Returns the currently showing interstitial, NULL if no interstitial is + // showing. InterstitialPage* interstitial_page() const { return interstitial_page_; } @@ -178,49 +156,6 @@ class RenderViewHostManager { private: friend class TestWebContents; - // RenderViewHost states. These states represent whether a cross-site - // request is pending (in the new process model) and whether an interstitial - // page is being shown. These are public to give easy access to unit tests. - enum RendererState { - // NORMAL: just showing a page normally. - // render_view_host_ is showing a page. - // pending_render_view_host_ is NULL. - // original_render_view_host_ is NULL. - // interstitial_render_view_host_ is NULL. - NORMAL = 0, - - // PENDING: creating a new RenderViewHost for a cross-site navigation. - // Never used when --process-per-tab is specified. - // render_view_host_ is showing a page. - // pending_render_view_host_ is loading a page in the background. - // original_render_view_host_ is NULL. - // interstitial_render_view_host_ is NULL. - PENDING, - - // ENTERING_INTERSTITIAL: an interstitial RenderViewHost has been created. - // and will be shown as soon as it calls DidNavigate. - // render_view_host_ is showing a page. - // pending_render_view_host_ is either NULL or suspended in the background. - // original_render_view_host_ is NULL. - // interstitial_render_view_host_ is loading in the background. - ENTERING_INTERSTITIAL, - - // INTERSTITIAL: Showing an interstitial page. - // render_view_host_ is showing the interstitial. - // pending_render_view_host_ is either NULL or suspended in the background. - // original_render_view_host_ is the hidden original page. - // interstitial_render_view_host_ is NULL. - INTERSTITIAL, - - // LEAVING_INTERSTITIAL: interstitial is still showing, but we are - // navigating to a new page that will replace it. - // render_view_host_ is showing the interstitial. - // pending_render_view_host_ is either NULL or loading a page. - // original_render_view_host_ is hidden and possibly loading a page. - // interstitial_render_view_host_ is NULL. - LEAVING_INTERSTITIAL - }; - // Returns whether this tab should transition to a new renderer for // cross-site URLs. Enabled unless we see the --process-per-tab command line // switch. Can be overridden in unit tests. @@ -251,22 +186,14 @@ class RenderViewHostManager { void SwapToRenderView(RenderViewHost** new_render_view_host, bool destroy_after); - RenderViewHost* UpdateRendererStateNavigate(const NavigationEntry& entry); - - // Prevent the interstitial page from proceeding after we start navigating - // away from it. If |stop_request| is true, abort the pending requests - // immediately, because we are navigating away. - void DisableInterstitialProceed(bool stop_request); + // Helper method to terminate the pending RenderViewHost. + void CancelPendingRenderView(); - // Cleans up after an interstitial page is hidden. - void InterstitialPageGone(); + RenderViewHost* UpdateRendererStateNavigate(const NavigationEntry& entry); // Our delegate, not owned by us. Guaranteed non-NULL. Delegate* delegate_; - // See RendererState definition above. - RendererState renderer_state_; - // Allows tests to create their own render view host types. RenderViewHostFactory* render_view_factory_; @@ -275,31 +202,19 @@ class RenderViewHostManager { RenderViewHostDelegate* render_view_delegate_; // Our RenderView host. This object is responsible for all communication with - // a child RenderView instance. Note that this can be the page render view - // host or the interstitial RenderViewHost if the RendererState is - // INTERSTITIAL or LEAVING_INTERSTITIAL. + // a child RenderView instance. RenderViewHost* render_view_host_; - // This var holds the original RenderViewHost when the interstitial page is - // showing (the RendererState is INTERSTITIAL or LEAVING_INTERSTITIAL). It - // is NULL otherwise. - RenderViewHost* original_render_view_host_; - - // The RenderViewHost of the interstitial page. This is non NULL when the - // the RendererState is ENTERING_INTERSTITIAL. - RenderViewHost* interstitial_render_view_host_; - // A RenderViewHost used to load a cross-site page. This remains hidden - // during the PENDING RendererState until it calls DidNavigate. It can also - // exist if an interstitial page is shown. + // while a cross-site request is pending until it calls DidNavigate. RenderViewHost* pending_render_view_host_; // The intersitial page currently shown if any, not own by this class // (the InterstitialPage is self-owned, it deletes itself when hidden). InterstitialPage* interstitial_page_; - // See comment above showing_repost_interstitial(). - bool showing_repost_interstitial_; + // Whether a cross-site request is pending (in the new process model). + bool cross_navigation_pending_; DISALLOW_COPY_AND_ASSIGN(RenderViewHostManager); }; diff --git a/chrome/browser/render_widget_host_view_win.h b/chrome/browser/render_widget_host_view_win.h index 064c7a0..be3c6b5 100644 --- a/chrome/browser/render_widget_host_view_win.h +++ b/chrome/browser/render_widget_host_view_win.h @@ -37,7 +37,7 @@ static const wchar_t* const kRenderWidgetHostHWNDClass = L"Chrome_RenderWidgetHostHWND"; /////////////////////////////////////////////////////////////////////////////// -// RenderWidgetHostHWND +// RenderWidgetHostViewWin // // An object representing the "View" of a rendered web page. This object is // responsible for displaying the content of the web page, receiving windows @@ -274,7 +274,7 @@ class RenderWidgetHostViewWin : // until that bug is fixed. bool renderer_accessible_; - DISALLOW_EVIL_CONSTRUCTORS(RenderWidgetHostViewWin); + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewWin); }; #endif // #ifndef CHROME_BROWSER_RENDER_WIDGET_HOST_VIEW_WIN_H_ diff --git a/chrome/browser/resource_dispatcher_host.cc b/chrome/browser/resource_dispatcher_host.cc index 1d1aa18..042f178 100644 --- a/chrome/browser/resource_dispatcher_host.cc +++ b/chrome/browser/resource_dispatcher_host.cc @@ -25,8 +25,8 @@ #include "chrome/browser/render_view_host_delegate.h" #include "chrome/browser/resource_request_details.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" -#include "chrome/browser/tab_contents.h" #include "chrome/browser/tab_util.h" +#include "chrome/browser/web_contents.h" #include "chrome/common/notification_source.h" #include "chrome/common/notification_types.h" #include "chrome/common/render_messages.h" @@ -2319,14 +2319,14 @@ class NotificationTask : public Task { void Run() { // Find the tab associated with this request. - TabContents* tab_contents = - tab_util::GetTabContentsByID(render_process_host_id_, tab_contents_id_); + WebContents* web_contents = + tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_); - if (tab_contents) { + if (web_contents) { // Issue the notification. NotificationService::current()-> Notify(type_, - Source<NavigationController>(tab_contents->controller()), + Source<NavigationController>(web_contents->controller()), Details<ResourceRequestDetails>(details_.get())); } } diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index 6c6433a..265e4c7 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc @@ -43,7 +43,7 @@ static const wchar_t* const kSbDiagnosticHtml = SafeBrowsingBlockingPage::SafeBrowsingBlockingPage( SafeBrowsingService* sb_service, const SafeBrowsingService::BlockingPageParam& param) - : InterstitialPage(tab_util::GetTabContentsByID( + : InterstitialPage(tab_util::GetWebContentsByID( param.render_process_host_id, param.render_view_id), param.resource_type == ResourceType::MAIN_FRAME, param.url), @@ -55,6 +55,12 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage( proceed_(false), did_notify_(false), is_main_frame_(param.resource_type == ResourceType::MAIN_FRAME) { + if (!is_main_frame_) { + navigation_entry_index_to_remove_ = + tab()->controller()->GetLastCommittedEntryIndex(); + } else { + navigation_entry_index_to_remove_ = -1; + } } SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() { @@ -138,8 +144,6 @@ std::string SafeBrowsingBlockingPage::GetHTMLContents() { } void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) { - DCHECK(tab()->type() == TAB_CONTENTS_WEB); - WebContents* web = tab()->AsWebContents(); if (command == "2") { // User pressed "Learn more". GURL url; @@ -150,7 +154,7 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) { } else { NOTREACHED(); } - web->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK); + tab()->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK); return; } if (command == "3") { @@ -161,8 +165,8 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) { GURL report_url = safe_browsing_util::GeneratePhishingReportUrl(kSbReportPhishingUrl, url().spec()); - web->HideInterstitialPage(false, false); - web->OpenURL(report_url, GURL(), CURRENT_TAB, PageTransition::LINK); + Hide(); + tab()->OpenURL(report_url, GURL(), CURRENT_TAB, PageTransition::LINK); return; } if (command == "4") { @@ -173,33 +177,26 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) { GURL diagnostic_url(diagnostic); diagnostic_url = google_util::AppendGoogleLocaleParam(diagnostic_url); DCHECK(result_ == SafeBrowsingService::URL_MALWARE); - web->HideInterstitialPage(false, false); - web->OpenURL(diagnostic_url, GURL(), CURRENT_TAB, PageTransition::LINK); + tab()->OpenURL(diagnostic_url, GURL(), CURRENT_TAB, PageTransition::LINK); return; } proceed_ = command == "1"; - if (proceed_) { - if (is_main_frame_) - web->HideInterstitialPage(true, true); - else - web->HideInterstitialPage(false, false); - } else { - if (is_main_frame_) { - DontProceed(); - } else { - NavigationController* controller = web->controller(); - controller->RemoveEntryAtIndex(controller->GetLastCommittedEntryIndex(), - NewTabUIURL()); - } - } + if (proceed_) + Proceed(); + else + DontProceed(); + NotifyDone(); } -void SafeBrowsingBlockingPage::InterstitialClosed() { - NotifyDone(); - InterstitialPage::InterstitialClosed(); +void SafeBrowsingBlockingPage::DontProceed() { + if (navigation_entry_index_to_remove_ != -1) { + tab()->controller()->RemoveEntryAtIndex(navigation_entry_index_to_remove_, + NewTabUIURL()); + } + InterstitialPage::DontProceed(); // We are now deleted. } diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h index 056d9ae..b0fa2ea 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h @@ -38,7 +38,7 @@ class SafeBrowsingBlockingPage : public InterstitialPage { // InterstitialPage method: virtual std::string GetHTMLContents(); - virtual void InterstitialClosed(); + virtual void DontProceed(); protected: // InterstitialPage method: @@ -77,6 +77,10 @@ class SafeBrowsingBlockingPage : public InterstitialPage { // Whether the flagged resource is the main page (or a sub-resource is false). bool is_main_frame_; + // The index of a navigation entry that should be removed when DontProceed() + // is invoked, -1 if not entry should be removed. + int navigation_entry_index_to_remove_; + DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage); }; diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 837c11f..5a7a617 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc @@ -17,6 +17,7 @@ #include "chrome/browser/safe_browsing/protocol_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h" #include "chrome/browser/safe_browsing/safe_browsing_database.h" +#include "chrome/browser/tab_util.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" @@ -281,6 +282,20 @@ void SafeBrowsingService::DisplayBlockingPage(const GURL& url, // Invoked on the UI thread. void SafeBrowsingService::DoDisplayBlockingPage( const BlockingPageParam& param) { + // The tab might have been closed. + if (!tab_util::GetWebContentsByID(param.render_process_host_id, + param.render_view_id)) { + // The tab is gone and we did not have a chance at showing the interstitial. + // Just act as "Don't Proceed" was chosen. + base::Thread* io_thread = g_browser_process->io_thread(); + if (!io_thread) + return; + BlockingPageParam response_param = param; + response_param.proceed = false; + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::OnBlockingPageDone, response_param)); + return; + } SafeBrowsingBlockingPage* blocking_page = new SafeBrowsingBlockingPage(this, param); blocking_page->Show(); diff --git a/chrome/browser/ssl_blocking_page.cc b/chrome/browser/ssl_blocking_page.cc index c92ddc2..88b402c 100644 --- a/chrome/browser/ssl_blocking_page.cc +++ b/chrome/browser/ssl_blocking_page.cc @@ -12,7 +12,6 @@ #include "chrome/browser/navigation_controller.h" #include "chrome/browser/navigation_entry.h" #include "chrome/browser/ssl_error_info.h" -#include "chrome/browser/tab_contents.h" #include "chrome/browser/web_contents.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/l10n_util.h" @@ -26,7 +25,7 @@ // No error happening loading a sub-resource triggers an interstitial so far. SSLBlockingPage::SSLBlockingPage(SSLManager::CertError* error, Delegate* delegate) - : InterstitialPage(error->GetTabContents(), true, error->request_url()), + : InterstitialPage(error->GetWebContents(), true, error->request_url()), error_(error), delegate_(delegate), delegate_has_been_notified_(false) { @@ -95,15 +94,11 @@ void SSLBlockingPage::CommandReceived(const std::string& command) { } void SSLBlockingPage::Proceed() { - // We hide the interstitial page first (by calling Proceed()) as allowing the - // certificate will resume the request and we want the WebContents back to - // showing the non interstitial page (otherwise the request completion - // messages may confuse the WebContents if it is still showing the - // interstitial page). - InterstitialPage::Proceed(); - // Accepting the certificate resumes the loading of the page. NotifyAllowCertificate(); + + // This call hides and deletes the interstitial. + InterstitialPage::Proceed(); } void SSLBlockingPage::DontProceed() { diff --git a/chrome/browser/ssl_manager.cc b/chrome/browser/ssl_manager.cc index f76774a0..2a875d4 100644 --- a/chrome/browser/ssl_manager.cc +++ b/chrome/browser/ssl_manager.cc @@ -259,10 +259,10 @@ SSLManager::ErrorHandler::ErrorHandler(ResourceDispatcherHost* rdh, void SSLManager::ErrorHandler::Dispatch() { DCHECK(MessageLoop::current() == ui_loop_); - TabContents* tab_contents = - tab_util::GetTabContentsByID(render_process_host_id_, tab_contents_id_); + TabContents* web_contents = + tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_); - if (!tab_contents) { + if (!web_contents) { // We arrived on the UI thread, but the tab we're looking for is no longer // here. OnDispatchFailed(); @@ -270,12 +270,12 @@ void SSLManager::ErrorHandler::Dispatch() { } // Hand ourselves off to the SSLManager. - manager_ = tab_contents->controller()->ssl_manager(); + manager_ = web_contents->controller()->ssl_manager(); OnDispatched(); } -TabContents* SSLManager::ErrorHandler::GetTabContents() { - return tab_util::GetTabContentsByID(render_process_host_id_, +WebContents* SSLManager::ErrorHandler::GetWebContents() { + return tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_); } @@ -570,11 +570,6 @@ void SSLManager::DidCommitProvisionalLoad( changed = true; } - if (details->is_interstitial) { - // We should not have any errors when loading an interstitial page, and as - // a consequence no messages. - DCHECK(pending_messages_.empty()); - } ShowPendingMessages(); } @@ -615,14 +610,12 @@ void SSLManager::DidCommitProvisionalLoad( void SSLManager::DidFailProvisionalLoadWithError( ProvisionalLoadDetails* details) { DCHECK(details); - // A transitional page is not expected to fail. - DCHECK(!details->interstitial_page()); // Ignore in-page navigations. if (details->in_page_navigation()) return; - if (details->main_frame() && !details->interstitial_page()) + if (details->main_frame()) ClearPendingMessages(); } diff --git a/chrome/browser/ssl_manager.h b/chrome/browser/ssl_manager.h index 29c01f3..43b71c2 100644 --- a/chrome/browser/ssl_manager.h +++ b/chrome/browser/ssl_manager.h @@ -34,9 +34,9 @@ class PrefService; class ResourceRedirectDetails; class ResourceRequestDetails; class SSLErrorInfo; -class TabContents; class Task; class URLRequest; +class WebContents; // The SSLManager SSLManager controls the SSL UI elements in a TabContents. It // listens for various events that influence when these elements should or @@ -75,9 +75,9 @@ class SSLManager : public NotificationObserver { // Call on the UI thread. SSLManager* manager() const { return manager_; }; - // Returns the TabContents this object is associated with. Should be + // Returns the WebContents this object is associated with. Should be // called from the UI thread. - TabContents* GetTabContents(); + WebContents* GetWebContents(); // Cancels the associated URLRequest. // This method can be called from OnDispatchFailed and OnDispatched. diff --git a/chrome/browser/ssl_policy.cc b/chrome/browser/ssl_policy.cc index 8ed4486..f89cdcd 100644 --- a/chrome/browser/ssl_policy.cc +++ b/chrome/browser/ssl_policy.cc @@ -61,9 +61,7 @@ ShowUnsafeContentTask::~ShowUnsafeContentTask() { void ShowUnsafeContentTask::Run() { error_handler_->manager()->AllowShowInsecureContentForURL(main_frame_url_); // Reload the page. - DCHECK(error_handler_->GetTabContents()->type() == TAB_CONTENTS_WEB); - WebContents* tab = error_handler_->GetTabContents()->AsWebContents(); - tab->controller()->Reload(true); + error_handler_->GetWebContents()->controller()->Reload(true); } static void ShowErrorPage(SSLPolicy* policy, SSLManager::CertError* error) { @@ -91,8 +89,7 @@ static void ShowErrorPage(SSLPolicy* policy, SSLManager::CertError* error) { std::string html_text(jstemplate_builder::GetTemplateHtml(html, &strings, "template_root")); - DCHECK(error->GetTabContents()->type() == TAB_CONTENTS_WEB); - WebContents* tab = error->GetTabContents()->AsWebContents(); + WebContents* tab = error->GetWebContents(); int cert_id = CertStore::GetSharedInstance()->StoreCert( error->ssl_info().cert, tab->render_view_host()->process()->host_id()); std::string security_info = @@ -481,7 +478,6 @@ void SSLPolicy::OnFatalCertError(const GURL& main_frame_url, return; } error->CancelRequest(); - DCHECK(error->GetTabContents()->type() == TAB_CONTENTS_WEB); ShowErrorPage(this, error); // No need to degrade our security indicators because we didn't continue. } diff --git a/chrome/browser/tab_util.cc b/chrome/browser/tab_util.cc index 815abfe..863b38d4 100644 --- a/chrome/browser/tab_util.cc +++ b/chrome/browser/tab_util.cc @@ -27,7 +27,7 @@ bool tab_util::GetTabContentsID(URLRequest* request, return true; } -TabContents* tab_util::GetTabContentsByID(int render_process_id, +WebContents* tab_util::GetWebContentsByID(int render_process_id, int render_view_id) { RenderViewHost* render_view_host = RenderViewHost::FromID(render_process_id, render_view_id); diff --git a/chrome/browser/tab_util.h b/chrome/browser/tab_util.h index 9b576e5..6aa96f3 100644 --- a/chrome/browser/tab_util.h +++ b/chrome/browser/tab_util.h @@ -5,8 +5,8 @@ #ifndef CHROME_BROWSER_TAB_UTIL_H__ #define CHROME_BROWSER_TAB_UTIL_H__ -class TabContents; class URLRequest; +class WebContents; namespace tab_util { @@ -15,10 +15,10 @@ namespace tab_util { bool GetTabContentsID(URLRequest* request, int* render_process_host_id, int* routing_id); -// Helper to find the TabContents that originated the given request. Can be +// Helper to find the WebContents that originated the given request. Can be // NULL if the tab has been closed or some other error occurs. // Should only be called from the UI thread, since it accesses TabContent. -TabContents* GetTabContentsByID(int render_process_host_id, int routing_id); +WebContents* GetWebContentsByID(int render_process_host_id, int routing_id); } // namespace tab_util diff --git a/chrome/browser/task_manager_resource_providers.cc b/chrome/browser/task_manager_resource_providers.cc index ceca70c..6e62e7a 100644 --- a/chrome/browser/task_manager_resource_providers.cc +++ b/chrome/browser/task_manager_resource_providers.cc @@ -85,12 +85,9 @@ TaskManager::Resource* TaskManagerWebContentsResourceProvider::GetResource( int render_process_host_id, int routing_id) { - TabContents* tab_contents = - tab_util::GetTabContentsByID(render_process_host_id, routing_id); - if (!tab_contents) // Not one of our resource. - return NULL; - WebContents* web_contents = tab_contents->AsWebContents(); - if (!web_contents) + WebContents* web_contents = + tab_util::GetWebContentsByID(render_process_host_id, routing_id); + if (!web_contents) // Not one of our resource. return NULL; if (!web_contents->process()->process().handle()) { diff --git a/chrome/browser/views/dom_view.cc b/chrome/browser/views/dom_view.cc index ed8fa95..f6c92a8 100644 --- a/chrome/browser/views/dom_view.cc +++ b/chrome/browser/views/dom_view.cc @@ -27,8 +27,8 @@ bool DOMView::Init(Profile* profile, SiteInstance* instance) { // a DOMUIHostFactory rather than TabContentsFactory, because DOMView's // should only be associated with instances of DOMUIHost. TabContentsType type = TabContents::TypeForURL(&contents_); - TabContents* tab_contents = TabContents::CreateWithType(type, profile, - instance); + TabContents* tab_contents = TabContents::CreateWithType(type, profile, + instance); host_ = tab_contents->AsDOMUIHost(); DCHECK(host_); diff --git a/chrome/browser/views/external_protocol_dialog.cc b/chrome/browser/views/external_protocol_dialog.cc index aa9308d..f4aafcb 100644 --- a/chrome/browser/views/external_protocol_dialog.cc +++ b/chrome/browser/views/external_protocol_dialog.cc @@ -10,7 +10,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/external_protocol_handler.h" #include "chrome/browser/tab_util.h" -#include "chrome/browser/tab_contents.h" +#include "chrome/browser/web_contents.h" #include "chrome/common/l10n_util.h" #include "chrome/views/message_box_view.h" #include "chrome/views/window.h" @@ -31,10 +31,10 @@ const int kMessageWidth = 400; void ExternalProtocolDialog::RunExternalProtocolDialog( const GURL& url, const std::wstring& command, int render_process_host_id, int routing_id) { - TabContents* tab_contents = tab_util::GetTabContentsByID( + WebContents* web_contents = tab_util::GetWebContentsByID( render_process_host_id, routing_id); ExternalProtocolDialog* handler = - new ExternalProtocolDialog(tab_contents, url, command); + new ExternalProtocolDialog(web_contents, url, command); } ExternalProtocolDialog::~ExternalProtocolDialog() { diff --git a/chrome/browser/views/external_protocol_dialog.h b/chrome/browser/views/external_protocol_dialog.h index db23116..720ebae 100644 --- a/chrome/browser/views/external_protocol_dialog.h +++ b/chrome/browser/views/external_protocol_dialog.h @@ -17,7 +17,7 @@ class ExternalProtocolDialog : public views::DialogDelegate { // |url| - The url of the request. // |command| - the command that ShellExecute will run. // |render_process_host_id| and |routing_id| are used by - // tab_util::GetTabContentsByID to aquire the tab contents associated with + // tab_util::GetWebContentsByID to aquire the tab contents associated with // this dialog. // NOTE: There is a race between the Time of Check and the Time Of Use for // the command line. Since the caller (web page) does not have access diff --git a/chrome/browser/web_contents.cc b/chrome/browser/web_contents.cc index bf60d58f..d4c661f 100644 --- a/chrome/browser/web_contents.cc +++ b/chrome/browser/web_contents.cc @@ -19,7 +19,6 @@ #include "chrome/browser/download/download_request_manager.h" #include "chrome/browser/find_notification_details.h" #include "chrome/browser/google_util.h" -#include "chrome/browser/interstitial_page.h" #include "chrome/browser/js_before_unload_handler.h" #include "chrome/browser/jsmessage_box_handler.h" #include "chrome/browser/load_from_memory_cache_details.h" @@ -590,7 +589,7 @@ void WebContents::SavePage(const std::wstring& main_file, void WebContents::PrintPreview() { // We can't print interstitial page for now. - if (render_manager_.showing_interstitial_page()) + if (showing_interstitial_page()) return; // If we have a find bar it needs to hide as well. @@ -602,7 +601,7 @@ void WebContents::PrintPreview() { bool WebContents::PrintNow() { // We can't print interstitial page for now. - if (render_manager_.showing_interstitial_page()) + if (showing_interstitial_page()) return false; // If we have a find bar it needs to hide as well. @@ -648,11 +647,7 @@ Profile* WebContents::GetProfile() const { } void WebContents::RendererReady(RenderViewHost* rvh) { - if (render_manager_.showing_interstitial_page() && - rvh == render_view_host()) { - // We are showing an interstitial page, don't notify the world. - return; - } else if (rvh != render_view_host()) { + if (rvh != render_view_host()) { // Don't notify the world, since this came from a renderer in the // background. return; @@ -667,10 +662,7 @@ void WebContents::RendererGone(RenderViewHost* rvh) { if (!printing_.OnRendererGone(rvh)) return; if (rvh != render_view_host()) { - // The pending or interstitial page's RenderViewHost is gone. If we are - // showing an interstitial, this may mean that the original RenderViewHost - // is gone. If so, we will call RendererGone again if we try to swap that - // RenderViewHost back in, in SwapToRenderView. + // The pending page's RenderViewHost is gone. return; } @@ -691,27 +683,12 @@ void WebContents::DidNavigate(RenderViewHost* rvh, if (PageTransition::IsMainFrame(params.transition)) render_manager_.DidNavigateMainFrame(rvh); - // In the case of interstitial, we don't mess with the navigation entries. - // TODO(brettw) this seems like a bug. What happens if the page goes and - // does something on its own (or something that just got delayed), then - // we won't have a navigation entry for that stuff when the interstitial - // is hidden. - if (render_manager_.showing_interstitial_page()) - return; - // We can't do anything about navigations when we're inactive. if (!controller() || !is_active()) return; - // Update the site of the SiteInstance if it doesn't have one yet, unless we - // are showing an interstitial page. If we are, we should wait until the - // real page commits. - // - // TODO(brettw) the old code only checked for INTERSTIAL, this new code also - // checks for LEAVING_INTERSTITIAL mode in the manager. Is this difference - // important? - if (!GetSiteInstance()->has_site() && - !render_manager_.showing_interstitial_page()) + // Update the site of the SiteInstance if it doesn't have one yet. + if (!GetSiteInstance()->has_site()) GetSiteInstance()->SetSite(params.url); // Need to update MIME type here because it's referred to in @@ -726,10 +703,7 @@ void WebContents::DidNavigate(RenderViewHost* rvh, contents_mime_type_ = params.contents_mime_type; NavigationController::LoadCommittedDetails details; - if (!controller()->RendererDidNavigate( - params, - render_manager_.IsRenderViewInterstitial(rvh), - &details)) + if (!controller()->RendererDidNavigate(params, &details)) return; // No navigation happened. // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen @@ -746,18 +720,7 @@ void WebContents::DidNavigate(RenderViewHost* rvh, void WebContents::UpdateState(RenderViewHost* rvh, int32 page_id, const std::string& state) { - if (rvh != render_view_host() || - render_manager_.showing_interstitial_page()) { - // This UpdateState is either: - // - targeted not at the current RenderViewHost. This could be that we are - // showing the interstitial page and getting an update for the regular page, - // or that we are navigating from the interstitial and getting an update - // for it. - // - targeted at the interstitial page. Ignore it as we don't want to update - // the fake navigation entry. - return; - } - + DCHECK(rvh == render_view_host()); if (!controller()) return; @@ -788,19 +751,10 @@ void WebContents::UpdateTitle(RenderViewHost* rvh, // getting useful data. SetNotWaitingForResponse(); - NavigationEntry* entry; - if (render_manager_.showing_interstitial_page() && - (rvh == render_view_host())) { - // We are showing an interstitial page in a different RenderViewHost, so - // the page_id is not sufficient to find the entry from the controller. - // (both RenderViewHost page_ids overlap). We know it is the active entry, - // so just use that. - entry = controller()->GetActiveEntry(); - } else { - entry = controller()->GetEntryWithPageID(type(), GetSiteInstance(), - page_id); - } - + DCHECK(rvh == render_view_host()); + NavigationEntry* entry = controller()->GetEntryWithPageID(type(), + GetSiteInstance(), + page_id); if (!entry || !UpdateTitleForEntry(entry, title)) return; @@ -882,11 +836,9 @@ void WebContents::DidStartProvisionalLoadForFrame( RenderViewHost* render_view_host, bool is_main_frame, const GURL& url) { - ProvisionalLoadDetails details( - is_main_frame, - render_manager_.IsRenderViewInterstitial(render_view_host), - controller()->IsURLInPageNavigation(url), - url, std::string(), false); + ProvisionalLoadDetails details(is_main_frame, + controller()->IsURLInPageNavigation(url), + url, std::string(), false); NotificationService::current()-> Notify(NOTIFY_FRAME_PROVISIONAL_LOAD_START, Source<NavigationController>(controller()), @@ -931,8 +883,7 @@ void WebContents::DidFailProvisionalLoadWithError( RenderViewHost* render_view_host, bool is_main_frame, int error_code, - const GURL& url, - bool showing_repost_interstitial) { + const GURL& url) { if (!controller()) return; @@ -955,7 +906,7 @@ void WebContents::DidFailProvisionalLoadWithError( // in the previous tab type. If you navigate somewhere that activates the // tab with the interstitial again, you'll see a flash before the new load // commits of the interstitial page. - if (render_manager_.showing_interstitial_page()) { + if (showing_interstitial_page()) { LOG(WARNING) << "Discarding message during interstitial."; return; } @@ -972,15 +923,11 @@ void WebContents::DidFailProvisionalLoadWithError( } // Send out a notification that we failed a provisional load with an error. - ProvisionalLoadDetails details( - is_main_frame, - render_manager_.IsRenderViewInterstitial(render_view_host), - controller()->IsURLInPageNavigation(url), - url, std::string(), false); + ProvisionalLoadDetails details(is_main_frame, + controller()->IsURLInPageNavigation(url), + url, std::string(), false); details.set_error_code(error_code); - render_manager_.set_showing_repost_interstitial(showing_repost_interstitial); - NotificationService::current()-> Notify(NOTIFY_FAIL_PROVISIONAL_LOAD_WITH_ERROR, Source<NavigationController>(controller()), diff --git a/chrome/browser/web_contents.h b/chrome/browser/web_contents.h index f7ed61e..359a294 100644 --- a/chrome/browser/web_contents.h +++ b/chrome/browser/web_contents.h @@ -124,32 +124,24 @@ class WebContents : public TabContents, // Various other systems need to know about our interstitials. bool showing_interstitial_page() const { - return render_manager_.showing_interstitial_page(); - } - bool showing_repost_interstitial() const { - return render_manager_.showing_repost_interstitial(); + return render_manager_.interstitial_page() != NULL; } - // Displays the specified interstitial page. This method can be used to show - // temporary pages (such as security error pages). It can be hidden by - // calling HideInterstitialPage, in which case the original page is restored. - // |interstitial_page| is not owned by the WebContents. - void ShowInterstitialPage(InterstitialPage* interstitial_page) { - render_manager_.ShowInterstitialPage(interstitial_page); + // Sets the passed passed interstitial as the currently showing interstitial. + // |interstitial_page| should be non NULL (use the remove_interstitial_page + // method to unset the interstitial) and no interstitial page should be set + // when there is already a non NULL interstitial page set. + void set_interstitial_page(InterstitialPage* interstitial_page) { + render_manager_.set_interstitial_page(interstitial_page); } - // Reverts from the interstitial page to the original page. - // If |wait_for_navigation| is true, the interstitial page is removed when - // the original page has transitioned to the new contents. This is useful - // when you want to hide the interstitial page as you navigate to a new page. - // Hiding the interstitial page right away would show the previous displayed - // page. If |proceed| is true, the WebContents will expect the navigation - // to complete. If not, it will revert to the last shown page. - void HideInterstitialPage(bool wait_for_navigation, bool proceed) { - render_manager_.HideInterstitialPage(wait_for_navigation, proceed); + // Unsets the currently showing interstitial. + void remove_interstitial_page() { + render_manager_.remove_interstitial_page(); } - // Returns the interstitial page currently shown if any, NULL otherwise. + // Returns the currently showing interstitial, NULL if no interstitial is + // showing. InterstitialPage* interstitial_page() const { return render_manager_.interstitial_page(); } @@ -253,12 +245,10 @@ class WebContents : public TabContents, const GURL& target_url); virtual void DidLoadResourceFromMemoryCache(const GURL& url, const std::string& security_info); - virtual void DidFailProvisionalLoadWithError( - RenderViewHost* render_view_host, - bool is_main_frame, - int error_code, - const GURL& url, - bool showing_repost_interstitial); + virtual void DidFailProvisionalLoadWithError(RenderViewHost* render_view_host, + bool is_main_frame, + int error_code, + const GURL& url); virtual void UpdateFavIconURL(RenderViewHost* render_view_host, int32 page_id, const GURL& icon_url); virtual void DidDownloadImage(RenderViewHost* render_view_host, @@ -368,6 +358,9 @@ class WebContents : public TabContents, // Temporary until the view/contents separation is complete. friend class WebContentsViewWin; + // So InterstitialPage can access SetIsLoading. + friend class InterstitialPage; + // When CreateShortcut is invoked RenderViewHost::GetApplicationInfo is // invoked. CreateShortcut caches the state of the page needed to create the // shortcut in PendingInstall. When OnDidGetApplicationInfo is invoked, it diff --git a/chrome/browser/web_contents_unittest.cc b/chrome/browser/web_contents_unittest.cc index 4811350..8f9ed31 100644 --- a/chrome/browser/web_contents_unittest.cc +++ b/chrome/browser/web_contents_unittest.cc @@ -16,11 +16,29 @@ #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" +static void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params, + int page_id, + const GURL& url) { + params->page_id = page_id; + params->url = url; + params->referrer = GURL::EmptyGURL(); + params->transition = PageTransition::TYPED; + params->redirects = std::vector<GURL>(); + params->should_update_history = false; + params->searchable_form_url = GURL::EmptyGURL(); + params->searchable_form_element_name = std::wstring(); + params->searchable_form_encoding = std::string(); + params->password_form = PasswordForm(); + params->security_info = std::string(); + params->gesture = NavigationGestureUser; + params->is_post = false; +} + // Subclass the RenderViewHost's view so that we can call Show(), etc., // without having side-effects. class TestRenderWidgetHostView : public RenderWidgetHostView { public: - TestRenderWidgetHostView() {} + TestRenderWidgetHostView() : is_showing_(false) {} virtual RenderWidgetHost* GetRenderWidgetHost() const { return NULL; } virtual void DidBecomeSelected() {} @@ -35,8 +53,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void Blur() {} virtual bool HasFocus() { return true; } virtual void AdvanceFocus(bool reverse) {} - virtual void Show() {} - virtual void Hide() {} + virtual void Show() { is_showing_ = true; } + virtual void Hide() { is_showing_ = false; } virtual gfx::Rect GetViewBounds() const { return gfx::Rect(); } virtual void UpdateCursor(const WebCursor& cursor) {} virtual void UpdateCursorIfOverSelf() {} @@ -50,6 +68,11 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void Destroy() {} virtual void PrepareToDestroy() {} virtual void SetTooltipText(const std::wstring& tooltip_text) {} + + bool is_showing() const { return is_showing_; } + + private: + bool is_showing_; }; // Subclass RenderViewHost so that it does not create a process. @@ -184,33 +207,10 @@ class TestWebContents : public WebContents { return static_cast<TestRenderViewHost*>( render_manager_.pending_render_view_host_); } - TestRenderViewHost* interstitial_rvh() { - return static_cast<TestRenderViewHost*>( - render_manager_.interstitial_render_view_host_); - } - TestRenderViewHost* original_rvh() { - return static_cast<TestRenderViewHost*>( - render_manager_.original_render_view_host_); - } - - // State accessors. - bool state_is_normal() const { - return render_manager_.renderer_state_ == RenderViewHostManager::NORMAL; - } - bool state_is_pending() const { - return render_manager_.renderer_state_ == RenderViewHostManager::PENDING; - } - bool state_is_entering_interstitial() const { - return render_manager_.renderer_state_ == - RenderViewHostManager::ENTERING_INTERSTITIAL; - } - bool state_is_interstitial() const { - return render_manager_.renderer_state_ == - RenderViewHostManager::INTERSTITIAL; - } - bool state_is_leaving_interstitial() const { - return render_manager_.renderer_state_ == - RenderViewHostManager::LEAVING_INTERSTITIAL; + + // State accessor. + bool cross_navigation_pending() { + return render_manager_.cross_navigation_pending_; } // Ensure we create TestRenderViewHosts that don't spawn processes. @@ -250,28 +250,84 @@ class TestWebContents : public WebContents { bool transition_cross_site; }; -class WebContentsTest : public testing::Test { +class TestInterstitialPage : public InterstitialPage { public: - WebContentsTest() : contents(NULL) {} + enum InterstitialState { + UNDECIDED = 0, // No decision taken yet. + OKED, // Proceed was called. + CANCELED // DontProceed was called. + }; + + TestInterstitialPage(WebContents* tab, + bool new_navigation, + const GURL& url, + InterstitialState* state, + bool* deleted) + : InterstitialPage(tab, new_navigation, url), + state_(state), + deleted_(deleted), + command_received_count_(0) { + *state_ = UNDECIDED; + *deleted_ = false; + } + + virtual ~TestInterstitialPage() { + *deleted_ = true; + } + + virtual void DontProceed() { + *state_ = CANCELED; + InterstitialPage::DontProceed(); + } + virtual void Proceed() { + *state_ = OKED; + InterstitialPage::Proceed(); + } + + int command_received_count() const { + return command_received_count_; + } - void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params, - int pageID, - const GURL& url) { - params->page_id = pageID; - params->url = url; - params->referrer = GURL::EmptyGURL(); - params->transition = PageTransition::TYPED; - params->redirects = std::vector<GURL>(); - params->should_update_history = false; - params->searchable_form_url = GURL::EmptyGURL(); - params->searchable_form_element_name = std::wstring(); - params->searchable_form_encoding = std::string(); - params->password_form = PasswordForm(); - params->security_info = std::string(); - params->gesture = NavigationGestureUser; - params->is_post = false; + void TestDomOperationResponse(const std::string& json_string) { + DomOperationResponse(json_string, 1); } + void TestDidNavigate(int page_id, const GURL& url) { + ViewHostMsg_FrameNavigate_Params params; + InitNavigateParams(¶ms, page_id, url); + DidNavigate(render_view_host(), params); + } + + void TestRendererGone() { + RendererGone(render_view_host()); + } + + bool is_showing() const { + return static_cast<TestRenderWidgetHostView*>(render_view_host()->view())-> + is_showing(); + } + + protected: + virtual RenderViewHost* CreateRenderViewHost() { + return new TestRenderViewHost( + SiteInstance::CreateSiteInstance(tab()->profile()), + this, MSG_ROUTING_NONE, NULL); + } + + virtual void CommandReceived(const std::string& command) { + command_received_count_++; + } + + private: + InterstitialState* state_; + bool* deleted_; + int command_received_count_; +}; + +class WebContentsTest : public testing::Test { + public: + WebContentsTest() : contents(NULL) {} + // testing::Test methods: virtual void SetUp() { @@ -286,6 +342,7 @@ class WebContentsTest : public testing::Test { virtual void TearDown() { // This will delete the contents. + if (contents) contents->CloseContents(); // Make sure that we flush any messages related to WebContents destruction @@ -293,6 +350,13 @@ class WebContentsTest : public testing::Test { MessageLoop::current()->RunAllPending(); } + void Navigate(int page_id, const GURL& url) { + DCHECK(contents); + ViewHostMsg_FrameNavigate_Params params; + InitNavigateParams(¶ms, page_id, url); + contents->TestDidNavigate(contents->rvh(), params); + } + scoped_ptr<WebContentsTestingProfile> profile; TestWebContents* contents; @@ -306,9 +370,9 @@ TEST_F(WebContentsTest, UpdateTitle) { InitNavigateParams(¶ms, 0, GURL("about:blank")); NavigationController::LoadCommittedDetails details; - contents->controller()->RendererDidNavigate(params, false, &details); + contents->controller()->RendererDidNavigate(params, &details); - contents->UpdateTitle(NULL, 0, L" Lots O' Whitespace\n"); + contents->UpdateTitle(contents->rvh(), 0, L" Lots O' Whitespace\n"); EXPECT_EQ(std::wstring(L"Lots O' Whitespace"), contents->GetTitle()); } @@ -317,14 +381,12 @@ TEST_F(WebContentsTest, SimpleNavigation) { TestRenderViewHost* orig_rvh = contents->rvh(); SiteInstance* instance1 = contents->GetSiteInstance(); EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); EXPECT_FALSE(orig_rvh->is_loading); // Navigate to URL const GURL url("http://www.google.com"); contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_TRUE(orig_rvh->is_loading); EXPECT_EQ(instance1, orig_rvh->site_instance()); // Controller's pending entry will have a NULL site instance until we assign @@ -336,7 +398,7 @@ TEST_F(WebContentsTest, SimpleNavigation) { ViewHostMsg_FrameNavigate_Params params; InitNavigateParams(¶ms, 1, url); contents->TestDidNavigate(orig_rvh, params); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(orig_rvh, contents->render_view_host()); EXPECT_EQ(instance1, orig_rvh->site_instance()); // Controller's entry should now have the SiteInstance, or else we won't be @@ -345,260 +407,6 @@ TEST_F(WebContentsTest, SimpleNavigation) { contents->controller()->GetActiveEntry()->site_instance()); } -// Test navigating to a page that shows an interstitial, then hiding it -// without proceeding. -TEST_F(WebContentsTest, ShowInterstitialDontProceed) { - TestRenderViewHost* orig_rvh = contents->rvh(); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - EXPECT_FALSE(orig_rvh->is_loading); - - // Navigate to URL - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_TRUE(orig_rvh->is_loading); - - // Show interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - EXPECT_TRUE(contents->state_is_entering_interstitial()); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - EXPECT_TRUE(orig_rvh->is_loading); // Still loading in the background - EXPECT_TRUE(interstitial_rvh->is_loading); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params; - InitNavigateParams(¶ms, 1, url); - contents->TestDidNavigate(interstitial_rvh, params); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_FALSE(interstitial_rvh->is_loading); - - // Hide interstitial (don't proceed) - contents->HideInterstitialPage(false, false); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); -} - -// Test navigating to a page that shows an interstitial, then proceeding. -TEST_F(WebContentsTest, ShowInterstitialProceed) { - TestRenderViewHost* orig_rvh = contents->rvh(); - - // The RenderViewHost's SiteInstance should not yet have a site. - EXPECT_EQ(GURL(), contents->rvh()->site_instance()->site()); - - // Navigate to URL - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - - // Show interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params; - InitNavigateParams(¶ms, 1, url); - contents->TestDidNavigate(interstitial_rvh, params); - - // Ensure this DidNavigate hasn't changed the SiteInstance's site. - // Prevents regression for bug 1163298. - EXPECT_EQ(GURL(), contents->rvh()->site_instance()->site()); - - // Hide interstitial (proceed and wait) - contents->HideInterstitialPage(true, true); - EXPECT_TRUE(contents->state_is_leaving_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - - // DidNavigate from the destination page - contents->TestDidNavigate(orig_rvh, params); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // The SiteInstance's site should now be updated. - EXPECT_EQ(GURL("http://google.com"), - contents->rvh()->site_instance()->site()); - - // Since we weren't viewing a page before, we shouldn't be able to go back. - EXPECT_FALSE(contents->controller()->CanGoBack()); -} - -// Test navigating to a page that shows an interstitial, then navigating away. -TEST_F(WebContentsTest, ShowInterstitialThenNavigate) { - TestRenderViewHost* orig_rvh = contents->rvh(); - - // Navigate to URL - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - - // Show interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params; - InitNavigateParams(¶ms, 1, url); - contents->TestDidNavigate(interstitial_rvh, params); - - // While interstitial showing, navigate to a new URL. - const GURL url2("http://www.yahoo.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_leaving_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_TRUE(orig_rvh->is_loading); - EXPECT_FALSE(interstitial_rvh->is_loading); - - // DidNavigate from the new URL. In the old process model, we'll still have - // the same RenderViewHost. - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 2, url2); - contents->TestDidNavigate(orig_rvh, params2); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_FALSE(orig_rvh->is_loading); -} - -// Ensures that an interstitial cannot be cancelled if a notification for a -// navigation from an IFrame from the previous page is received while the -// interstitial is being shown (bug #1182394). -TEST_F(WebContentsTest, ShowInterstitialIFrameNavigate) { - TestRenderViewHost* orig_rvh = contents->rvh(); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - EXPECT_FALSE(orig_rvh->is_loading); - - // Navigate to URL. - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_TRUE(orig_rvh->is_loading); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - // Show interstitial (in real world would probably be triggered by a resource - // in the page). - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - EXPECT_TRUE(contents->state_is_entering_interstitial()); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - EXPECT_TRUE(interstitial_rvh->is_loading); - - // DidNavigate from an IFrame in the initial page. - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 1, GURL("http://www.iframe.com")); - params2.transition = PageTransition::AUTO_SUBFRAME; - contents->TestDidNavigate(orig_rvh, params2); - - // Now we get the DidNavigate from the interstitial. - ViewHostMsg_FrameNavigate_Params params3; - InitNavigateParams(¶ms3, 1, url); - contents->TestDidNavigate(interstitial_rvh, params3); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_FALSE(interstitial_rvh->is_loading); -} - -// Test navigating to an interstitial page from a normal page. Also test -// visiting the interstitial-inducing URL twice (bug 1079784), and test -// that going back shows the first page and not the interstitial. -TEST_F(WebContentsTest, VisitInterstitialURLTwice) { - TestRenderViewHost* orig_rvh = contents->rvh(); - - // Navigate to URL - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - // Now navigate to an interstitial-inducing URL - const GURL url2("https://www.google.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - EXPECT_TRUE(contents->state_is_entering_interstitial()); - int interstitial_delete_counter = 0; - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - interstitial_rvh->set_delete_counter(&interstitial_delete_counter); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 2, url2); - contents->TestDidNavigate(interstitial_rvh, params2); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - - // While interstitial showing, navigate to the same URL. - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_leaving_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - - // Interstitial shown a second time in a different RenderViewHost. - interstitial = new InterstitialPage(contents, true, interstitial_url); - interstitial->Show(); - EXPECT_TRUE(contents->state_is_entering_interstitial()); - // We expect the original interstitial has been deleted. - EXPECT_EQ(interstitial_delete_counter, 1); - TestRenderViewHost* interstitial_rvh2 = contents->interstitial_rvh(); - interstitial_rvh2->set_delete_counter(&interstitial_delete_counter); - - // DidNavigate from the interstitial. - ViewHostMsg_FrameNavigate_Params params3; - InitNavigateParams(¶ms3, 3, url2); - contents->TestDidNavigate(interstitial_rvh2, params3); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh2, contents->render_view_host()); - - // Proceed. In the old process model, we'll still have the same - // RenderViewHost. - contents->HideInterstitialPage(true, true); - EXPECT_TRUE(contents->state_is_leaving_interstitial()); - ViewHostMsg_FrameNavigate_Params params4; - InitNavigateParams(¶ms4, 3, url2); - contents->TestDidNavigate(orig_rvh, params4); - EXPECT_TRUE(contents->state_is_normal()); - // We expect the second interstitial has been deleted. - EXPECT_EQ(interstitial_delete_counter, 2); - - // Now go back. Should take us back to the original page. - contents->controller()->GoBack(); - EXPECT_TRUE(contents->state_is_normal()); - - // DidNavigate from going back. - contents->TestDidNavigate(orig_rvh, params1); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); -} - // Test that navigating across a site boundary creates a new RenderViewHost // with a new SiteInstance. Going back should do the same. TEST_F(WebContentsTest, CrossSiteBoundaries) { @@ -615,15 +423,13 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) { InitNavigateParams(¶ms1, 1, url); contents->TestDidNavigate(orig_rvh, params1); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); // Navigate to new site const GURL url2("http://www.yahoo.com"); contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_pending()); + EXPECT_TRUE(contents->cross_navigation_pending()); TestRenderViewHost* pending_rvh = contents->pending_rvh(); int pending_rvh_delete_count = 0; pending_rvh->set_delete_counter(&pending_rvh_delete_count); @@ -634,23 +440,21 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) { contents->TestDidNavigate(pending_rvh, params2); SiteInstance* instance2 = contents->GetSiteInstance(); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(pending_rvh, contents->render_view_host()); EXPECT_NE(instance1, instance2); EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); EXPECT_EQ(orig_rvh_delete_count, 1); // Going back should switch SiteInstances again. The first SiteInstance is // stored in the NavigationEntry, so it should be the same as at the start. contents->controller()->GoBack(); TestRenderViewHost* goback_rvh = contents->pending_rvh(); - EXPECT_TRUE(contents->state_is_pending()); + EXPECT_TRUE(contents->cross_navigation_pending()); // DidNavigate from the back action contents->TestDidNavigate(goback_rvh, params1); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(goback_rvh, contents->render_view_host()); EXPECT_EQ(pending_rvh_delete_count, 1); EXPECT_EQ(instance1, contents->GetSiteInstance()); @@ -672,10 +476,8 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) { InitNavigateParams(¶ms1, 1, url); contents->TestDidNavigate(orig_rvh, params1); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); // Crash the renderer. orig_rvh->is_created = false; @@ -684,10 +486,8 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) { const GURL url2("http://www.yahoo.com"); contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); TestRenderViewHost* new_rvh = contents->rvh(); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); EXPECT_NE(orig_rvh, new_rvh); EXPECT_EQ(orig_rvh_delete_count, 1); @@ -697,330 +497,10 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) { contents->TestDidNavigate(new_rvh, params2); SiteInstance* instance2 = contents->GetSiteInstance(); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(new_rvh, contents->render_view_host()); EXPECT_NE(instance1, instance2); EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); -} - -// Test state transitions when showing an interstitial in the new process -// model, and then choosing DontProceed. -TEST_F(WebContentsTest, CrossSiteInterstitialDontProceed) { - contents->transition_cross_site = true; - TestRenderViewHost* orig_rvh = contents->rvh(); - SiteInstance* instance1 = contents->GetSiteInstance(); - - // Navigate to URL. First URL should use first RenderViewHost. - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - - // Navigate to new site - const GURL url2("https://www.google.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_pending()); - TestRenderViewHost* pending_rvh = contents->pending_rvh(); - - // Show an interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - EXPECT_TRUE(contents->state_is_entering_interstitial()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_EQ(pending_rvh, contents->pending_rvh()); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 2, url2); - contents->TestDidNavigate(interstitial_rvh, params2); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_EQ(pending_rvh, contents->pending_rvh()); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // Hide interstitial (don't proceed) - contents->HideInterstitialPage(false, false); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); -} - -// Test state transitions when showing an interstitial in the new process -// model, and then choosing Proceed. -TEST_F(WebContentsTest, CrossSiteInterstitialProceed) { - contents->transition_cross_site = true; - int orig_rvh_delete_count = 0; - TestRenderViewHost* orig_rvh = contents->rvh(); - orig_rvh->set_delete_counter(&orig_rvh_delete_count); - SiteInstance* instance1 = contents->GetSiteInstance(); - - // Navigate to URL. First URL should use first RenderViewHost. - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - // Navigate to new site - const GURL url2("https://www.google.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - TestRenderViewHost* pending_rvh = contents->pending_rvh(); - int pending_rvh_delete_count = 0; - pending_rvh->set_delete_counter(&pending_rvh_delete_count); - - // Show an interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 1, url2); - contents->TestDidNavigate(interstitial_rvh, params2); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_EQ(pending_rvh, contents->pending_rvh()); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // Hide interstitial (proceed and wait) - contents->HideInterstitialPage(true, true); - EXPECT_TRUE(contents->state_is_leaving_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_EQ(pending_rvh, contents->pending_rvh()); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // DidNavigate from the destination page should transition to new renderer - ViewHostMsg_FrameNavigate_Params params3; - InitNavigateParams(¶ms3, 2, url2); - contents->TestDidNavigate(pending_rvh, params3); - SiteInstance* instance2 = contents->GetSiteInstance(); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(pending_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - EXPECT_NE(instance1, instance2); - EXPECT_EQ(orig_rvh_delete_count, 1); // The original should be gone. - - // Since we were viewing a page before, we should be able to go back. - EXPECT_TRUE(contents->controller()->CanGoBack()); - - // Going back should switch SiteInstances again. The first SiteInstance is - // stored in the NavigationEntry, so it should be the same as at the start. - contents->controller()->GoBack(); - TestRenderViewHost* goback_rvh = contents->pending_rvh(); - EXPECT_TRUE(contents->state_is_pending()); - - // DidNavigate from the back action - contents->TestDidNavigate(goback_rvh, params1); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(goback_rvh, contents->render_view_host()); - EXPECT_EQ(instance1, contents->GetSiteInstance()); - EXPECT_EQ(pending_rvh_delete_count, 1); // The second page's rvh should die. -} - -// Tests that we can transition away from an interstitial page. -TEST_F(WebContentsTest, CrossSiteInterstitialThenNavigate) { - contents->transition_cross_site = true; - int orig_rvh_delete_count = 0; - TestRenderViewHost* orig_rvh = contents->rvh(); - orig_rvh->set_delete_counter(&orig_rvh_delete_count); - - // Navigate to URL. First URL should use first RenderViewHost. - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - // Show an interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - false, - interstitial_url); - interstitial->Show(); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 1, url); - contents->TestDidNavigate(interstitial_rvh, params2); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // Navigate to a new page. - const GURL url2("http://www.yahoo.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - - TestRenderViewHost* new_rvh = contents->pending_rvh(); - ASSERT_TRUE(new_rvh != NULL); - // Make sure the RVH is not suspended (bug #1236441). - EXPECT_FALSE(new_rvh->IsNavigationSuspended()); - EXPECT_TRUE(contents->state_is_leaving_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - - // DidNavigate from the new page - ViewHostMsg_FrameNavigate_Params params3; - InitNavigateParams(¶ms3, 1, url2); - contents->TestDidNavigate(new_rvh, params3); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(new_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_EQ(orig_rvh_delete_count, 1); -} - -// Tests that we can transition away from an interstitial page even if the -// interstitial renderer has crashed. -TEST_F(WebContentsTest, CrossSiteInterstitialCrashThenNavigate) { - contents->transition_cross_site = true; - int orig_rvh_delete_count = 0; - TestRenderViewHost* orig_rvh = contents->rvh(); - orig_rvh->set_delete_counter(&orig_rvh_delete_count); - - // Navigate to URL. First URL should use first RenderViewHost. - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - // Navigate to new site - const GURL url2("https://www.google.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - TestRenderViewHost* pending_rvh = contents->pending_rvh(); - int pending_rvh_delete_count = 0; - pending_rvh->set_delete_counter(&pending_rvh_delete_count); - - // Show an interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 1, url2); - contents->TestDidNavigate(interstitial_rvh, params2); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_EQ(pending_rvh, contents->pending_rvh()); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // Crash the interstitial RVH - // (by making IsRenderViewLive() == false) - interstitial_rvh->is_created = false; - - // Navigate to a new page. Since interstitial RVH is dead, we should clean - // it up and go to a new PENDING state, showing the orig_rvh. - const GURL url3("http://www.yahoo.com"); - contents->controller()->LoadURL(url3, GURL(), PageTransition::TYPED); - TestRenderViewHost* new_rvh = contents->pending_rvh(); - ASSERT_TRUE(new_rvh != NULL); - EXPECT_TRUE(contents->state_is_pending()); - EXPECT_EQ(orig_rvh, contents->render_view_host()); - EXPECT_EQ(pending_rvh_delete_count, 1); - EXPECT_NE(interstitial_rvh, new_rvh); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // DidNavigate from the new page - ViewHostMsg_FrameNavigate_Params params3; - InitNavigateParams(¶ms3, 1, url3); - contents->TestDidNavigate(new_rvh, params3); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(new_rvh, contents->render_view_host()); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_EQ(orig_rvh_delete_count, 1); -} - -// Tests that we can transition away from an interstitial page even if both the -// original and interstitial renderers have crashed. -TEST_F(WebContentsTest, CrossSiteInterstitialCrashesThenNavigate) { - contents->transition_cross_site = true; - int orig_rvh_delete_count = 0; - TestRenderViewHost* orig_rvh = contents->rvh(); - orig_rvh->set_delete_counter(&orig_rvh_delete_count); - - // Navigate to URL. First URL should use first RenderViewHost. - const GURL url("http://www.google.com"); - contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); - ViewHostMsg_FrameNavigate_Params params1; - InitNavigateParams(¶ms1, 1, url); - contents->TestDidNavigate(orig_rvh, params1); - - // Navigate to new site - const GURL url2("https://www.google.com"); - contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - TestRenderViewHost* pending_rvh = contents->pending_rvh(); - int pending_rvh_delete_count = 0; - pending_rvh->set_delete_counter(&pending_rvh_delete_count); - - // Show an interstitial - const GURL interstitial_url("http://interstitial"); - InterstitialPage* interstitial = new InterstitialPage(contents, - true, - interstitial_url); - interstitial->Show(); - TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh(); - - // DidNavigate from the interstitial - ViewHostMsg_FrameNavigate_Params params2; - InitNavigateParams(¶ms2, 1, url2); - contents->TestDidNavigate(interstitial_rvh, params2); - EXPECT_TRUE(contents->state_is_interstitial()); - EXPECT_EQ(interstitial_rvh, contents->render_view_host()); - EXPECT_EQ(orig_rvh, contents->original_rvh()); - EXPECT_EQ(pending_rvh, contents->pending_rvh()); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // Crash both the original and interstitial RVHs - // (by making IsRenderViewLive() == false) - orig_rvh->is_created = false; - interstitial_rvh->is_created = false; - - // Navigate to a new page. Since both the interstitial and original RVHs are - // dead, we should create a new RVH, jump back to NORMAL, and navigate. - const GURL url3("http://www.yahoo.com"); - contents->controller()->LoadURL(url3, GURL(), PageTransition::TYPED); - TestRenderViewHost* new_rvh = contents->rvh(); - ASSERT_TRUE(new_rvh != NULL); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(orig_rvh_delete_count, 1); - EXPECT_EQ(pending_rvh_delete_count, 1); - EXPECT_NE(interstitial_rvh, new_rvh); - EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); - - // DidNavigate from the new page - ViewHostMsg_FrameNavigate_Params params3; - InitNavigateParams(¶ms3, 1, url3); - contents->TestDidNavigate(new_rvh, params3); - EXPECT_TRUE(contents->state_is_normal()); - EXPECT_EQ(new_rvh, contents->render_view_host()); } // Test that opening a new tab in the same SiteInstance and then navigating @@ -1062,7 +542,7 @@ TEST_F(WebContentsTest, NavigateTwoTabsCrossSite) { contents2->controller()->LoadURL(url2b, GURL(), PageTransition::TYPED); TestRenderViewHost* pending_rvh_b = contents2->pending_rvh(); EXPECT_TRUE(pending_rvh_b != NULL); - EXPECT_TRUE(contents2->state_is_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 @@ -1100,16 +580,16 @@ TEST_F(WebContentsTest, CrossSiteComparesAgainstCurrentPage) { contents2->SetupController(profile.get()); const GURL url2("http://www.yahoo.com"); contents2->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); - // The first RVH in contents2 isn't live yet, so we shortcut the PENDING - // state and go straight to NORMAL. + // The first RVH in contents2 isn't live yet, so we shortcut the cross site + // pending. TestRenderViewHost* rvh2 = contents2->rvh(); - EXPECT_TRUE(contents2->state_is_normal()); + EXPECT_FALSE(contents2->cross_navigation_pending()); ViewHostMsg_FrameNavigate_Params params2; InitNavigateParams(¶ms2, 2, url2); contents2->TestDidNavigate(rvh2, params2); SiteInstance* instance2 = contents2->GetSiteInstance(); EXPECT_NE(instance1, instance2); - EXPECT_TRUE(contents2->state_is_normal()); + 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. @@ -1118,13 +598,13 @@ TEST_F(WebContentsTest, CrossSiteComparesAgainstCurrentPage) { contents->TestDidNavigate(orig_rvh, params3); SiteInstance* instance3 = contents->GetSiteInstance(); EXPECT_EQ(instance1, instance3); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); // 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"); contents->controller()->LoadURL(url3, GURL(), PageTransition::TYPED); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); ViewHostMsg_FrameNavigate_Params params4; InitNavigateParams(¶ms4, 3, url3); contents->TestDidNavigate(orig_rvh, params4); @@ -1147,7 +627,7 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) { ViewHostMsg_FrameNavigate_Params params1; InitNavigateParams(¶ms1, 1, url); contents->TestDidNavigate(orig_rvh, params1); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(orig_rvh, contents->render_view_host()); // Navigate to new site, but simulate an onbeforeunload denial. @@ -1155,13 +635,13 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) { orig_rvh->immediate_before_unload = false; contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); orig_rvh->TestOnMsgShouldClose(false); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(orig_rvh, contents->render_view_host()); // Navigate again, but simulate an onbeforeunload approval. contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED); orig_rvh->TestOnMsgShouldClose(true); - EXPECT_TRUE(contents->state_is_pending()); + EXPECT_TRUE(contents->cross_navigation_pending()); TestRenderViewHost* pending_rvh = contents->pending_rvh(); // We won't hear DidNavigate until the onunload handler has finished running. @@ -1173,12 +653,10 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) { InitNavigateParams(¶ms2, 1, url2); contents->TestDidNavigate(pending_rvh, params2); SiteInstance* instance2 = contents->GetSiteInstance(); - EXPECT_TRUE(contents->state_is_normal()); + EXPECT_FALSE(contents->cross_navigation_pending()); EXPECT_EQ(pending_rvh, contents->render_view_host()); EXPECT_NE(instance1, instance2); EXPECT_TRUE(contents->pending_rvh() == NULL); - EXPECT_TRUE(contents->original_rvh() == NULL); - EXPECT_TRUE(contents->interstitial_rvh() == NULL); } // Test that NavigationEntries have the correct content state after going @@ -1253,3 +731,472 @@ TEST_F(WebContentsTest, WebKitPrefs) { EXPECT_EQ(true, webkit_prefs.javascript_enabled); } +//////////////////////////////////////////////////////////////////////////////// +// Interstitial Tests +//////////////////////////////////////////////////////////////////////////////// + +// Test navigating to a page (with the navigation initiated from the browser, +// as when a URL is typed in the location bar) that shows an interstitial and +// creates a new navigation entry, then hiding it without proceeding. +TEST_F(WebContentsTest, + ShowInterstitialFromBrowserWithNewNavigationDontProceed) { + // Navigate to a page. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Initiate a browser navigation that will trigger the interstitial + contents->controller()->LoadURL(GURL("http://www.evil.com"), GURL(), + PageTransition::TYPED); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url2, &state, &deleted); + interstitial->Show(); + // The interstitial should not show until its navigation has committed. + EXPECT_FALSE(interstitial->is_showing()); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + // Let's commit the interstitial navigation. + interstitial->TestDidNavigate(1, url2); + EXPECT_TRUE(interstitial->is_showing()); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url2); + + // Now don't proceed. + interstitial->DontProceed(); + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); +} + +// Test navigating to a page (with the navigation initiated from the renderer, +// as when clicking on a link in the page) that shows an interstitial and +// creates a new navigation entry, then hiding it without proceeding. +TEST_F(WebContentsTest, + ShowInterstitiaFromRendererlWithNewNavigationDontProceed) { + // Navigate to a page. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Show an interstitial (no pending entry, the interstitial would have been + // triggered by clicking on a link). + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url2, &state, &deleted); + interstitial->Show(); + // The interstitial should not show until its navigation has committed. + EXPECT_FALSE(interstitial->is_showing()); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + // Let's commit the interstitial navigation. + interstitial->TestDidNavigate(1, url2); + EXPECT_TRUE(interstitial->is_showing()); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url2); + + // Now don't proceed. + interstitial->DontProceed(); + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); +} + +// Test navigating to a page that shows an interstitial without creating a new +// navigation entry (this happens when the interstitial is triggered by a +// sub-resource in the page), then hiding it without proceeding. +TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationDontProceed) { + // Navigate to a page. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, false, url2, &state, &deleted); + interstitial->Show(); + // The interstitial should not show until its navigation has committed. + EXPECT_FALSE(interstitial->is_showing()); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + // Let's commit the interstitial navigation. + interstitial->TestDidNavigate(1, url2); + EXPECT_TRUE(interstitial->is_showing()); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + // The URL specified to the interstitial should have been ignored. + EXPECT_TRUE(entry->url() == url1); + + // Now don't proceed. + interstitial->DontProceed(); + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); +} + +// Test navigating to a page (with the navigation initiated from the browser, +// as when a URL is typed in the location bar) that shows an interstitial and +// creates a new navigation entry, then proceeding. +TEST_F(WebContentsTest, ShowInterstitialFromBrowserNewNavigationProceed) { + // Navigate to a page. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Initiate a browser navigation that will trigger the interstitial + contents->controller()->LoadURL(GURL("http://www.evil.com"), GURL(), + PageTransition::TYPED); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url2, &state, &deleted); + interstitial->Show(); + // The interstitial should not show until its navigation has committed. + EXPECT_FALSE(interstitial->is_showing()); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + // Let's commit the interstitial navigation. + interstitial->TestDidNavigate(1, url2); + EXPECT_TRUE(interstitial->is_showing()); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url2); + + // Then proceed. + interstitial->Proceed(); + // The interstitial should show until the new navigation commits. + ASSERT_FALSE(deleted); + EXPECT_EQ(TestInterstitialPage::OKED, state); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + + // Simulate the navigation to the page, that's when the interstitial gets + // hidden. + GURL url3("http://www.thepage.com"); + Navigate(2, url3); + + EXPECT_TRUE(deleted); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url3); + + EXPECT_EQ(2, contents->controller()->GetEntryCount()); +} + +// Test navigating to a page (with the navigation initiated from the renderer, +// as when clicking on a link in the page) that shows an interstitial and +// creates a new navigation entry, then proceeding. +TEST_F(WebContentsTest, ShowInterstitialFromRendererNewNavigationProceed) { + // Navigate to a page. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url2, &state, &deleted); + interstitial->Show(); + // The interstitial should not show until its navigation has committed. + EXPECT_FALSE(interstitial->is_showing()); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + // Let's commit the interstitial navigation. + interstitial->TestDidNavigate(1, url2); + EXPECT_TRUE(interstitial->is_showing()); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url2); + + // Then proceed. + interstitial->Proceed(); + // The interstitial should show until the new navigation commits. + ASSERT_FALSE(deleted); + EXPECT_EQ(TestInterstitialPage::OKED, state); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + + // Simulate the navigation to the page, that's when the interstitial gets + // hidden. + GURL url3("http://www.thepage.com"); + Navigate(2, url3); + + EXPECT_TRUE(deleted); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url3); + + EXPECT_EQ(2, contents->controller()->GetEntryCount()); +} + +// Test navigating to a page that shows an interstitial without creating a new +// navigation entry (this happens when the interstitial is triggered by a +// sub-resource in the page), then proceeding. +TEST_F(WebContentsTest, ShowInterstitialNoNewNavigationProceed) { + // Navigate to a page so we have a navigation entry in the controller. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, false, url2, &state, &deleted); + interstitial->Show(); + // The interstitial should not show until its navigation has committed. + EXPECT_FALSE(interstitial->is_showing()); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + // Let's commit the interstitial navigation. + interstitial->TestDidNavigate(1, url2); + EXPECT_TRUE(interstitial->is_showing()); + EXPECT_TRUE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == interstitial); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + // The URL specified to the interstitial should have been ignored. + EXPECT_TRUE(entry->url() == url1); + + // Then proceed. + interstitial->Proceed(); + // Since this is not a new navigation, the previous page is dismissed right + // away and shows the original page. + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::OKED, state); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == url1); + + EXPECT_EQ(1, contents->controller()->GetEntryCount()); +} + +// Test navigating to a page that shows an interstitial, then navigating away. +TEST_F(WebContentsTest, ShowInterstitialThenNavigate) { + // Show interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url, &state, &deleted); + interstitial->Show(); + interstitial->TestDidNavigate(1, url); + + // While interstitial showing, navigate to a new URL. + const GURL url2("http://www.yahoo.com"); + Navigate(1, url2); + + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); +} + +// Test navigating to a page that shows an interstitial, then close the tab. +TEST_F(WebContentsTest, ShowInterstitialThenCloseTab) { + // Show interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url, &state, &deleted); + interstitial->Show(); + interstitial->TestDidNavigate(1, url); + + // Now close the tab. + contents->CloseContents(); + contents = NULL; // So we don't detroy it again on TearDown. + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); +} + +// Test that after Proceed is called and an interstitial is still shown, no more +// commands get executed. +TEST_F(WebContentsTest, ShowInterstitialProceedMultipleCommands) { + // Navigate to a page so we have a navigation entry in the controller. + GURL url1("http://www.google.com"); + Navigate(1, url1); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url2("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url2, &state, &deleted); + interstitial->Show(); + interstitial->TestDidNavigate(1, url2); + + // Run a command. + EXPECT_EQ(0, interstitial->command_received_count()); + interstitial->TestDomOperationResponse("toto"); + EXPECT_EQ(1, interstitial->command_received_count()); + + // Then proceed. + interstitial->Proceed(); + ASSERT_FALSE(deleted); + + // While the navigation to the new page is pending, send other commands, they + // should be ignored. + interstitial->TestDomOperationResponse("hello"); + interstitial->TestDomOperationResponse("hi"); + EXPECT_EQ(1, interstitial->command_received_count()); +} + +// Test showing an interstitial while another interstitial is already showing. +TEST_F(WebContentsTest, ShowInterstitialOnInterstitial) { + // Navigate to a page so we have a navigation entry in the controller. + GURL start_url("http://www.google.com"); + Navigate(1, start_url); + EXPECT_EQ(1, contents->controller()->GetEntryCount()); + + // Show an interstitial. + TestInterstitialPage::InterstitialState state1 = + TestInterstitialPage::UNDECIDED; + bool deleted1 = false; + GURL url1("http://interstitial1"); + TestInterstitialPage* interstitial1 = + new TestInterstitialPage(contents, true, url1, &state1, &deleted1); + interstitial1->Show(); + interstitial1->TestDidNavigate(1, url1); + + // Now show another interstitial. + TestInterstitialPage::InterstitialState state2 = + TestInterstitialPage::UNDECIDED; + bool deleted2 = false; + GURL url2("http://interstitial2"); + TestInterstitialPage* interstitial2 = + new TestInterstitialPage(contents, true, url2, &state2, &deleted2); + interstitial2->Show(); + interstitial2->TestDidNavigate(1, url2); + + // Showing interstitial2 should have caused interstitial1 to go away. + EXPECT_TRUE(deleted1); + EXPECT_EQ(TestInterstitialPage::CANCELED, state1); + + // Let's make sure interstitial2 is working as intended. + ASSERT_FALSE(deleted2); + EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); + interstitial2->Proceed(); + GURL landing_url("http://www.thepage.com"); + Navigate(2, landing_url); + + EXPECT_TRUE(deleted2); + EXPECT_FALSE(contents->showing_interstitial_page()); + EXPECT_TRUE(contents->interstitial_page() == NULL); + NavigationEntry* entry = contents->controller()->GetActiveEntry(); + ASSERT_TRUE(entry != NULL); + EXPECT_TRUE(entry->url() == landing_url); + EXPECT_EQ(2, contents->controller()->GetEntryCount()); +} + +// Test that navigating away from an interstitial while it's loading cause it +// not to show. +TEST_F(WebContentsTest, NavigateBeforeInterstitialShows) { + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL interstitial_url("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, interstitial_url, + &state, &deleted); + interstitial->Show(); + + // Let's simulate a navigation initiated from the browser before the + // interstitial finishes loading. + const GURL url("http://www.google.com"); + contents->controller()->LoadURL(url, GURL(), PageTransition::TYPED); + ASSERT_FALSE(deleted); + EXPECT_FALSE(interstitial->is_showing()); + + // Now let's make the interstitial navigation commit. + interstitial->TestDidNavigate(1, interstitial_url); + + // After it loaded the interstitial should be gone. + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); +} + +// Test showing an interstitial and have its renderer crash. +TEST_F(WebContentsTest, InterstitialCrasher) { + // Show an interstitial. + TestInterstitialPage::InterstitialState state = + TestInterstitialPage::UNDECIDED; + bool deleted = false; + GURL url("http://interstitial"); + TestInterstitialPage* interstitial = + new TestInterstitialPage(contents, true, url, &state, &deleted); + interstitial->Show(); + // Simulate a renderer crash before the interstitial is shown. + interstitial->TestRendererGone(); + // The interstitial should have been dismissed. + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); + + // Now try again but this time crash the intersitial after it was shown. + interstitial = + new TestInterstitialPage(contents, true, url, &state, &deleted); + interstitial->Show(); + interstitial->TestDidNavigate(1, url); + // Simulate a renderer crash. + interstitial->TestRendererGone(); + // The interstitial should have been dismissed. + EXPECT_TRUE(deleted); + EXPECT_EQ(TestInterstitialPage::CANCELED, state); +} diff --git a/chrome/browser/web_contents_view_win.cc b/chrome/browser/web_contents_view_win.cc index e97f6ac..dda346c 100644 --- a/chrome/browser/web_contents_view_win.cc +++ b/chrome/browser/web_contents_view_win.cc @@ -10,6 +10,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_request_manager.h" +#include "chrome/browser/interstitial_page.h" #include "chrome/browser/render_view_context_menu.h" #include "chrome/browser/render_view_context_menu_controller.h" #include "chrome/browser/render_view_host.h" @@ -595,6 +596,8 @@ void WebContentsViewWin::WasShown() { } void WebContentsViewWin::WasSized(const gfx::Size& size) { + if (web_contents_->interstitial_page()) + web_contents_->interstitial_page()->SetSize(size); if (web_contents_->render_widget_host_view()) web_contents_->render_widget_host_view()->SetSize(size); if (find_bar_.get()) |