diff options
-rw-r--r-- | chrome/browser/browser.cc | 181 | ||||
-rw-r--r-- | chrome/browser/browser.h | 28 | ||||
-rw-r--r-- | chrome/browser/render_process_host.cc | 6 | ||||
-rw-r--r-- | chrome/browser/render_process_host.h | 3 | ||||
-rw-r--r-- | chrome/browser/render_view_host.cc | 49 | ||||
-rw-r--r-- | chrome/browser/render_view_host.h | 12 | ||||
-rw-r--r-- | chrome/browser/render_widget_helper.cc | 12 | ||||
-rw-r--r-- | chrome/browser/render_widget_helper.h | 6 | ||||
-rw-r--r-- | chrome/browser/resource_dispatcher_host.cc | 6 | ||||
-rw-r--r-- | chrome/browser/resource_dispatcher_host.h | 3 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.cc | 6 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.h | 3 | ||||
-rw-r--r-- | chrome/browser/tab_contents_delegate.h | 10 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.cc | 2 | ||||
-rw-r--r-- | chrome/browser/web_contents.cc | 15 | ||||
-rw-r--r-- | chrome/browser/web_contents_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 17 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 12 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 5 |
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(); |