summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/unload_controller.cc
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 05:16:44 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 05:16:44 +0000
commited1bb720731ea7c7644c208da970f0609a7e3b62 (patch)
tree5d66f86a406225f13f3c87485db4e2dbdde688b0 /chrome/browser/ui/unload_controller.cc
parent8dc0d4052bbc6e023577e372679d471da9717236 (diff)
downloadchromium_src-ed1bb720731ea7c7644c208da970f0609a7e3b62.zip
chromium_src-ed1bb720731ea7c7644c208da970f0609a7e3b62.tar.gz
chromium_src-ed1bb720731ea7c7644c208da970f0609a7e3b62.tar.bz2
Revert Fast tab closure and dependent CL
Revert r205149 (Fast tab closure) and dependent CL r207181 (Move histograms and supporting code that don't belong in content out) since it breaks a bunch of systems. Mechanical revert of problematic CLs, setting NOTRY so we can land this in the face of flaky bots. BUG=142458,156896,249289,246999,246634,248998,250863 TBR=sky@chromium.org,joi@chromium.org,jam@chromium.org NOTRY=True Review URL: https://chromiumcodereview.appspot.com/17487002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207712 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/unload_controller.cc')
-rw-r--r--chrome/browser/ui/unload_controller.cc280
1 files changed, 80 insertions, 200 deletions
diff --git a/chrome/browser/ui/unload_controller.cc b/chrome/browser/ui/unload_controller.cc
index 19d6154..da61646 100644
--- a/chrome/browser/ui/unload_controller.cc
+++ b/chrome/browser/ui/unload_controller.cc
@@ -4,55 +4,25 @@
#include "chrome/browser/ui/unload_controller.h"
-#include "base/logging.h"
#include "base/message_loop.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
-#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/common/chrome_notification_types.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"
namespace chrome {
-
-////////////////////////////////////////////////////////////////////////////////
-// DetachedWebContentsDelegate will delete web contents when they close.
-class UnloadController::DetachedWebContentsDelegate
- : public content::WebContentsDelegate {
- public:
- DetachedWebContentsDelegate() { }
- virtual ~DetachedWebContentsDelegate() { }
-
- private:
- // WebContentsDelegate implementation.
- virtual bool ShouldSuppressDialogs() OVERRIDE {
- return true; // Return true so dialogs are suppressed.
- }
-
- virtual void CloseContents(content::WebContents* source) OVERRIDE {
- // Finished detached close.
- // UnloadController will observe |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|.
- delete source;
- }
-
- DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate);
-};
-
////////////////////////////////////////////////////////////////////////////////
// UnloadController, public:
UnloadController::UnloadController(Browser* browser)
: browser_(browser),
- tab_needing_before_unload_ack_(NULL),
is_attempting_to_close_browser_(false),
- detached_delegate_(new DetachedWebContentsDelegate()),
weak_factory_(this) {
browser_->tab_strip_model()->AddObserver(this);
}
@@ -64,20 +34,16 @@ UnloadController::~UnloadController() {
bool UnloadController::CanCloseContents(content::WebContents* contents) {
// Don't try to close the tab when the whole browser is being closed, since
// that avoids the fast shutdown path where we just kill all the renderers.
+ if (is_attempting_to_close_browser_)
+ ClearUnloadState(contents, true);
return !is_attempting_to_close_browser_;
}
bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
bool proceed) {
if (!is_attempting_to_close_browser_) {
- if (!proceed) {
+ if (!proceed)
contents->SetClosedByUserGesture(false);
- } else {
- // No more dialogs are possible, so remove the tab and finish
- // running unload listeners asynchrounously.
- browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents);
- DetachWebContents(contents);
- }
return proceed;
}
@@ -87,10 +53,10 @@ bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
return false;
}
- if (tab_needing_before_unload_ack_ == contents) {
- // Now that beforeunload has fired, queue the tab to fire unload.
- tab_needing_before_unload_ack_ = NULL;
- tabs_needing_unload_.insert(contents);
+ if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) {
+ // Now that beforeunload has fired, put the tab on the queue to fire
+ // unload.
+ tabs_needing_unload_fired_.insert(contents);
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
@@ -115,20 +81,15 @@ bool UnloadController::ShouldCloseWindow() {
}
bool UnloadController::TabsNeedBeforeUnloadFired() {
- if (!tabs_needing_before_unload_.empty() ||
- tab_needing_before_unload_ack_ != NULL)
- return true;
-
- if (!tabs_needing_unload_.empty())
- return false;
-
- for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
- content::WebContents* contents =
- browser_->tab_strip_model()->GetWebContentsAt(i);
- if (contents->NeedToFireBeforeUnload())
- tabs_needing_before_unload_.insert(contents);
+ if (tabs_needing_before_unload_fired_.empty()) {
+ for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
+ content::WebContents* contents =
+ browser_->tab_strip_model()->GetWebContentsAt(i);
+ if (contents->NeedToFireBeforeUnload())
+ tabs_needing_before_unload_fired_.insert(contents);
+ }
}
- return !tabs_needing_before_unload_.empty();
+ return !tabs_needing_before_unload_fired_.empty();
}
////////////////////////////////////////////////////////////////////////////////
@@ -138,15 +99,12 @@ void UnloadController::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
- case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: {
- registrar_.Remove(this,
- content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
- source);
- content::WebContents* contents =
- content::Source<content::WebContents>(source).ptr();
- ClearUnloadState(contents);
+ case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED:
+ if (is_attempting_to_close_browser_) {
+ ClearUnloadState(content::Source<content::WebContents>(source).ptr(),
+ false); // See comment for ClearUnloadState().
+ }
break;
- }
default:
NOTREACHED() << "Got a notification we didn't register for.";
}
@@ -193,41 +151,11 @@ void UnloadController::TabAttachedImpl(content::WebContents* contents) {
}
void UnloadController::TabDetachedImpl(content::WebContents* contents) {
- if (tabs_needing_unload_ack_.find(contents) !=
- tabs_needing_unload_ack_.end()) {
- // Tab needs unload to complete.
- // It will send |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| when done.
- return;
- }
-
- // If WEB_CONTENTS_DISCONNECTED was received then the notification may have
- // already been unregistered.
- const content::NotificationSource& source =
- content::Source<content::WebContents>(contents);
- if (registrar_.IsRegistered(this,
- content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
- source)) {
- registrar_.Remove(this,
- content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
- source);
- }
-
if (is_attempting_to_close_browser_)
- ClearUnloadState(contents);
-}
-
-bool UnloadController::DetachWebContents(content::WebContents* contents) {
- int index = browser_->tab_strip_model()->GetIndexOfWebContents(contents);
- if (index != TabStripModel::kNoTab &&
- contents->NeedToFireBeforeUnload()) {
- tabs_needing_unload_ack_.insert(contents);
- browser_->tab_strip_model()->DetachWebContentsAt(index);
- contents->SetDelegate(detached_delegate_.get());
- CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
- core_tab_helper->OnUnloadDetachedStarted();
- return true;
- }
- return false;
+ ClearUnloadState(contents, false);
+ registrar_.Remove(this,
+ content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+ content::Source<content::WebContents>(contents));
}
void UnloadController::ProcessPendingTabs() {
@@ -238,105 +166,58 @@ void UnloadController::ProcessPendingTabs() {
return;
}
- if (tab_needing_before_unload_ack_ != NULL) {
- // Wait for |BeforeUnloadFired| before proceeding.
+ if (HasCompletedUnloadProcessing()) {
+ // We've finished all the unload events and can proceed to close the
+ // browser.
+ browser_->OnWindowClosing();
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);
+ // Process beforeunload tabs first. When that queue is empty, process
+ // unload tabs.
+ if (!tabs_needing_before_unload_fired_.empty()) {
+ content::WebContents* web_contents =
+ *(tabs_needing_before_unload_fired_.begin());
// 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();
-
- contents->GetRenderViewHost()->FirePageBeforeUnload(false);
+ if (web_contents->GetRenderViewHost()) {
+ web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
} else {
- ProcessPendingTabs();
+ ClearUnloadState(web_contents, true);
}
- return;
- }
-
- // Process all the unload handlers. (The beforeunload handlers have finished.)
- if (!tabs_needing_unload_.empty()) {
- browser_->OnWindowClosing();
-
- // Run unload handlers detached since no more interaction is possible.
- WebContentsSet::iterator it = tabs_needing_unload_.begin();
- while (it != tabs_needing_unload_.end()) {
- WebContentsSet::iterator current = it++;
- content::WebContents* contents = *current;
- tabs_needing_unload_.erase(current);
- // 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()) {
- CoreTabHelper* core_tab_helper =
- CoreTabHelper::FromWebContents(contents);
- core_tab_helper->OnUnloadStarted();
- DetachWebContents(contents);
- contents->GetRenderViewHost()->ClosePage();
- }
- }
-
- // Get the browser hidden.
- if (browser_->tab_strip_model()->empty()) {
- browser_->TabStripEmpty();
- } else {
- browser_->tab_strip_model()->CloseAllTabs(); // tabs not needing unload
- }
- return;
- }
-
- if (HasCompletedUnloadProcessing()) {
- browser_->OnWindowClosing();
-
- // Get the browser closed.
- if (browser_->tab_strip_model()->empty()) {
- browser_->TabStripEmpty();
+ } 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.
+ // 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.
+ content::WebContents* web_contents = *(tabs_needing_unload_fired_.begin());
+ // 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 (web_contents->GetRenderViewHost()) {
+ web_contents->GetRenderViewHost()->ClosePage();
} else {
- // There may be tabs if the last tab needing beforeunload crashed.
- browser_->tab_strip_model()->CloseAllTabs();
+ ClearUnloadState(web_contents, true);
}
- return;
+ } else {
+ NOTREACHED();
}
}
bool UnloadController::HasCompletedUnloadProcessing() const {
return is_attempting_to_close_browser_ &&
- tabs_needing_before_unload_.empty() &&
- tab_needing_before_unload_ack_ == NULL &&
- tabs_needing_unload_.empty() &&
- tabs_needing_unload_ack_.empty();
+ tabs_needing_before_unload_fired_.empty() &&
+ tabs_needing_unload_fired_.empty();
}
void UnloadController::CancelWindowClose() {
// Closing of window can be canceled from a beforeunload handler.
DCHECK(is_attempting_to_close_browser_);
- tabs_needing_before_unload_.clear();
- if (tab_needing_before_unload_ack_ != NULL) {
-
- CoreTabHelper* core_tab_helper =
- CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_);
- core_tab_helper->OnCloseCanceled();
- tab_needing_before_unload_ack_ = NULL;
- }
- for (WebContentsSet::iterator it = tabs_needing_unload_.begin();
- it != tabs_needing_unload_.end(); it++) {
- content::WebContents* contents = *it;
-
- CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
- core_tab_helper->OnCloseCanceled();
- }
- tabs_needing_unload_.clear();
-
- // No need to clear tabs_needing_unload_ack_. Those tabs are already detached.
-
+ tabs_needing_before_unload_fired_.clear();
+ tabs_needing_unload_fired_.clear();
is_attempting_to_close_browser_ = false;
content::NotificationService::current()->Notify(
@@ -345,34 +226,33 @@ void UnloadController::CancelWindowClose() {
content::NotificationService::NoDetails());
}
-void UnloadController::ClearUnloadState(content::WebContents* contents) {
- if (tabs_needing_unload_ack_.erase(contents) > 0) {
- if (HasCompletedUnloadProcessing())
- PostTaskForProcessPendingTabs();
- return;
- }
-
- if (!is_attempting_to_close_browser_)
- return;
-
- if (tab_needing_before_unload_ack_ == contents) {
- tab_needing_before_unload_ack_ = NULL;
- PostTaskForProcessPendingTabs();
- return;
- }
+bool UnloadController::RemoveFromSet(UnloadListenerSet* set,
+ content::WebContents* web_contents) {
+ DCHECK(is_attempting_to_close_browser_);
- if (tabs_needing_before_unload_.erase(contents) > 0 ||
- tabs_needing_unload_.erase(contents) > 0) {
- if (tab_needing_before_unload_ack_ == NULL)
- PostTaskForProcessPendingTabs();
+ UnloadListenerSet::iterator iter =
+ std::find(set->begin(), set->end(), web_contents);
+ if (iter != set->end()) {
+ set->erase(iter);
+ return true;
}
+ return false;
}
-void UnloadController::PostTaskForProcessPendingTabs() {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&UnloadController::ProcessPendingTabs,
- weak_factory_.GetWeakPtr()));
+void UnloadController::ClearUnloadState(content::WebContents* web_contents,
+ bool process_now) {
+ if (is_attempting_to_close_browser_) {
+ RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
+ RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
+ if (process_now) {
+ ProcessPendingTabs();
+ } else {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&UnloadController::ProcessPendingTabs,
+ weak_factory_.GetWeakPtr()));
+ }
+ }
}
} // namespace chrome