| 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..ad7ca3612571270428c7bb496804e730ce0c9559 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()),
|
| 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_before_unload_event,
|
| 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_before_unload_event);
|
| + return true && !skip_before_unload_event;
|
| }
|
|
|
| -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_before_unload_event) {
|
| 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_before_unload_event) {
|
| + // 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_before_unload_event) {
|
| + 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_before_unload_event);
|
| + }
|
| + return;
|
| }
|
| - return;
|
| }
|
|
|
| if (is_calling_before_unload_handlers()) {
|
| - on_close_confirmed_.Run(true);
|
| + if (!skip_before_unload_event)
|
| + on_close_confirmed_.Run(true);
|
| return;
|
| }
|
| +
|
| // Process all the unload handlers. (The beforeunload handlers have finished.)
|
| if (!tabs_needing_unload_.empty()) {
|
| browser_->OnWindowClosing();
|
| @@ -494,7 +491,7 @@ void FastUnloadController::ClearUnloadState(content::WebContents* contents) {
|
| void FastUnloadController::PostTaskForProcessPendingTabs() {
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE, base::Bind(&FastUnloadController::ProcessPendingTabs,
|
| - weak_factory_.GetWeakPtr()));
|
| + weak_factory_.GetWeakPtr(), false));
|
| }
|
|
|
| } // namespace chrome
|
|
|