summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser.cc181
-rw-r--r--chrome/browser/browser.h28
-rw-r--r--chrome/browser/render_process_host.cc6
-rw-r--r--chrome/browser/render_process_host.h3
-rw-r--r--chrome/browser/render_view_host.cc49
-rw-r--r--chrome/browser/render_view_host.h12
-rw-r--r--chrome/browser/render_widget_helper.cc12
-rw-r--r--chrome/browser/render_widget_helper.h6
-rw-r--r--chrome/browser/resource_dispatcher_host.cc6
-rw-r--r--chrome/browser/resource_dispatcher_host.h3
-rw-r--r--chrome/browser/resource_message_filter.cc6
-rw-r--r--chrome/browser/resource_message_filter.h3
-rw-r--r--chrome/browser/tab_contents_delegate.h10
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc2
-rw-r--r--chrome/browser/web_contents.cc15
-rw-r--r--chrome/browser/web_contents_unittest.cc6
-rw-r--r--chrome/common/render_messages_internal.h17
-rw-r--r--chrome/renderer/render_view.cc12
-rw-r--r--chrome/renderer/render_view.h5
19 files changed, 188 insertions, 194 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 02fe2e2..2768b65 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -209,7 +209,7 @@ Browser::Browser(const gfx::Rect& initial_bounds,
: profile_(profile),
window_(NULL),
initial_show_command_(show_command),
- is_processing_tab_unload_events_(false),
+ is_attempting_to_close_browser_(false),
controller_(this),
chrome_updater_factory_(this),
method_factory_(this),
@@ -743,6 +743,15 @@ void Browser::LoadingStateChanged(TabContents* source) {
}
void Browser::CloseContents(TabContents* source) {
+ if (is_attempting_to_close_browser_) {
+ // If we're trying to close the browser, just clear the state related to
+ // waiting for unload to fire. Don't actually try to close the tab as it
+ // will go down the slow shutdown path instead of the fast path of killing
+ // all the renderer processes.
+ UnloadFired(source);
+ return;
+ }
+
int index = tabstrip_model_.GetIndexOfTabContents(source);
if (index == TabStripModel::kNoTab) {
NOTREACHED() << "CloseContents called for tab not in our strip";
@@ -992,11 +1001,10 @@ void Browser::MoveToFront(bool should_activate) {
}
bool Browser::ShouldCloseWindow() {
- if (is_processing_tab_unload_events_) {
- return tabs_needing_before_unload_fired_.empty() &&
- tabs_needing_unload_fired_.empty();
+ if (HasCompletedUnloadProcessing()) {
+ return true;
}
- is_processing_tab_unload_events_ = true;
+ is_attempting_to_close_browser_ = true;
for (int i = 0; i < tab_count(); ++i) {
if (tabstrip_model_.TabHasUnloadListener(i)) {
@@ -1015,108 +1023,129 @@ bool Browser::ShouldCloseWindow() {
if (tabs_needing_before_unload_fired_.empty())
return true;
- ProcessPendingBeforeUnloadTabs();
+ ProcessPendingTabs();
return false;
}
-void Browser::ProcessPendingBeforeUnloadTabs() {
- DCHECK(is_processing_tab_unload_events_);
-
- TabContents* tab = tabs_needing_before_unload_fired_.back();
- tab->AsWebContents()->render_view_host()->AttemptToClosePage(true);
-}
-
-void Browser::ProcessPendingUnloadTabs() {
- DCHECK(is_processing_tab_unload_events_);
+void Browser::ProcessPendingTabs() {
+ DCHECK(is_attempting_to_close_browser_);
- TabContents* tab = tabs_needing_unload_fired_.back();
- tab->AsWebContents()->render_view_host()->OnProceedWithClosePage(true);
-}
-
-void Browser::BeforeUnloadFired(TabContents* tab, bool proceed) {
- DCHECK(is_processing_tab_unload_events_);
-
- if (!proceed) {
- tabs_needing_before_unload_fired_.clear();
- tabs_needing_unload_fired_.clear();
- is_processing_tab_unload_events_ = false;
+ if (HasCompletedUnloadProcessing()) {
+ // We've finished all the unload events and can proceed to close the
+ // browser.
+ OnWindowClosing();
return;
}
- tabs_needing_unload_fired_.push_back(tab);
-
- for (UnloadListenerVector::iterator it =
- tabs_needing_before_unload_fired_.begin();
- it != tabs_needing_before_unload_fired_.end();
- ++it) {
- if (*it == tab) {
- tabs_needing_before_unload_fired_.erase(it);
- break;
- }
- }
-
- if (tabs_needing_before_unload_fired_.empty()) {
+ // Process beforeunload tabs first. When that queue is empty, process
+ // unload tabs.
+ // TODO(ojan): Move some of this logic down into TabContents and/or
+ // WebContents so we don't need to dig into RenderViewHost here.
+ if (!tabs_needing_before_unload_fired_.empty()) {
+ TabContents* tab = tabs_needing_before_unload_fired_.back();
+ tab->AsWebContents()->render_view_host()->FirePageBeforeUnload();
+ } else if (!tabs_needing_unload_fired_.empty()) {
// We've finished firing all beforeunload events and can proceed with unload
// events.
// TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
// somewhere around here so that we have accurate measurements of shutdown
// time.
- ProcessPendingUnloadTabs();
+ // TODO(ojan): We can probably fire all the unload events in parallel and
+ // get a perf benefit from that in the cases where the tab hangs in it's
+ // unload handler or takes a long time to page in.
+ TabContents* tab = tabs_needing_unload_fired_.back();
+ tab->AsWebContents()->render_view_host()->FirePageUnload();
} else {
- ProcessPendingBeforeUnloadTabs();
+ NOTREACHED();
}
}
-void Browser::UnloadFired(TabContents* tab) {
- DCHECK(is_processing_tab_unload_events_);
+bool Browser::HasCompletedUnloadProcessing() {
+ return is_attempting_to_close_browser_ &&
+ tabs_needing_before_unload_fired_.empty() &&
+ tabs_needing_unload_fired_.empty();
+}
- for (UnloadListenerVector::iterator it = tabs_needing_unload_fired_.begin();
- it != tabs_needing_unload_fired_.end();
- ++it) {
- if (*it == tab) {
- tabs_needing_unload_fired_.erase(it);
- break;
- }
+void Browser::CancelWindowClose() {
+ DCHECK(is_attempting_to_close_browser_);
+ // Only cancelling beforeunload should be able to cancel the window's close.
+ // So there had better be a tab that we think needs beforeunload fired.
+ DCHECK(!tabs_needing_before_unload_fired_.empty());
+
+ while (!tabs_needing_before_unload_fired_.empty()) {
+ TabContents* tab = tabs_needing_before_unload_fired_.back();
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
+ Source<TabContents>(tab));
+ tabs_needing_before_unload_fired_.pop_back();
}
- NotificationService::current()->
- RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
- Source<TabContents>(tab));
+ while (!tabs_needing_unload_fired_.empty()) {
+ TabContents* tab = tabs_needing_unload_fired_.back();
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
+ Source<TabContents>(tab));
+ tabs_needing_unload_fired_.pop_back();
+ }
- if (tabs_needing_unload_fired_.empty()) {
- // We've finished all the unload events and can proceed to close the
- // browser.
- OnWindowClosing();
- } else {
- ProcessPendingUnloadTabs();
+ is_attempting_to_close_browser_ = false;
+}
+
+void Browser::BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload) {
+ if (!is_attempting_to_close_browser_) {
+ *proceed_to_fire_unload = proceed;
+ return;
}
+
+ if (!proceed) {
+ CancelWindowClose();
+ *proceed_to_fire_unload = false;
+ return;
+ }
+
+ if (RemoveFromVector(&tabs_needing_before_unload_fired_, tab)) {
+ // Now that beforeunload has fired, put the tab on the queue to fire unload.
+ tabs_needing_unload_fired_.push_back(tab);
+ ProcessPendingTabs();
+ // We want to handle firing the unload event ourselves since we want to
+ // fire all the beforeunload events before attempting to fire the unload
+ // events should the user cancel closing the browser.
+ *proceed_to_fire_unload = false;
+ return;
+ }
+
+ *proceed_to_fire_unload = true;
+}
+
+void Browser::UnloadFired(TabContents* tab) {
+ DCHECK(is_attempting_to_close_browser_);
+ RemoveFromVector(&tabs_needing_unload_fired_, tab);
+ ProcessPendingTabs();
}
void Browser::ClearUnloadStateOnCrash(TabContents* tab) {
- bool is_waiting_on_before_unload = false;
+ DCHECK(is_attempting_to_close_browser_);
+ RemoveFromVector(&tabs_needing_before_unload_fired_, tab);
+ RemoveFromVector(&tabs_needing_unload_fired_, tab);
+ ProcessPendingTabs();
+}
- for (UnloadListenerVector::iterator it =
- tabs_needing_before_unload_fired_.begin();
- it != tabs_needing_before_unload_fired_.end();
+bool Browser::RemoveFromVector(UnloadListenerVector* vector, TabContents* tab) {
+ DCHECK(is_attempting_to_close_browser_);
+
+ for (UnloadListenerVector::iterator it = vector->begin();
+ it != vector->end();
++it) {
if (*it == tab) {
- is_waiting_on_before_unload = true;
- break;
+ vector->erase(it);
+ return true;
}
}
-
- if (is_waiting_on_before_unload) {
- // Even though beforeunload didn't really fire, we call the same function
- // so that all the appropriate cleanup happens.
- BeforeUnloadFired(tab, true);
- } else {
- // Even though unload didn't really fire, we call the same function
- // so that all the appropriate cleanup happens.
- UnloadFired(tab);
- }
+ return false;
}
-
void Browser::OnWindowClosing() {
if (!ShouldCloseWindow())
return;
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index ba4133e..a172df8 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -187,8 +187,12 @@ class Browser : public TabStripModelDelegate,
// Tells us that we've finished firing this tab's beforeunload event.
// The proceed bool tells us whether the user chose to proceed closing the
- // tab.
- void BeforeUnloadFired(TabContents* source, bool proceed);
+ // tab. Returns true if the tab can continue on firing it's unload event.
+ // If we're closing the entire browser, then we'll want to delay firing
+ // unload events until all the beforeunload events have fired.
+ void BeforeUnloadFired(TabContents* source,
+ bool proceed,
+ bool* proceed_to_fire_unload);
// Tells us that we've finished firing this tab's unload event.
void UnloadFired(TabContents* source);
@@ -512,13 +516,19 @@ class Browser : public TabStripModelDelegate,
TabContents* new_contents,
const gfx::Rect& initial_pos);
- // Processes the next tab that needs it's beforeunload event fired before
- // we can proceed with closing the browser.
- void ProcessPendingBeforeUnloadTabs();
+ // Processes the next tab that needs it's beforeunload/unload event fired.
+ void ProcessPendingTabs();
- // Processes the next tab that needs it's unload event fired before we can
- // proceed with closing the browser.
- void ProcessPendingUnloadTabs();
+ // Whether we've completed firing all the tabs' beforeunload/unload events.
+ bool HasCompletedUnloadProcessing();
+
+ // Clears all the state associated with processing tabs' beforeunload/unload
+ // events since the user cancelled closing the window.
+ void CancelWindowClose();
+
+ // Removes the tab from the associated vector. Returns whether the tab
+ // was in the vector in the first place.
+ bool RemoveFromVector(UnloadListenerVector* vector, TabContents* tab);
// Cleans up state appropriately when we are trying to close the browser
// and a tab crashes in it's beforeunload/unload handler.
@@ -572,7 +582,7 @@ class Browser : public TabStripModelDelegate,
// Whether we are processing the beforeunload and unload events of each tab
// in preparation for closing the browser.
- bool is_processing_tab_unload_events_;
+ bool is_attempting_to_close_browser_;
// The following factory is used for chrome update coalescing.
ScopedRunnableMethodFactory<Browser> chrome_updater_factory_;
diff --git a/chrome/browser/render_process_host.cc b/chrome/browser/render_process_host.cc
index feb1e32..c1f2b5f 100644
--- a/chrome/browser/render_process_host.cc
+++ b/chrome/browser/render_process_host.cc
@@ -531,11 +531,9 @@ void RenderProcessHost::UpdateMaxPageID(int32 page_id) {
}
void RenderProcessHost::CrossSiteClosePageACK(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser) {
+ int new_request_id) {
widget_helper_->CrossSiteClosePageACK(new_render_process_host_id,
- new_request_id,
- is_closing_browser);
+ new_request_id);
}
void RenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
diff --git a/chrome/browser/render_process_host.h b/chrome/browser/render_process_host.h
index 6384fd9..117ad55 100644
--- a/chrome/browser/render_process_host.h
+++ b/chrome/browser/render_process_host.h
@@ -149,8 +149,7 @@ class RenderProcessHost : public IPC::Channel::Listener,
// Necessary for a cross-site request, in the case that the original
// RenderViewHost is not live and thus cannot run an onunload handler.
void CrossSiteClosePageACK(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser);
+ int new_request_id);
// IPC channel listener
virtual void OnMessageReceived(const IPC::Message& msg);
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc
index c18356a..bb98a9e 100644
--- a/chrome/browser/render_view_host.cc
+++ b/chrome/browser/render_view_host.cc
@@ -45,8 +45,6 @@
#include "chrome/browser/renderer_security_policy.h"
#include "chrome/browser/debugger/debugger_wrapper.h"
#include "chrome/browser/site_instance.h"
-#include "chrome/browser/tab_contents.h"
-#include "chrome/browser/tab_contents_delegate.h"
#include "chrome/browser/user_metrics.h"
#include "chrome/browser/web_contents.h"
#include "chrome/common/resource_bundle.h"
@@ -246,35 +244,33 @@ void RenderViewHost::SetNavigationsSuspended(bool suspend) {
}
}
-void RenderViewHost::AttemptToClosePage(bool is_closing_browser) {
+void RenderViewHost::FirePageBeforeUnload() {
if (IsRenderViewLive()) {
// Start the hang monitor in case the renderer hangs in the beforeunload
// handler.
DCHECK(!is_waiting_for_unload_ack_);
is_waiting_for_unload_ack_ = true;
StartHangMonitorTimeout(kUnloadTimeoutMS);
- Send(new ViewMsg_ShouldClose(routing_id_, is_closing_browser));
+ Send(new ViewMsg_ShouldClose(routing_id_));
} else {
// This RenderViewHost doesn't have a live renderer, so just skip running
// the onbeforeunload handler.
- OnMsgShouldCloseACK(true, is_closing_browser);
+ OnMsgShouldCloseACK(true);
}
}
-void RenderViewHost::OnProceedWithClosePage(bool is_closing_browser) {
+void RenderViewHost::FirePageUnload() {
// Start the hang monitor in case the renderer hangs in the unload handler.
DCHECK(!is_waiting_for_unload_ack_);
is_waiting_for_unload_ack_ = true;
StartHangMonitorTimeout(kUnloadTimeoutMS);
ClosePage(site_instance()->process_host_id(),
- routing_id(),
- is_closing_browser);
+ routing_id());
}
// static
void RenderViewHost::ClosePageIgnoringUnloadEvents(int render_process_host_id,
- int request_id,
- bool is_closing_browser) {
+ int request_id) {
RenderViewHost* rvh = RenderViewHost::FromID(render_process_host_id,
request_id);
if (!rvh)
@@ -284,32 +280,22 @@ void RenderViewHost::ClosePageIgnoringUnloadEvents(int render_process_host_id,
DCHECK(rvh->is_waiting_for_unload_ack_);
rvh->is_waiting_for_unload_ack_ = false;
- // The RenderViewHost's delegate is a WebContents.
- TabContents* tab = static_cast<WebContents*>(rvh->delegate());
rvh->UnloadListenerHasFired();
-
- if (is_closing_browser) {
- tab->delegate()->UnloadFired(tab);
- } else {
- rvh->delegate()->Close(rvh);
- }
+ rvh->delegate()->Close(rvh);
}
void RenderViewHost::ClosePage(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser) {
+ int new_request_id) {
if (IsRenderViewLive()) {
Send(new ViewMsg_ClosePage(routing_id_,
new_render_process_host_id,
- new_request_id,
- is_closing_browser));
+ new_request_id));
} else {
// This RenderViewHost doesn't have a live renderer, so just skip closing
// the page. We must notify the ResourceDispatcherHost on the IO thread,
// which we will do through the RenderProcessHost's widget helper.
process()->CrossSiteClosePageACK(new_render_process_host_id,
- new_request_id,
- is_closing_browser);
+ new_request_id);
}
}
@@ -1164,22 +1150,11 @@ void RenderViewHost::OnReceivedSerializedHtmlData(const GURL& frame_url,
delegate_->OnReceivedSerializedHtmlData(frame_url, data, status);
}
-void RenderViewHost::OnMsgShouldCloseACK(bool proceed,
- bool is_closing_browser) {
+void RenderViewHost::OnMsgShouldCloseACK(bool proceed) {
StopHangMonitorTimeout();
DCHECK(is_waiting_for_unload_ack_);
is_waiting_for_unload_ack_ = false;
-
- if (is_closing_browser) {
- // The RenderViewHost's delegate is a WebContents.
- TabContents* tab = static_cast<WebContents*>(delegate());
- if (!tab)
- return;
-
- tab->delegate()->BeforeUnloadFired(tab, proceed);
- } else {
- delegate_->ShouldClosePage(proceed);
- }
+ delegate_->ShouldClosePage(proceed);
}
void RenderViewHost::OnUnloadListenerChanged(bool has_listener) {
diff --git a/chrome/browser/render_view_host.h b/chrome/browser/render_view_host.h
index 488131a..a05659a 100644
--- a/chrome/browser/render_view_host.h
+++ b/chrome/browser/render_view_host.h
@@ -152,20 +152,19 @@ class RenderViewHost : public RenderWidgetHost {
// Causes the renderer to invoke the onbeforeunload event handler. The
// result will be returned via ViewMsg_ShouldClose.
- virtual void AttemptToClosePage(bool is_closing_browser);
+ virtual void FirePageBeforeUnload();
// Close the page after the page has responded that it can be closed via
// ViewMsg_ShouldClose. This is where the page itself is closed. The
// unload handler is triggered here, which can block with a dialog, but cannot
// cancel the close of the page.
- virtual void OnProceedWithClosePage(bool is_closing_browser);
+ virtual void FirePageUnload();
// Close the page ignoring whether it has unload events registers.
// This is called after the beforeunload and unload events have fired
// and the user has agreed to continue with closing the page.
static void ClosePageIgnoringUnloadEvents(int render_process_host_id,
- int request_id,
- bool is_closing_browser);
+ int request_id);
// Causes the renderer to close the current page, including running its
// onunload event handler. A ClosePage_ACK message will be sent to the
@@ -173,8 +172,7 @@ class RenderViewHost : public RenderWidgetHost {
// and |new_request_id| will help the ResourceDispatcherHost identify which
// response is associated with this event.
virtual void ClosePage(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser);
+ int new_request_id);
// Sets whether this RenderViewHost has an outstanding cross-site request,
// for which another renderer will need to run an onunload event handler.
@@ -502,7 +500,7 @@ class RenderViewHost : public RenderWidgetHost {
void OnDidGetApplicationInfo(int32 page_id,
const webkit_glue::WebApplicationInfo& info);
- void OnMsgShouldCloseACK(bool proceed, bool is_closing_browser);
+ void OnMsgShouldCloseACK(bool proceed);
void OnUnloadListenerChanged(bool has_handler);
virtual void NotifyRendererUnresponsive();
diff --git a/chrome/browser/render_widget_helper.cc b/chrome/browser/render_widget_helper.cc
index 708c236..241b23b 100644
--- a/chrome/browser/render_widget_helper.cc
+++ b/chrome/browser/render_widget_helper.cc
@@ -86,16 +86,14 @@ void RenderWidgetHelper::CancelResourceRequests(int render_widget_id) {
}
void RenderWidgetHelper::CrossSiteClosePageACK(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser) {
+ int new_request_id) {
if (g_browser_process->io_thread())
g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(this,
&RenderWidgetHelper::OnCrossSiteClosePageACK,
g_browser_process->resource_dispatcher_host(),
new_render_process_host_id,
- new_request_id,
- is_closing_browser));
+ new_request_id));
}
bool RenderWidgetHelper::WaitForPaintMsg(int render_widget_id,
@@ -198,10 +196,8 @@ void RenderWidgetHelper::OnCancelResourceRequests(
void RenderWidgetHelper::OnCrossSiteClosePageACK(
ResourceDispatcherHost* dispatcher,
int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser) {
- dispatcher->OnClosePageACK(new_render_process_host_id, new_request_id,
- is_closing_browser);
+ int new_request_id) {
+ dispatcher->OnClosePageACK(new_render_process_host_id, new_request_id);
}
void RenderWidgetHelper::CreateView(int opener_id,
diff --git a/chrome/browser/render_widget_helper.h b/chrome/browser/render_widget_helper.h
index 27360a3..1a7f939 100644
--- a/chrome/browser/render_widget_helper.h
+++ b/chrome/browser/render_widget_helper.h
@@ -116,8 +116,7 @@ class RenderWidgetHelper :
// that the original RenderViewHost is not live and thus cannot run an
// onunload handler.
void CrossSiteClosePageACK(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser);
+ int new_request_id);
// Called on the UI thread to wait for the next PaintRect message for the
// specified render widget. Returns true if successful, and the msg out-
@@ -159,8 +158,7 @@ class RenderWidgetHelper :
// Called on the IO thread to resume a cross-site response.
void OnCrossSiteClosePageACK(ResourceDispatcherHost* dispatcher,
int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser);
+ int new_request_id);
// A map of live paint messages. Must hold pending_paints_lock_ to access.
// The PaintMsgProxy objects are not owned by this map. (See PaintMsgProxy
diff --git a/chrome/browser/resource_dispatcher_host.cc b/chrome/browser/resource_dispatcher_host.cc
index c3f4e91..5c3ee2f 100644
--- a/chrome/browser/resource_dispatcher_host.cc
+++ b/chrome/browser/resource_dispatcher_host.cc
@@ -1682,8 +1682,7 @@ void ResourceDispatcherHost::PauseRequest(int render_process_host_id,
}
void ResourceDispatcherHost::OnClosePageACK(int render_process_host_id,
- int request_id,
- bool is_closing_browser) {
+ int request_id) {
GlobalRequestID global_id(render_process_host_id, request_id);
PendingRequestList::iterator i = pending_requests_.find(global_id);
if (i == pending_requests_.end()) {
@@ -1692,8 +1691,7 @@ void ResourceDispatcherHost::OnClosePageACK(int render_process_host_id,
ui_loop_->PostTask(FROM_HERE, NewRunnableFunction(
&RenderViewHost::ClosePageIgnoringUnloadEvents,
render_process_host_id,
- request_id,
- is_closing_browser));
+ request_id));
return;
}
diff --git a/chrome/browser/resource_dispatcher_host.h b/chrome/browser/resource_dispatcher_host.h
index a9099a9..ab03fcf 100644
--- a/chrome/browser/resource_dispatcher_host.h
+++ b/chrome/browser/resource_dispatcher_host.h
@@ -332,8 +332,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
MessageLoop* ui_loop() const { return ui_loop_; }
// Called when the onunload handler for a cross-site request has finished.
- void OnClosePageACK(int render_process_host_id, int request_id,
- bool is_closing_browser);
+ void OnClosePageACK(int render_process_host_id, int request_id);
// Force cancels any pending requests for the given process.
void CancelRequestsForProcess(int render_process_host_id);
diff --git a/chrome/browser/resource_message_filter.cc b/chrome/browser/resource_message_filter.cc
index 20007dc..d5234a8 100644
--- a/chrome/browser/resource_message_filter.cc
+++ b/chrome/browser/resource_message_filter.cc
@@ -329,11 +329,9 @@ void ResourceMessageFilter::OnCancelRequest(int request_id) {
}
void ResourceMessageFilter::OnClosePageACK(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser) {
+ int new_request_id) {
resource_dispatcher_host_->OnClosePageACK(new_render_process_host_id,
- new_request_id,
- is_closing_browser);
+ new_request_id);
}
void ResourceMessageFilter::OnSyncLoad(
diff --git a/chrome/browser/resource_message_filter.h b/chrome/browser/resource_message_filter.h
index dde52c8..a5525e7 100644
--- a/chrome/browser/resource_message_filter.h
+++ b/chrome/browser/resource_message_filter.h
@@ -93,8 +93,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnRequestResource(const IPC::Message& msg, int request_id,
const ViewHostMsg_Resource_Request& request);
void OnCancelRequest(int request_id);
- void OnClosePageACK(int new_render_process_host_id, int new_request_id,
- bool is_closing_browser);
+ void OnClosePageACK(int new_render_process_host_id, int new_request_id);
void OnDataReceivedACK(int request_id);
void OnUploadProgressACK(int request_id);
void OnSyncLoad(int request_id,
diff --git a/chrome/browser/tab_contents_delegate.h b/chrome/browser/tab_contents_delegate.h
index fc2a8c2..2dd077c7d 100644
--- a/chrome/browser/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents_delegate.h
@@ -182,8 +182,14 @@ class TabContentsDelegate : public PageNavigator {
// Tells us that we've finished firing this tab's beforeunload event.
// The proceed bool tells us whether the user chose to proceed closing the
- // tab.
- virtual void BeforeUnloadFired(TabContents* tab, bool proceed) {}
+ // tab. Returns true if the tab can continue on firing it's unload event.
+ // If we're closing the entire browser, then we'll want to delay firing
+ // unload events until all the beforeunload events have fired.
+ virtual void BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload) {
+ *proceed_to_fire_unload = true;
+ }
// Tells us that we've finished firing this tab's unload event.
virtual void UnloadFired(TabContents* tab) {}
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index dbfc0d1..c2076f1 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -531,7 +531,7 @@ bool TabStripModel::InternalCloseTabContentsAt(int index,
WebContents* web_contents = GetContentsAt(index)->AsWebContents();
// If we hit this code path, the tab had better be a WebContents tab.
DCHECK(web_contents);
- web_contents->render_view_host()->AttemptToClosePage(false);
+ web_contents->render_view_host()->FirePageBeforeUnload();
return false;
}
diff --git a/chrome/browser/web_contents.cc b/chrome/browser/web_contents.cc
index bed2787..927fc54 100644
--- a/chrome/browser/web_contents.cc
+++ b/chrome/browser/web_contents.cc
@@ -832,7 +832,7 @@ RenderViewHost* WebContents::UpdateRendererStateNavigate(
// Tell the old render view to run its onbeforeunload handler, since it
// doesn't otherwise know that the cross-site request is happening. This
// will trigger a call to ShouldClosePage with the reply.
- render_view_host_->AttemptToClosePage(false);
+ render_view_host_->FirePageBeforeUnload();
return pending_render_view_host_;
}
@@ -990,9 +990,12 @@ void WebContents::ShouldClosePage(bool proceed) {
// Should only see this while we have a pending renderer. Otherwise, we
// should ignore.
if (!pending_render_view_host_) {
- if (proceed) {
+ bool proceed_to_fire_unload;
+ delegate()->BeforeUnloadFired(this, proceed, &proceed_to_fire_unload);
+
+ if (proceed_to_fire_unload) {
// This is not a cross-site navigation, the tab is being closed.
- render_view_host_->OnProceedWithClosePage(false);
+ render_view_host_->FirePageUnload();
}
return;
}
@@ -1024,12 +1027,10 @@ void WebContents::OnCrossSiteResponse(int new_render_process_host_id,
if (IsShowingInterstitialPage()) {
DCHECK(original_render_view_host_);
original_render_view_host_->ClosePage(new_render_process_host_id,
- new_request_id,
- false); // is_closing_browser
+ new_request_id);
} else {
render_view_host_->ClosePage(new_render_process_host_id,
- new_request_id,
- false); // is_closing_browser
+ new_request_id);
}
// ResourceDispatcherHost has told us to run the onunload handler, which
diff --git a/chrome/browser/web_contents_unittest.cc b/chrome/browser/web_contents_unittest.cc
index da9d5d2..a4995fa 100644
--- a/chrome/browser/web_contents_unittest.cc
+++ b/chrome/browser/web_contents_unittest.cc
@@ -123,10 +123,8 @@ class TestRenderViewHost : public RenderViewHost {
}
// Support for onbeforeunload, onunload
- void AttemptToClosePage(bool is_closing_browser) {
+ void FirePageBeforeUnload() {
is_waiting_for_unload_ack_ = true;
- // TODO(ojan): Add tests for the case where is_closing_browser is true.
- DCHECK(!is_closing_browser);
if (immediate_before_unload)
delegate()->ShouldClosePage(true);
}
@@ -135,7 +133,7 @@ class TestRenderViewHost : public RenderViewHost {
// ResourceDispatcherHost, so we can simulate that manually.
}
void TestOnMsgShouldClose(bool proceed) {
- OnMsgShouldCloseACK(proceed, false);
+ OnMsgShouldCloseACK(proceed);
}
bool is_loading;
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index e7f7ea3..d52417f 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -418,14 +418,13 @@ IPC_BEGIN_MESSAGES(View, 1)
// Instructs the renderer to invoke the frame's shouldClose method, which
// runs the onbeforeunload event handler. Expects the result to be returned
// via ViewHostMsg_ShouldClose.
- IPC_MESSAGE_ROUTED1(ViewMsg_ShouldClose, bool /* is_closing_browser */)
+ IPC_MESSAGE_ROUTED0(ViewMsg_ShouldClose)
// Instructs the renderer to close the current page, including running the
// onunload event handler. Expects a ClosePage_ACK message when finished.
- IPC_MESSAGE_ROUTED3(ViewMsg_ClosePage,
+ IPC_MESSAGE_ROUTED2(ViewMsg_ClosePage,
int /* new_render_process_host_id */,
- int /* new_request_id */,
- bool /* is_closing_browser */)
+ int /* new_request_id */)
// Asks the renderer to send back stats on the WebCore cache broken down by
// resource types.
@@ -939,16 +938,14 @@ IPC_BEGIN_MESSAGES(ViewHost, 2)
// return value of the the frame's shouldClose method (which includes the
// onbeforeunload handler): true if the user decided to proceed with leaving
// the page.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_ShouldClose_ACK,
- bool /* proceed */,
- bool /* is_closing_browser */)
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_ShouldClose_ACK,
+ bool /* proceed */)
// Indicates that the current page has been closed, after a ClosePage
// message.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_ClosePage_ACK,
+ IPC_MESSAGE_ROUTED2(ViewHostMsg_ClosePage_ACK,
int /* new_render_process_host_id */,
- int /* new_request_id */,
- bool /* is_closing_browser */)
+ int /* new_request_id */)
IPC_MESSAGE_ROUTED4(ViewHostMsg_DidDownloadImage,
int /* Identifier of the request */,
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 28a9195..478efaa 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -2425,16 +2425,13 @@ void RenderView::DidSerializeDataForFrame(const GURL& frame_url,
frame_url, data, static_cast<int32>(status)));
}
-void RenderView::OnMsgShouldClose(bool is_closing_browser) {
+void RenderView::OnMsgShouldClose() {
bool should_close = webview()->ShouldClose();
-
- Send(new ViewHostMsg_ShouldClose_ACK(routing_id_, should_close,
- is_closing_browser));
+ Send(new ViewHostMsg_ShouldClose_ACK(routing_id_, should_close));
}
void RenderView::OnClosePage(int new_render_process_host_id,
- int new_request_id,
- bool is_closing_browser) {
+ int new_request_id) {
// TODO(creis): We'd rather use webview()->Close() here, but that currently
// sets the WebView's delegate_ to NULL, preventing any JavaScript dialogs
// in the onunload handler from appearing. For now, we're bypassing that and
@@ -2448,8 +2445,7 @@ void RenderView::OnClosePage(int new_render_process_host_id,
Send(new ViewHostMsg_ClosePage_ACK(routing_id_,
new_render_process_host_id,
- new_request_id,
- is_closing_browser));
+ new_request_id));
}
void RenderView::OnThemeChanged() {
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 844d877..c04be51 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -443,12 +443,11 @@ class RenderView : public RenderWidget, public WebViewDelegate,
// Checks if the RenderView should close, runs the beforeunload handler and
// sends ViewMsg_ShouldClose to the browser.
- void OnMsgShouldClose(bool is_closing_browser);
+ void OnMsgShouldClose();
// Runs the onunload handler and closes the page, replying with ClosePage_ACK
// (with the given RPH and request IDs, to help track the request).
- void OnClosePage(int new_render_process_host_id, int new_request_id,
- bool is_closing_browser);
+ void OnClosePage(int new_render_process_host_id, int new_request_id);
// Notification about ui theme changes.
void OnThemeChanged();