summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-17 19:57:24 +0000
committerjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-17 19:57:24 +0000
commit7cef64b495701e8ff17b2fbb6e632aa34eee450f (patch)
tree8af439034838b28edd0223010a1f6aad4b2f61ce /chrome/browser
parenta16d22388edff186095e37fecd5537beae88c7c9 (diff)
downloadchromium_src-7cef64b495701e8ff17b2fbb6e632aa34eee450f.zip
chromium_src-7cef64b495701e8ff17b2fbb6e632aa34eee450f.tar.gz
chromium_src-7cef64b495701e8ff17b2fbb6e632aa34eee450f.tar.bz2
Reverting 7149.
Review URL: http://codereview.chromium.org/15004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7153 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/automation/automation_provider.cc10
-rw-r--r--chrome/browser/browser.cc7
-rw-r--r--chrome/browser/download/download_file.cc6
-rw-r--r--chrome/browser/download/download_manager.cc4
-rw-r--r--chrome/browser/download/download_request_manager.cc6
-rw-r--r--chrome/browser/download/save_file_manager.cc10
-rw-r--r--chrome/browser/interstitial_page.cc229
-rw-r--r--chrome/browser/interstitial_page.h111
-rw-r--r--chrome/browser/login_prompt.cc10
-rw-r--r--chrome/browser/navigation_controller.cc13
-rw-r--r--chrome/browser/navigation_controller.h8
-rw-r--r--chrome/browser/navigation_controller_unittest.cc34
-rw-r--r--chrome/browser/provisional_load_details.cc2
-rw-r--r--chrome/browser/provisional_load_details.h12
-rw-r--r--chrome/browser/render_view_host_manager.cc551
-rw-r--r--chrome/browser/render_view_host_manager.h139
-rw-r--r--chrome/browser/render_widget_host_view_win.h4
-rw-r--r--chrome/browser/resource_dispatcher_host.cc10
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.cc47
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.h6
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.cc15
-rw-r--r--chrome/browser/ssl_blocking_page.cc13
-rw-r--r--chrome/browser/ssl_manager.cc21
-rw-r--r--chrome/browser/ssl_manager.h6
-rw-r--r--chrome/browser/ssl_policy.cc8
-rw-r--r--chrome/browser/tab_util.cc2
-rw-r--r--chrome/browser/tab_util.h6
-rw-r--r--chrome/browser/task_manager_resource_providers.cc9
-rw-r--r--chrome/browser/views/dom_view.cc4
-rw-r--r--chrome/browser/views/external_protocol_dialog.cc6
-rw-r--r--chrome/browser/views/external_protocol_dialog.h2
-rw-r--r--chrome/browser/web_contents.cc93
-rw-r--r--chrome/browser/web_contents.h45
-rw-r--r--chrome/browser/web_contents_unittest.cc1261
-rw-r--r--chrome/browser/web_contents_view_win.cc3
35 files changed, 1606 insertions, 1107 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 3a36b52..2f2b6b5 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(WebContents* tab,
+ AutomationInterstitialPage(TabContents* 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);
- interstitial->Show();
+ web_contents->ShowInterstitialPage(interstitial);
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->interstitial_page()) {
- web_contents->interstitial_page()->DontProceed();
+ if (web_contents) {
+ web_contents->HideInterstitialPage(false, false);
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->AsWebContents());
+ InterstitialPage::GetInterstitialPage(tab_contents);
if (ssl_blocking_page) {
if (proceed) {
AddNavigationStatusListener(tab,
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 862398d..87b3e9e 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -558,11 +558,8 @@ 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->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.
+ if (web_contents && web_contents->showing_interstitial_page()) {
+ // Pressing back on an interstitial page means "don't proceed".
web_contents->interstitial_page()->DontProceed();
return;
}
diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc
index 2a5e612..f921661 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) {
- WebContents* contents = tab_util::GetWebContentsByID(render_process_id,
+ TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
render_view_id);
- if (contents) {
+ if (contents && contents->type() == TAB_CONTENTS_WEB) {
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 adf62d3..5328807 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);
- WebContents* contents = tab_util::GetWebContentsByID(
+ TabContents* contents = tab_util::GetTabContentsByID(
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::GetWebContentsByID(info.render_process_id, info.render_view_id);
+ tab_util::GetTabContentsByID(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 ac4cdb5..6869d6e 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_);
- WebContents* originating_tab =
- tab_util::GetWebContentsByID(render_process_host_id, render_view_id);
+ TabContents* originating_tab =
+ tab_util::GetTabContentsByID(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 631b55d..940e878 100644
--- a/chrome/browser/download/save_file_manager.cc
+++ b/chrome/browser/download/save_file_manager.cc
@@ -215,10 +215,14 @@ 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) {
- WebContents* contents = tab_util::GetWebContentsByID(render_process_id,
+ TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
render_view_id);
- if (contents)
- return contents->save_package();
+ 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();
+ }
return NULL;
}
diff --git a/chrome/browser/interstitial_page.cc b/chrome/browser/interstitial_page.cc
index 6fee67f..5cbc37e 100644
--- a/chrome/browser/interstitial_page.cc
+++ b/chrome/browser/interstitial_page.cc
@@ -5,237 +5,98 @@
#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/render_widget_host_view_win.h"
+#include "chrome/browser/tab_contents.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(WebContents* tab,
- bool new_navigation,
+InterstitialPage::InterstitialPage(TabContents* tab,
+ bool create_navigation_entry,
const GURL& url)
: tab_(tab),
url_(url),
- action_taken_(false),
- enabled_(true),
- new_navigation_(new_navigation),
- render_view_host_(NULL),
- should_revert_tab_title_(false) {
+ delegate_has_been_notified_(false),
+ create_navigation_entry_(create_navigation_entry) {
InitInterstitialPageMap();
- // 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());
+
+ // 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_));
}
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() {
- // If an interstitial is already showing, close it before showing the new one.
- if (tab_->interstitial_page())
- tab_->interstitial_page()->DontProceed();
+ DCHECK(tab_->type() == TAB_CONTENTS_WEB);
+ WebContents* tab = tab_->AsWebContents();
- // 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;
+ 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);
- 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()));
-}
+ // Give sub-classes a chance to set some states on the navigation entry.
+ UpdateEntry(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_->controller()->AddTransientEntry(entry);
}
- delete this;
+
+ tab->ShowInterstitialPage(this);
}
void InterstitialPage::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- 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!
- }
+ DCHECK(type == NOTIFY_DOM_OPERATION_RESPONSE);
+ std::string json = Details<DomOperationNotificationDetails>(details)->json();
+ CommandReceived(json);
}
-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::InterstitialClosed() {
+ delete this;
+}
void InterstitialPage::Proceed() {
- 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!
- }
+ DCHECK(tab_->type() == TAB_CONTENTS_WEB);
+ tab_->AsWebContents()->HideInterstitialPage(true, true);
}
void InterstitialPage::DontProceed() {
- DCHECK(!action_taken_);
- Disable();
- action_taken_ = true;
-
- if (new_navigation_) {
+ if (create_navigation_entry_) {
// 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_)
@@ -244,10 +105,10 @@ void InterstitialPage::InitInterstitialPageMap() {
// static
InterstitialPage* InterstitialPage::GetInterstitialPage(
- WebContents* web_contents) {
+ TabContents* tab_contents) {
InitInterstitialPageMap();
InterstitialPageMap::const_iterator iter =
- tab_to_interstitial_page_->find(web_contents);
+ tab_to_interstitial_page_->find(tab_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 ab8967f..ce17818 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 WebContents;
+class TabContents;
// 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 containing
+// page. (Navigating to a page served over bad HTTPS or a page contining
// 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 WebContents;
// through a navigation, the WebContents closing them or the tab containing them
// being closed.
-class InterstitialPage : public NotificationObserver,
- public RenderViewHostDelegate {
+class InterstitialPage : public NotificationObserver {
public:
- // 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
+ // 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
// added to the navigation controller (so the interstitial page appears as a
- // 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);
+ // new navigation entry).
+ InterstitialPage(TabContents* tab,
+ bool create_navigation_entry,
+ const GURL& url);
virtual ~InterstitialPage();
// Shows the interstitial page in the tab.
- virtual void Show();
+ void Show();
- // Hides the interstitial page. Warning: this deletes the InterstitialPage.
- void Hide();
+ // Invoked by the tab showing the interstitial to notify that the interstitial
+ // page was closed.
+ virtual void InterstitialClosed();
// Retrieves the InterstitialPage if any associated with the specified
// |tab_contents| (used by ui tests).
- static InterstitialPage* GetInterstitialPage(WebContents* web_contents);
+ static InterstitialPage* GetInterstitialPage(TabContents* tab_contents);
// Sub-classes should return the HTML that should be displayed in the page.
virtual std::string GetHTMLContents() { return std::string(); }
@@ -57,34 +57,7 @@ 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) { }
@@ -95,61 +68,47 @@ class InterstitialPage : public NotificationObserver,
// |create_navigation_entry| set to true.
virtual void UpdateEntry(NavigationEntry* entry) { }
- WebContents* tab() const { return tab_; }
- const GURL& url() const { return url_; }
- RenderViewHost* render_view_host() const { return render_view_host_; }
+ // 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();
- // Creates and shows the RenderViewHost containing the interstitial content.
- // Overriden in unit tests.
- virtual RenderViewHost* CreateRenderViewHost();
+ TabContents* tab() const { return tab_; }
+ const GURL& url() const { return url_; }
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();
- // 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();
+ // A flag to indicate if we've notified |delegate_| of the user's decision.
+ bool delegate_has_been_notified_;
// The tab in which we are displayed.
- WebContents* tab_;
+ TabContents* tab_;
// The URL that is shown when the interstitial is showing.
GURL url_;
- // 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_;
+ // Whether a transient navigation entry should be created when the page is
+ // shown.
+ bool create_navigation_entry_;
- // The original title of the tab that should be reverted to when the
- // interstitial is hidden.
- std::wstring original_tab_title_;
+ // Notification magic.
+ NotificationRegistrar notification_registrar_;
// We keep a map of the various blocking pages shown as the UI tests need to
// be able to retrieve them.
- typedef std::map<WebContents*,InterstitialPage*> InterstitialPageMap;
+ typedef std::map<TabContents*,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 db9d775..1e95b0c 100644
--- a/chrome/browser/login_prompt.cc
+++ b/chrome/browser/login_prompt.cc
@@ -84,11 +84,11 @@ class LoginHandlerImpl : public LoginHandler,
SendNotifications();
}
- // Returns the WebContents that needs authentication.
- WebContents* GetWebContentsForLogin() {
+ // Returns the TabContents that needs authentication.
+ TabContents* GetTabContentsForLogin() {
DCHECK(MessageLoop::current() == ui_loop_);
- return tab_util::GetWebContentsByID(render_process_host_id_,
+ return tab_util::GetTabContentsByID(render_process_host_id_,
tab_contents_id_);
}
@@ -238,7 +238,7 @@ class LoginHandlerImpl : public LoginHandler,
DCHECK(MessageLoop::current() == ui_loop_);
NotificationService* service = NotificationService::current();
- WebContents* requesting_contents = GetWebContentsForLogin();
+ TabContents* requesting_contents = GetTabContentsForLogin();
if (!requesting_contents)
return;
@@ -311,7 +311,7 @@ class LoginDialogTask : public Task {
}
void Run() {
- WebContents* parent_contents = handler_->GetWebContentsForLogin();
+ TabContents* parent_contents = handler_->GetTabContentsForLogin();
if (!parent_contents) {
// The request was probably cancelled.
return;
diff --git a/chrome/browser/navigation_controller.cc b/chrome/browser/navigation_controller.cc
index 35aec38..2b3f96e 100644
--- a/chrome/browser/navigation_controller.cc
+++ b/chrome/browser/navigation_controller.cc
@@ -212,10 +212,13 @@ 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()) {
- // 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.
+ 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.
active_contents_->Activate();
RepostFormWarningDialog::RunRepostFormWarningDialog(this);
} else {
@@ -535,6 +538,7 @@ 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()) {
@@ -609,6 +613,7 @@ 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 ce5a20f..bd1d2aa 100644
--- a/chrome/browser/navigation_controller.h
+++ b/chrome/browser/navigation_controller.h
@@ -51,7 +51,8 @@ class NavigationController {
: entry(NULL),
is_auto(false),
is_in_page(false),
- is_main_frame(true) {
+ is_main_frame(true),
+ is_interstitial(false) {
}
// The committed entry. This will be the active entry in the controller.
@@ -84,6 +85,10 @@ 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;
@@ -320,6 +325,7 @@ 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 26fd338..08b43a0 100644
--- a/chrome/browser/navigation_controller_unittest.cc
+++ b/chrome/browser/navigation_controller_unittest.cc
@@ -794,7 +794,8 @@ TEST_F(NavigationControllerTest, NewSubframe) {
params.is_post = false;
NavigationController::LoadCommittedDetails details;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(url1, details.previous_url);
EXPECT_FALSE(details.is_auto);
@@ -828,7 +829,8 @@ TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
params.is_post = false;
NavigationController::LoadCommittedDetails details;
- EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_EQ(0, notifications.size());
}
@@ -853,7 +855,8 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
// Navigating should do nothing.
NavigationController::LoadCommittedDetails details;
- EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_FALSE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_EQ(0, notifications.size());
// There should still be only one entry.
@@ -882,7 +885,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// This should generate a new entry.
NavigationController::LoadCommittedDetails details;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(2, contents->controller()->GetEntryCount());
@@ -890,7 +894,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
const GURL url3(scheme1() + ":foo3");
params.page_id = 2;
params.url = url3;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(3, contents->controller()->GetEntryCount());
EXPECT_EQ(2, contents->controller()->GetCurrentEntryIndex());
@@ -899,7 +904,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
contents->controller()->GoBack();
params.url = url2;
params.page_id = 1;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(3, contents->controller()->GetEntryCount());
EXPECT_EQ(1, contents->controller()->GetCurrentEntryIndex());
@@ -908,7 +914,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
contents->controller()->GoBack();
params.url = url1;
params.page_id = 0;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(3, contents->controller()->GetEntryCount());
EXPECT_EQ(0, contents->controller()->GetCurrentEntryIndex());
@@ -959,7 +966,8 @@ TEST_F(NavigationControllerTest, InPage) {
// This should generate a new entry.
NavigationController::LoadCommittedDetails details;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, &details));
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(params, false,
+ &details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(2, contents->controller()->GetEntryCount());
@@ -968,7 +976,7 @@ TEST_F(NavigationControllerTest, InPage) {
contents->controller()->GoBack();
back_params.url = url1;
back_params.page_id = 0;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params,
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params, false,
&details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(2, contents->controller()->GetEntryCount());
@@ -980,7 +988,7 @@ TEST_F(NavigationControllerTest, InPage) {
contents->controller()->GoForward();
forward_params.url = url2;
forward_params.page_id = 1;
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params,
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params, false,
&details));
EXPECT_TRUE(notifications.Check1AndReset(NOTIFY_NAV_ENTRY_COMMITTED));
EXPECT_EQ(2, contents->controller()->GetEntryCount());
@@ -993,10 +1001,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,
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(back_params, false,
&details));
contents->controller()->GoForward();
- EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params,
+ EXPECT_TRUE(contents->controller()->RendererDidNavigate(forward_params, false,
&details));
EXPECT_EQ(forward_params.url,
contents->controller()->GetActiveEntry()->url());
@@ -1242,7 +1250,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
params.gesture = NavigationGestureUser;
params.is_post = false;
NavigationController::LoadCommittedDetails details;
- controller->RendererDidNavigate(params, &details);
+ controller->RendererDidNavigate(params, false, &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 ffc85a0..f7a9f89 100644
--- a/chrome/browser/provisional_load_details.cc
+++ b/chrome/browser/provisional_load_details.cc
@@ -8,11 +8,13 @@
#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 5cb9501..9f63acb 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,6 +20,7 @@
class ProvisionalLoadDetails {
public:
ProvisionalLoadDetails(bool main_frame,
+ bool interstitial_page,
bool in_page_navigation,
const GURL& url,
const std::string& security_info,
@@ -33,6 +34,8 @@ 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_; }
@@ -47,14 +50,15 @@ 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_COPY_AND_ASSIGN(ProvisionalLoadDetails);
+ DISALLOW_EVIL_CONSTRUCTORS(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 5ad576b..81e95aa 100644
--- a/chrome/browser/render_view_host_manager.cc
+++ b/chrome/browser/render_view_host_manager.cc
@@ -6,6 +6,7 @@
#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"
@@ -15,23 +16,37 @@
#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),
- cross_navigation_pending_(false),
+ renderer_state_(NORMAL),
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) {
+ interstitial_page_(NULL),
+ showing_repost_interstitial_(false) {
}
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,
@@ -48,8 +63,21 @@ void RenderViewHostManager::Init(Profile* profile,
}
void RenderViewHostManager::Shutdown() {
- if (pending_render_view_host_)
- CancelPendingRenderView();
+ 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;
+ }
// We should always have a main RenderViewHost.
render_view_host_->Shutdown();
@@ -95,17 +123,29 @@ RenderViewHost* RenderViewHostManager::Navigate(const NavigationEntry& entry) {
}
}
+ showing_repost_interstitial_ = false;
return dest_render_view_host;
}
void RenderViewHostManager::Stop() {
render_view_host_->Stop();
- // 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_) {
+ // 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) {
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();
+ }
}
}
@@ -113,10 +153,12 @@ 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 (!cross_navigation_pending_)
+ if (renderer_state_ != PENDING)
return true;
// If the tab becomes unresponsive during unload while doing a
@@ -136,31 +178,119 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
void RenderViewHostManager::DidNavigateMainFrame(
RenderViewHost* render_view_host) {
- if (!cross_navigation_pending_) {
+ if (renderer_state_ == NORMAL) {
// 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 one else should be sending us DidNavigate in this state.
+ // No such 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.
- if (!cross_navigation_pending_)
+ // 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)
return;
DCHECK(pending_render_view_host_);
@@ -168,7 +298,14 @@ 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.
- render_view_host_->ClosePage(new_render_process_host_id, new_request_id);
+ 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);
+ }
// 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
@@ -190,6 +327,50 @@ 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) {
@@ -207,21 +388,226 @@ 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.
- CancelPendingRenderView();
- cross_navigation_pending_ = false;
+ CancelRenderView(&pending_render_view_host_);
+ renderer_state_ = NORMAL;
}
}
+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) {
- render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, 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);
}
@@ -290,7 +676,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 (interstitial_page_) {
+ if (showing_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);
@@ -339,7 +725,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 {
- CancelPendingRenderView();
+ CancelRenderView(&pending_render_view_host_);
}
return success;
}
@@ -408,18 +794,37 @@ void RenderViewHostManager::SwapToRenderView(
RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate(
const NavigationEntry& entry) {
- // If we are cross-navigating, then we want to get back to normal and navigate
- // as usual.
- if (cross_navigation_pending_) {
+ // 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 (pending_render_view_host_)
- CancelPendingRenderView();
- cross_navigation_pending_ = false;
+ CancelRenderView(&pending_render_view_host_);
+ if (interstitial_render_view_host_)
+ CancelRenderView(&interstitial_render_view_host_);
+ 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.
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.
@@ -429,7 +834,8 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate(
if (new_instance != curr_instance) {
// New SiteInstance.
- DCHECK(!cross_navigation_pending_);
+ DCHECK(renderer_state_ == NORMAL ||
+ renderer_state_ == LEAVING_INTERSTITIAL);
// Create a pending RVH and navigate it.
bool success = CreatePendingRenderView(new_instance);
@@ -438,14 +844,36 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate(
// Check if our current RVH is live before we set up a transition.
if (!render_view_host_->IsRenderViewLive()) {
- if (!cross_navigation_pending_) {
+ if (renderer_state_ == NORMAL) {
// 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 non
- // cross-navigating (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 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.)
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_;
@@ -467,9 +895,12 @@ 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.
- DCHECK(!cross_navigation_pending_);
- cross_navigation_pending_ = true;
+ // 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);
// Tell the old render view to run its onbeforeunload handler, since it
// doesn't otherwise know that the cross-site request is happening. This
@@ -479,14 +910,38 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateNavigate(
return pending_render_view_host_;
}
- // Same SiteInstance can be used. Navigate render_view_host_ if we are not
- // cross navigating.
- DCHECK(!cross_navigation_pending_);
- return 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();
+ }
}
-void RenderViewHostManager::CancelPendingRenderView() {
- pending_render_view_host_->Shutdown();
- pending_render_view_host_ = NULL;
+void RenderViewHostManager::InterstitialPageGone() {
+ DCHECK(!showing_interstitial_page());
+ if (interstitial_page_) {
+ interstitial_page_->InterstitialClosed();
+ interstitial_page_ = NULL;
+ }
}
diff --git a/chrome/browser/render_view_host_manager.h b/chrome/browser/render_view_host_manager.h
index 40eabce..371c398 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 transitions of processes (and hence
-// RenderViewHosts) that can get complex.
+// it is easy to do. But we can also have interstitial pages and transitions
+// of processes (and hence RenderViewHosts) that can get very 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 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.
+ // 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.
void SetIsLoading(bool is_loading);
// Whether to close the tab or not when there is a hang during an unload
@@ -111,7 +111,8 @@ class RenderViewHostManager {
// with the navigation instead of closing the tab.
bool ShouldCloseTabOnUnresponsiveRenderer();
- // Called when a renderer's main frame navigates.
+ // Called when a renderer's main frame navigates. This handles all the logic
+ // associated with interstitial management.
void DidNavigateMainFrame(RenderViewHost* render_view_host);
// Allows the WebContents to react when a cross-site response is ready to be
@@ -127,28 +128,49 @@ class RenderViewHostManager {
// WebContents.
void ShouldClosePage(bool proceed);
- // Forwards the message to the RenderViewHost, which is the original one.
+ // 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.
void OnJavaScriptMessageBoxClosed(IPC::Message* reply_msg,
bool success,
const std::wstring& prompt);
- // 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;
+ // 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;
}
- // Unsets the currently showing interstitial.
- void remove_interstitial_page() {
- DCHECK(interstitial_page_);
- interstitial_page_ = NULL;
+ // Returns whether we are currently showing an interstitial page.
+ bool showing_interstitial_page() const {
+ return (renderer_state_ == INTERSTITIAL) ||
+ (renderer_state_ == LEAVING_INTERSTITIAL);
}
- // Returns the currently showing interstitial, NULL if no interstitial is
- // showing.
+ // Accessors to the the interstitial page.
InterstitialPage* interstitial_page() const {
return interstitial_page_;
}
@@ -156,6 +178,49 @@ 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.
@@ -186,14 +251,22 @@ class RenderViewHostManager {
void SwapToRenderView(RenderViewHost** new_render_view_host,
bool destroy_after);
- // Helper method to terminate the pending RenderViewHost.
- void CancelPendingRenderView();
-
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);
+
+ // Cleans up after an interstitial page is hidden.
+ void InterstitialPageGone();
+
// 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_;
@@ -202,19 +275,31 @@ class RenderViewHostManager {
RenderViewHostDelegate* render_view_delegate_;
// Our RenderView host. This object is responsible for all communication with
- // a child RenderView instance.
+ // 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.
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
- // while a cross-site request is pending until it calls DidNavigate.
+ // during the PENDING RendererState until it calls DidNavigate. It can also
+ // exist if an interstitial page is shown.
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_;
- // Whether a cross-site request is pending (in the new process model).
- bool cross_navigation_pending_;
+ // See comment above showing_repost_interstitial().
+ bool showing_repost_interstitial_;
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 be3c6b5..064c7a0 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";
///////////////////////////////////////////////////////////////////////////////
-// RenderWidgetHostViewWin
+// RenderWidgetHostHWND
//
// 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_COPY_AND_ASSIGN(RenderWidgetHostViewWin);
+ DISALLOW_EVIL_CONSTRUCTORS(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 042f178..1d1aa18 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.
- WebContents* web_contents =
- tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_);
+ TabContents* tab_contents =
+ tab_util::GetTabContentsByID(render_process_host_id_, tab_contents_id_);
- if (web_contents) {
+ if (tab_contents) {
// Issue the notification.
NotificationService::current()->
Notify(type_,
- Source<NavigationController>(web_contents->controller()),
+ Source<NavigationController>(tab_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 265e4c7..6c6433a 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::GetWebContentsByID(
+ : InterstitialPage(tab_util::GetTabContentsByID(
param.render_process_host_id, param.render_view_id),
param.resource_type == ResourceType::MAIN_FRAME,
param.url),
@@ -55,12 +55,6 @@ 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() {
@@ -144,6 +138,8 @@ 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;
@@ -154,7 +150,7 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) {
} else {
NOTREACHED();
}
- tab()->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK);
+ web->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK);
return;
}
if (command == "3") {
@@ -165,8 +161,8 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) {
GURL report_url =
safe_browsing_util::GeneratePhishingReportUrl(kSbReportPhishingUrl,
url().spec());
- Hide();
- tab()->OpenURL(report_url, GURL(), CURRENT_TAB, PageTransition::LINK);
+ web->HideInterstitialPage(false, false);
+ web->OpenURL(report_url, GURL(), CURRENT_TAB, PageTransition::LINK);
return;
}
if (command == "4") {
@@ -177,26 +173,33 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) {
GURL diagnostic_url(diagnostic);
diagnostic_url = google_util::AppendGoogleLocaleParam(diagnostic_url);
DCHECK(result_ == SafeBrowsingService::URL_MALWARE);
- tab()->OpenURL(diagnostic_url, GURL(), CURRENT_TAB, PageTransition::LINK);
+ web->HideInterstitialPage(false, false);
+ web->OpenURL(diagnostic_url, GURL(), CURRENT_TAB, PageTransition::LINK);
return;
}
proceed_ = command == "1";
- if (proceed_)
- Proceed();
- else
- DontProceed();
-
+ 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());
+ }
+ }
NotifyDone();
}
-void SafeBrowsingBlockingPage::DontProceed() {
- if (navigation_entry_index_to_remove_ != -1) {
- tab()->controller()->RemoveEntryAtIndex(navigation_entry_index_to_remove_,
- NewTabUIURL());
- }
- InterstitialPage::DontProceed();
+void SafeBrowsingBlockingPage::InterstitialClosed() {
+ NotifyDone();
+ InterstitialPage::InterstitialClosed();
// 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 b0fa2ea..056d9ae 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 DontProceed();
+ virtual void InterstitialClosed();
protected:
// InterstitialPage method:
@@ -77,10 +77,6 @@ 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 5a7a617..837c11f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -17,7 +17,6 @@
#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"
@@ -282,20 +281,6 @@ 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 88b402c..c92ddc2 100644
--- a/chrome/browser/ssl_blocking_page.cc
+++ b/chrome/browser/ssl_blocking_page.cc
@@ -12,6 +12,7 @@
#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"
@@ -25,7 +26,7 @@
// No error happening loading a sub-resource triggers an interstitial so far.
SSLBlockingPage::SSLBlockingPage(SSLManager::CertError* error,
Delegate* delegate)
- : InterstitialPage(error->GetWebContents(), true, error->request_url()),
+ : InterstitialPage(error->GetTabContents(), true, error->request_url()),
error_(error),
delegate_(delegate),
delegate_has_been_notified_(false) {
@@ -94,11 +95,15 @@ 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 2a875d4..f76774a0 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* web_contents =
- tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_);
+ TabContents* tab_contents =
+ tab_util::GetTabContentsByID(render_process_host_id_, tab_contents_id_);
- if (!web_contents) {
+ if (!tab_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_ = web_contents->controller()->ssl_manager();
+ manager_ = tab_contents->controller()->ssl_manager();
OnDispatched();
}
-WebContents* SSLManager::ErrorHandler::GetWebContents() {
- return tab_util::GetWebContentsByID(render_process_host_id_,
+TabContents* SSLManager::ErrorHandler::GetTabContents() {
+ return tab_util::GetTabContentsByID(render_process_host_id_,
tab_contents_id_);
}
@@ -570,6 +570,11 @@ 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();
}
@@ -610,12 +615,14 @@ 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())
+ if (details->main_frame() && !details->interstitial_page())
ClearPendingMessages();
}
diff --git a/chrome/browser/ssl_manager.h b/chrome/browser/ssl_manager.h
index 43b71c2..29c01f3 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 WebContents this object is associated with. Should be
+ // Returns the TabContents this object is associated with. Should be
// called from the UI thread.
- WebContents* GetWebContents();
+ TabContents* GetTabContents();
// 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 f89cdcd..8ed4486 100644
--- a/chrome/browser/ssl_policy.cc
+++ b/chrome/browser/ssl_policy.cc
@@ -61,7 +61,9 @@ ShowUnsafeContentTask::~ShowUnsafeContentTask() {
void ShowUnsafeContentTask::Run() {
error_handler_->manager()->AllowShowInsecureContentForURL(main_frame_url_);
// Reload the page.
- error_handler_->GetWebContents()->controller()->Reload(true);
+ DCHECK(error_handler_->GetTabContents()->type() == TAB_CONTENTS_WEB);
+ WebContents* tab = error_handler_->GetTabContents()->AsWebContents();
+ tab->controller()->Reload(true);
}
static void ShowErrorPage(SSLPolicy* policy, SSLManager::CertError* error) {
@@ -89,7 +91,8 @@ static void ShowErrorPage(SSLPolicy* policy, SSLManager::CertError* error) {
std::string html_text(jstemplate_builder::GetTemplateHtml(html, &strings,
"template_root"));
- WebContents* tab = error->GetWebContents();
+ DCHECK(error->GetTabContents()->type() == TAB_CONTENTS_WEB);
+ WebContents* tab = error->GetTabContents()->AsWebContents();
int cert_id = CertStore::GetSharedInstance()->StoreCert(
error->ssl_info().cert, tab->render_view_host()->process()->host_id());
std::string security_info =
@@ -478,6 +481,7 @@ 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 863b38d4..815abfe 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;
}
-WebContents* tab_util::GetWebContentsByID(int render_process_id,
+TabContents* tab_util::GetTabContentsByID(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 6aa96f3..9b576e5 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 WebContents that originated the given request. Can be
+// Helper to find the TabContents 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.
-WebContents* GetWebContentsByID(int render_process_host_id, int routing_id);
+TabContents* GetTabContentsByID(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 6e62e7a..ceca70c 100644
--- a/chrome/browser/task_manager_resource_providers.cc
+++ b/chrome/browser/task_manager_resource_providers.cc
@@ -85,9 +85,12 @@ TaskManager::Resource* TaskManagerWebContentsResourceProvider::GetResource(
int render_process_host_id,
int routing_id) {
- WebContents* web_contents =
- tab_util::GetWebContentsByID(render_process_host_id, routing_id);
- if (!web_contents) // Not one of our resource.
+ 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)
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 f6c92a8..ed8fa95 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 f4aafcb..aa9308d 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/web_contents.h"
+#include "chrome/browser/tab_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) {
- WebContents* web_contents = tab_util::GetWebContentsByID(
+ TabContents* tab_contents = tab_util::GetTabContentsByID(
render_process_host_id, routing_id);
ExternalProtocolDialog* handler =
- new ExternalProtocolDialog(web_contents, url, command);
+ new ExternalProtocolDialog(tab_contents, url, command);
}
ExternalProtocolDialog::~ExternalProtocolDialog() {
diff --git a/chrome/browser/views/external_protocol_dialog.h b/chrome/browser/views/external_protocol_dialog.h
index 720ebae..db23116 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::GetWebContentsByID to aquire the tab contents associated with
+ // tab_util::GetTabContentsByID 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 d4c661f..bf60d58f 100644
--- a/chrome/browser/web_contents.cc
+++ b/chrome/browser/web_contents.cc
@@ -19,6 +19,7 @@
#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"
@@ -589,7 +590,7 @@ void WebContents::SavePage(const std::wstring& main_file,
void WebContents::PrintPreview() {
// We can't print interstitial page for now.
- if (showing_interstitial_page())
+ if (render_manager_.showing_interstitial_page())
return;
// If we have a find bar it needs to hide as well.
@@ -601,7 +602,7 @@ void WebContents::PrintPreview() {
bool WebContents::PrintNow() {
// We can't print interstitial page for now.
- if (showing_interstitial_page())
+ if (render_manager_.showing_interstitial_page())
return false;
// If we have a find bar it needs to hide as well.
@@ -647,7 +648,11 @@ Profile* WebContents::GetProfile() const {
}
void WebContents::RendererReady(RenderViewHost* rvh) {
- if (rvh != render_view_host()) {
+ 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()) {
// Don't notify the world, since this came from a renderer in the
// background.
return;
@@ -662,7 +667,10 @@ void WebContents::RendererGone(RenderViewHost* rvh) {
if (!printing_.OnRendererGone(rvh))
return;
if (rvh != render_view_host()) {
- // The pending page's RenderViewHost is gone.
+ // 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.
return;
}
@@ -683,12 +691,27 @@ 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.
- if (!GetSiteInstance()->has_site())
+ // 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())
GetSiteInstance()->SetSite(params.url);
// Need to update MIME type here because it's referred to in
@@ -703,7 +726,10 @@ void WebContents::DidNavigate(RenderViewHost* rvh,
contents_mime_type_ = params.contents_mime_type;
NavigationController::LoadCommittedDetails details;
- if (!controller()->RendererDidNavigate(params, &details))
+ if (!controller()->RendererDidNavigate(
+ params,
+ render_manager_.IsRenderViewInterstitial(rvh),
+ &details))
return; // No navigation happened.
// DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
@@ -720,7 +746,18 @@ void WebContents::DidNavigate(RenderViewHost* rvh,
void WebContents::UpdateState(RenderViewHost* rvh,
int32 page_id,
const std::string& state) {
- DCHECK(rvh == render_view_host());
+ 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;
+ }
+
if (!controller())
return;
@@ -751,10 +788,19 @@ void WebContents::UpdateTitle(RenderViewHost* rvh,
// getting useful data.
SetNotWaitingForResponse();
- DCHECK(rvh == render_view_host());
- NavigationEntry* entry = controller()->GetEntryWithPageID(type(),
- GetSiteInstance(),
- page_id);
+ 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);
+ }
+
if (!entry || !UpdateTitleForEntry(entry, title))
return;
@@ -836,9 +882,11 @@ void WebContents::DidStartProvisionalLoadForFrame(
RenderViewHost* render_view_host,
bool is_main_frame,
const GURL& url) {
- ProvisionalLoadDetails details(is_main_frame,
- controller()->IsURLInPageNavigation(url),
- url, std::string(), false);
+ ProvisionalLoadDetails details(
+ is_main_frame,
+ render_manager_.IsRenderViewInterstitial(render_view_host),
+ controller()->IsURLInPageNavigation(url),
+ url, std::string(), false);
NotificationService::current()->
Notify(NOTIFY_FRAME_PROVISIONAL_LOAD_START,
Source<NavigationController>(controller()),
@@ -883,7 +931,8 @@ void WebContents::DidFailProvisionalLoadWithError(
RenderViewHost* render_view_host,
bool is_main_frame,
int error_code,
- const GURL& url) {
+ const GURL& url,
+ bool showing_repost_interstitial) {
if (!controller())
return;
@@ -906,7 +955,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 (showing_interstitial_page()) {
+ if (render_manager_.showing_interstitial_page()) {
LOG(WARNING) << "Discarding message during interstitial.";
return;
}
@@ -923,11 +972,15 @@ void WebContents::DidFailProvisionalLoadWithError(
}
// Send out a notification that we failed a provisional load with an error.
- ProvisionalLoadDetails details(is_main_frame,
- controller()->IsURLInPageNavigation(url),
- url, std::string(), false);
+ ProvisionalLoadDetails details(
+ is_main_frame,
+ render_manager_.IsRenderViewInterstitial(render_view_host),
+ 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 359a294..f7ed61e 100644
--- a/chrome/browser/web_contents.h
+++ b/chrome/browser/web_contents.h
@@ -124,24 +124,32 @@ class WebContents : public TabContents,
// Various other systems need to know about our interstitials.
bool showing_interstitial_page() const {
- return render_manager_.interstitial_page() != NULL;
+ return render_manager_.showing_interstitial_page();
+ }
+ bool showing_repost_interstitial() const {
+ return render_manager_.showing_repost_interstitial();
}
- // 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);
+ // 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);
}
- // Unsets the currently showing interstitial.
- void remove_interstitial_page() {
- render_manager_.remove_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);
}
- // Returns the currently showing interstitial, NULL if no interstitial is
- // showing.
+ // Returns the interstitial page currently shown if any, NULL otherwise.
InterstitialPage* interstitial_page() const {
return render_manager_.interstitial_page();
}
@@ -245,10 +253,12 @@ 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);
+ virtual void DidFailProvisionalLoadWithError(
+ RenderViewHost* render_view_host,
+ bool is_main_frame,
+ int error_code,
+ const GURL& url,
+ bool showing_repost_interstitial);
virtual void UpdateFavIconURL(RenderViewHost* render_view_host,
int32 page_id, const GURL& icon_url);
virtual void DidDownloadImage(RenderViewHost* render_view_host,
@@ -358,9 +368,6 @@ 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 8f9ed31..4811350 100644
--- a/chrome/browser/web_contents_unittest.cc
+++ b/chrome/browser/web_contents_unittest.cc
@@ -16,29 +16,11 @@
#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() : is_showing_(false) {}
+ TestRenderWidgetHostView() {}
virtual RenderWidgetHost* GetRenderWidgetHost() const { return NULL; }
virtual void DidBecomeSelected() {}
@@ -53,8 +35,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual void Blur() {}
virtual bool HasFocus() { return true; }
virtual void AdvanceFocus(bool reverse) {}
- virtual void Show() { is_showing_ = true; }
- virtual void Hide() { is_showing_ = false; }
+ virtual void Show() {}
+ virtual void Hide() {}
virtual gfx::Rect GetViewBounds() const { return gfx::Rect(); }
virtual void UpdateCursor(const WebCursor& cursor) {}
virtual void UpdateCursorIfOverSelf() {}
@@ -68,11 +50,6 @@ 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.
@@ -207,10 +184,33 @@ class TestWebContents : public WebContents {
return static_cast<TestRenderViewHost*>(
render_manager_.pending_render_view_host_);
}
-
- // State accessor.
- bool cross_navigation_pending() {
- return render_manager_.cross_navigation_pending_;
+ 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;
}
// Ensure we create TestRenderViewHosts that don't spawn processes.
@@ -250,84 +250,28 @@ class TestWebContents : public WebContents {
bool transition_cross_site;
};
-class TestInterstitialPage : public InterstitialPage {
- public:
- 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 TestDomOperationResponse(const std::string& json_string) {
- DomOperationResponse(json_string, 1);
- }
-
- void TestDidNavigate(int page_id, const GURL& url) {
- ViewHostMsg_FrameNavigate_Params params;
- InitNavigateParams(&params, 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) {}
+ 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;
+ }
+
// testing::Test methods:
virtual void SetUp() {
@@ -342,7 +286,6 @@ 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
@@ -350,13 +293,6 @@ class WebContentsTest : public testing::Test {
MessageLoop::current()->RunAllPending();
}
- void Navigate(int page_id, const GURL& url) {
- DCHECK(contents);
- ViewHostMsg_FrameNavigate_Params params;
- InitNavigateParams(&params, page_id, url);
- contents->TestDidNavigate(contents->rvh(), params);
- }
-
scoped_ptr<WebContentsTestingProfile> profile;
TestWebContents* contents;
@@ -370,9 +306,9 @@ TEST_F(WebContentsTest, UpdateTitle) {
InitNavigateParams(&params, 0, GURL("about:blank"));
NavigationController::LoadCommittedDetails details;
- contents->controller()->RendererDidNavigate(params, &details);
+ contents->controller()->RendererDidNavigate(params, false, &details);
- contents->UpdateTitle(contents->rvh(), 0, L" Lots O' Whitespace\n");
+ contents->UpdateTitle(NULL, 0, L" Lots O' Whitespace\n");
EXPECT_EQ(std::wstring(L"Lots O' Whitespace"), contents->GetTitle());
}
@@ -381,12 +317,14 @@ 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_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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
@@ -398,7 +336,7 @@ TEST_F(WebContentsTest, SimpleNavigation) {
ViewHostMsg_FrameNavigate_Params params;
InitNavigateParams(&params, 1, url);
contents->TestDidNavigate(orig_rvh, params);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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
@@ -407,6 +345,260 @@ 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(&params, 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(&params, 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(&params, 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(&params2, 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(&params1, 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(&params2, 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(&params3, 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(&params1, 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(&params2, 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(&params3, 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(&params4, 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) {
@@ -423,13 +615,15 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) {
InitNavigateParams(&params1, 1, url);
contents->TestDidNavigate(orig_rvh, params1);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ 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);
// Navigate to new site
const GURL url2("http://www.yahoo.com");
contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
- EXPECT_TRUE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_pending());
TestRenderViewHost* pending_rvh = contents->pending_rvh();
int pending_rvh_delete_count = 0;
pending_rvh->set_delete_counter(&pending_rvh_delete_count);
@@ -440,21 +634,23 @@ TEST_F(WebContentsTest, CrossSiteBoundaries) {
contents->TestDidNavigate(pending_rvh, params2);
SiteInstance* instance2 = contents->GetSiteInstance();
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_pending());
// DidNavigate from the back action
contents->TestDidNavigate(goback_rvh, params1);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
EXPECT_EQ(goback_rvh, contents->render_view_host());
EXPECT_EQ(pending_rvh_delete_count, 1);
EXPECT_EQ(instance1, contents->GetSiteInstance());
@@ -476,8 +672,10 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) {
InitNavigateParams(&params1, 1, url);
contents->TestDidNavigate(orig_rvh, params1);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ 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);
// Crash the renderer.
orig_rvh->is_created = false;
@@ -486,8 +684,10 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) {
const GURL url2("http://www.yahoo.com");
contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
TestRenderViewHost* new_rvh = contents->rvh();
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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);
@@ -497,10 +697,330 @@ TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) {
contents->TestDidNavigate(new_rvh, params2);
SiteInstance* instance2 = contents->GetSiteInstance();
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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(&params1, 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(&params2, 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(&params1, 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(&params2, 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(&params3, 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(&params1, 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(&params2, 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(&params3, 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(&params1, 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(&params2, 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(&params3, 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(&params1, 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(&params2, 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(&params3, 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
@@ -542,7 +1062,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->cross_navigation_pending());
+ EXPECT_TRUE(contents2->state_is_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
@@ -580,16 +1100,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 cross site
- // pending.
+ // The first RVH in contents2 isn't live yet, so we shortcut the PENDING
+ // state and go straight to NORMAL.
TestRenderViewHost* rvh2 = contents2->rvh();
- EXPECT_FALSE(contents2->cross_navigation_pending());
+ EXPECT_TRUE(contents2->state_is_normal());
ViewHostMsg_FrameNavigate_Params params2;
InitNavigateParams(&params2, 2, url2);
contents2->TestDidNavigate(rvh2, params2);
SiteInstance* instance2 = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2);
- EXPECT_FALSE(contents2->cross_navigation_pending());
+ EXPECT_TRUE(contents2->state_is_normal());
// Simulate a link click in first tab to second site. Doesn't switch
// SiteInstances, because we don't intercept WebKit navigations.
@@ -598,13 +1118,13 @@ TEST_F(WebContentsTest, CrossSiteComparesAgainstCurrentPage) {
contents->TestDidNavigate(orig_rvh, params3);
SiteInstance* instance3 = contents->GetSiteInstance();
EXPECT_EQ(instance1, instance3);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
// 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_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
ViewHostMsg_FrameNavigate_Params params4;
InitNavigateParams(&params4, 3, url3);
contents->TestDidNavigate(orig_rvh, params4);
@@ -627,7 +1147,7 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) {
ViewHostMsg_FrameNavigate_Params params1;
InitNavigateParams(&params1, 1, url);
contents->TestDidNavigate(orig_rvh, params1);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
EXPECT_EQ(orig_rvh, contents->render_view_host());
// Navigate to new site, but simulate an onbeforeunload denial.
@@ -635,13 +1155,13 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) {
orig_rvh->immediate_before_unload = false;
contents->controller()->LoadURL(url2, GURL(), PageTransition::TYPED);
orig_rvh->TestOnMsgShouldClose(false);
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_pending());
TestRenderViewHost* pending_rvh = contents->pending_rvh();
// We won't hear DidNavigate until the onunload handler has finished running.
@@ -653,10 +1173,12 @@ TEST_F(WebContentsTest, CrossSiteUnloadHandlers) {
InitNavigateParams(&params2, 1, url2);
contents->TestDidNavigate(pending_rvh, params2);
SiteInstance* instance2 = contents->GetSiteInstance();
- EXPECT_FALSE(contents->cross_navigation_pending());
+ EXPECT_TRUE(contents->state_is_normal());
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
@@ -731,472 +1253,3 @@ 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 dda346c..e97f6ac 100644
--- a/chrome/browser/web_contents_view_win.cc
+++ b/chrome/browser/web_contents_view_win.cc
@@ -10,7 +10,6 @@
#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"
@@ -596,8 +595,6 @@ 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())