diff options
author | jeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 05:16:44 +0000 |
---|---|---|
committer | jeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 05:16:44 +0000 |
commit | ed1bb720731ea7c7644c208da970f0609a7e3b62 (patch) | |
tree | 5d66f86a406225f13f3c87485db4e2dbdde688b0 /chrome/browser/ui/unload_controller.cc | |
parent | 8dc0d4052bbc6e023577e372679d471da9717236 (diff) | |
download | chromium_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.cc | 280 |
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 |