Chromium Code Reviews| Index: chrome/browser/ui/fast_unload_controller.cc |
| diff --git a/chrome/browser/ui/fast_unload_controller.cc b/chrome/browser/ui/fast_unload_controller.cc |
| index 73ee5dc366a361dad76e84ee5bbedee0b174d9fc..cc0ec68f230f18a3fab436b2963b2a1ad538b348 100644 |
| --- a/chrome/browser/ui/fast_unload_controller.cc |
| +++ b/chrome/browser/ui/fast_unload_controller.cc |
| @@ -16,12 +16,12 @@ |
| #include "chrome/browser/ui/tab_contents/core_tab_helper.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" |
| +#include "chrome/browser/ui/unload_controller_web_contents_delegate.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/browser/notification_types.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/web_contents.h" |
| -#include "content/public/browser/web_contents_delegate.h" |
| #include "extensions/features/features.h" |
| #if BUILDFLAG(ENABLE_EXTENSIONS) |
| @@ -32,37 +32,13 @@ |
| namespace chrome { |
| //////////////////////////////////////////////////////////////////////////////// |
| -// DetachedWebContentsDelegate will delete web contents when they close. |
| -class FastUnloadController::DetachedWebContentsDelegate |
| - : public content::WebContentsDelegate { |
| - public: |
| - DetachedWebContentsDelegate() { } |
| - ~DetachedWebContentsDelegate() override {} |
| - |
| - private: |
| - // WebContentsDelegate implementation. |
| - bool ShouldSuppressDialogs(content::WebContents* source) override { |
| - return true; // Return true so dialogs are suppressed. |
| - } |
| - |
| - void CloseContents(content::WebContents* source) override { |
| - // Finished detached close. |
| - // FastUnloadController will observe |
| - // |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|. |
| - delete source; |
| - } |
| - |
| - DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate); |
| -}; |
| - |
| -//////////////////////////////////////////////////////////////////////////////// |
| // FastUnloadController, public: |
| FastUnloadController::FastUnloadController(Browser* browser) |
| : browser_(browser), |
| tab_needing_before_unload_ack_(NULL), |
| is_attempting_to_close_browser_(false), |
| - detached_delegate_(new DetachedWebContentsDelegate()), |
| + detached_delegate_(new UnloadControllerWebContentsDelegate()), |
|
sky
2017/03/14 00:04:05
MakeUnique
zmin
2017/03/14 17:46:47
Done.
|
| weak_factory_(this) { |
| browser_->tab_strip_model()->AddObserver(this); |
| } |
| @@ -156,7 +132,7 @@ bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents, |
| // Now that beforeunload has fired, queue the tab to fire unload. |
| tab_needing_before_unload_ack_ = NULL; |
| tabs_needing_unload_.insert(contents); |
| - ProcessPendingTabs(); |
| + ProcessPendingTabs(false); |
| // 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. |
| @@ -199,24 +175,26 @@ bool FastUnloadController::ShouldCloseWindow() { |
| // Cases 2 and 3. |
| on_close_confirmed_.Reset(); |
| - ProcessPendingTabs(); |
| + ProcessPendingTabs(false); |
| return false; |
| } |
| -bool FastUnloadController::CallBeforeUnloadHandlers( |
| +bool FastUnloadController::TryToCloseWindow( |
| + bool skip_beforeunload, |
| const base::Callback<void(bool)>& on_close_confirmed) { |
| -// The devtools browser gets its beforeunload events as the results of |
| -// intercepting events from the inspected tab, so don't send them here as well. |
| + // The devtools browser gets its beforeunload events as the results of |
| + // intercepting events from the inspected tab, so don't send them here as |
| + // well. |
| if (browser_->is_devtools() || !TabsNeedBeforeUnloadFired()) |
| return false; |
| on_close_confirmed_ = on_close_confirmed; |
| is_attempting_to_close_browser_ = true; |
| - ProcessPendingTabs(); |
| - return true; |
| + ProcessPendingTabs(skip_beforeunload); |
| + return true && !skip_beforeunload; |
|
sky
2017/03/14 00:04:05
return !skip_beforeunload?
zmin
2017/03/14 17:46:47
Done.
|
| } |
| -void FastUnloadController::ResetBeforeUnloadHandlers() { |
| +void FastUnloadController::ResetTryToCloseWindow() { |
| if (!is_calling_before_unload_handlers()) |
| return; |
| CancelWindowClose(); |
| @@ -252,10 +230,7 @@ bool FastUnloadController::HasCompletedUnloadProcessing() const { |
| tabs_needing_unload_ack_.empty(); |
| } |
| -void FastUnloadController::CancelWindowClose() { |
| - // Closing of window can be canceled from a beforeunload handler. |
| - DCHECK(is_attempting_to_close_browser_); |
| - tabs_needing_before_unload_.clear(); |
| +void FastUnloadController::CancelTabNeedingBeforeUnloadAck() { |
| if (tab_needing_before_unload_ack_ != NULL) { |
| CoreTabHelper* core_tab_helper = |
| CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_); |
| @@ -263,6 +238,13 @@ void FastUnloadController::CancelWindowClose() { |
| DevToolsWindow::OnPageCloseCanceled(tab_needing_before_unload_ack_); |
| tab_needing_before_unload_ack_ = NULL; |
| } |
| +} |
| + |
| +void FastUnloadController::CancelWindowClose() { |
| + // Closing of window can be canceled from a beforeunload handler. |
| + DCHECK(is_attempting_to_close_browser_); |
| + tabs_needing_before_unload_.clear(); |
| + CancelTabNeedingBeforeUnloadAck(); |
| for (WebContentsSet::iterator it = tabs_needing_unload_.begin(); |
| it != tabs_needing_unload_.end(); it++) { |
| content::WebContents* contents = *it; |
| @@ -382,7 +364,7 @@ bool FastUnloadController::DetachWebContents(content::WebContents* contents) { |
| return false; |
| } |
| -void FastUnloadController::ProcessPendingTabs() { |
| +void FastUnloadController::ProcessPendingTabs(bool skip_beforeunload) { |
| if (!is_attempting_to_close_browser_) { |
| // Because we might invoke this after a delay it's possible for the value of |
| // is_attempting_to_close_browser_ to have changed since we scheduled the |
| @@ -391,39 +373,54 @@ void FastUnloadController::ProcessPendingTabs() { |
| } |
| if (tab_needing_before_unload_ack_ != NULL) { |
| - // Wait for |BeforeUnloadFired| before proceeding. |
| - return; |
| + if (skip_beforeunload) { |
| + // Cancel and skip the ongoing before unload event. |
| + tabs_needing_before_unload_.insert(tab_needing_before_unload_ack_); |
| + CancelTabNeedingBeforeUnloadAck(); |
| + } else { |
| + // Wait for |BeforeUnloadFired| before proceeding. |
| + return; |
| + } |
| } |
| // Process a beforeunload handler. |
| if (!tabs_needing_before_unload_.empty()) { |
| - WebContentsSet::iterator it = tabs_needing_before_unload_.begin(); |
| - content::WebContents* contents = *it; |
| - tabs_needing_before_unload_.erase(it); |
| - // Null check render_view_host here as this gets called on a PostTask and |
| - // the tab's render_view_host may have been nulled out. |
| - if (contents->GetRenderViewHost()) { |
| - tab_needing_before_unload_ack_ = contents; |
| - |
| - CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); |
| - core_tab_helper->OnCloseStarted(); |
| - |
| - // If there's a devtools window attached to |contents|, |
| - // we would like devtools to call its own beforeunload handlers first, |
| - // and then call beforeunload handlers for |contents|. |
| - // See DevToolsWindow::InterceptPageBeforeUnload for details. |
| - if (!DevToolsWindow::InterceptPageBeforeUnload(contents)) |
| - contents->DispatchBeforeUnload(); |
| + if (skip_beforeunload) { |
| + tabs_needing_unload_.insert(tabs_needing_before_unload_.begin(), |
| + tabs_needing_before_unload_.end()); |
| + tabs_needing_before_unload_.clear(); |
| } else { |
| - ProcessPendingTabs(); |
| + WebContentsSet::iterator it = tabs_needing_before_unload_.begin(); |
| + content::WebContents* contents = *it; |
| + tabs_needing_before_unload_.erase(it); |
| + // Null check render_view_host here as this gets called on a PostTask and |
| + // the tab's render_view_host may have been nulled out. |
| + if (contents->GetRenderViewHost()) { |
| + tab_needing_before_unload_ack_ = contents; |
| + |
| + CoreTabHelper* core_tab_helper = |
| + CoreTabHelper::FromWebContents(contents); |
| + core_tab_helper->OnCloseStarted(); |
| + |
| + // If there's a devtools window attached to |contents|, |
| + // we would like devtools to call its own beforeunload handlers first, |
| + // and then call beforeunload handlers for |contents|. |
| + // See DevToolsWindow::InterceptPageBeforeUnload for details. |
| + if (!DevToolsWindow::InterceptPageBeforeUnload(contents)) |
| + contents->DispatchBeforeUnload(); |
| + } else { |
| + ProcessPendingTabs(skip_beforeunload); |
| + } |
| + return; |
| } |
| - return; |
| } |
| if (is_calling_before_unload_handlers()) { |
| - on_close_confirmed_.Run(true); |
| + if (!skip_beforeunload) |
| + on_close_confirmed_.Run(true); |
| return; |
| } |
| + |
| // Process all the unload handlers. (The beforeunload handlers have finished.) |
| if (!tabs_needing_unload_.empty()) { |
| browser_->OnWindowClosing(); |
| @@ -493,8 +490,9 @@ void FastUnloadController::ClearUnloadState(content::WebContents* contents) { |
| void FastUnloadController::PostTaskForProcessPendingTabs() { |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| - FROM_HERE, base::Bind(&FastUnloadController::ProcessPendingTabs, |
| - weak_factory_.GetWeakPtr())); |
| + FROM_HERE, |
| + base::Bind(&FastUnloadController::ProcessPendingTabs, |
| + weak_factory_.GetWeakPtr(), false)); |
| } |
| } // namespace chrome |