| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/ui/unload_controller.h" | 5 #include "chrome/browser/ui/unload_controller.h" | 
| 6 | 6 | 
|  | 7 #include "base/logging.h" | 
| 7 #include "base/message_loop.h" | 8 #include "base/message_loop.h" | 
| 8 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" | 
| 9 #include "chrome/browser/ui/browser_tabstrip.h" | 10 #include "chrome/browser/ui/browser_tabstrip.h" | 
| 10 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 
|  | 12 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" | 
| 11 #include "chrome/common/chrome_notification_types.h" | 13 #include "chrome/common/chrome_notification_types.h" | 
| 12 #include "content/public/browser/notification_service.h" | 14 #include "content/public/browser/notification_service.h" | 
| 13 #include "content/public/browser/notification_source.h" | 15 #include "content/public/browser/notification_source.h" | 
| 14 #include "content/public/browser/notification_types.h" | 16 #include "content/public/browser/notification_types.h" | 
| 15 #include "content/public/browser/render_view_host.h" | 17 #include "content/public/browser/render_view_host.h" | 
| 16 #include "content/public/browser/web_contents.h" | 18 #include "content/public/browser/web_contents.h" | 
|  | 19 #include "content/public/browser/web_contents_delegate.h" | 
| 17 | 20 | 
| 18 namespace chrome { | 21 namespace chrome { | 
| 19 | 22 | 
|  | 23 | 
|  | 24 //////////////////////////////////////////////////////////////////////////////// | 
|  | 25 // DetachedWebContentsDelegate will delete web contents when they close. | 
|  | 26 class UnloadController::DetachedWebContentsDelegate | 
|  | 27     : public content::WebContentsDelegate { | 
|  | 28  public: | 
|  | 29   DetachedWebContentsDelegate() { } | 
|  | 30   virtual ~DetachedWebContentsDelegate() { } | 
|  | 31 | 
|  | 32  private: | 
|  | 33   // WebContentsDelegate implementation. | 
|  | 34   virtual bool ShouldSuppressDialogs() OVERRIDE { | 
|  | 35     return true;  // Return true so dialogs are suppressed. | 
|  | 36   } | 
|  | 37 | 
|  | 38   virtual void CloseContents(content::WebContents* source) OVERRIDE { | 
|  | 39     // Finished detached close. | 
|  | 40     // UnloadController will observe |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|. | 
|  | 41     delete source; | 
|  | 42   } | 
|  | 43 | 
|  | 44   DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate); | 
|  | 45 }; | 
|  | 46 | 
| 20 //////////////////////////////////////////////////////////////////////////////// | 47 //////////////////////////////////////////////////////////////////////////////// | 
| 21 // UnloadController, public: | 48 // UnloadController, public: | 
| 22 | 49 | 
| 23 UnloadController::UnloadController(Browser* browser) | 50 UnloadController::UnloadController(Browser* browser) | 
| 24     : browser_(browser), | 51     : browser_(browser), | 
|  | 52       tab_needing_before_unload_ack_(NULL), | 
| 25       is_attempting_to_close_browser_(false), | 53       is_attempting_to_close_browser_(false), | 
|  | 54       detached_delegate_(new DetachedWebContentsDelegate()), | 
| 26       weak_factory_(this) { | 55       weak_factory_(this) { | 
| 27   browser_->tab_strip_model()->AddObserver(this); | 56   browser_->tab_strip_model()->AddObserver(this); | 
| 28 } | 57 } | 
| 29 | 58 | 
| 30 UnloadController::~UnloadController() { | 59 UnloadController::~UnloadController() { | 
| 31   browser_->tab_strip_model()->RemoveObserver(this); | 60   browser_->tab_strip_model()->RemoveObserver(this); | 
| 32 } | 61 } | 
| 33 | 62 | 
| 34 bool UnloadController::CanCloseContents(content::WebContents* contents) { | 63 bool UnloadController::CanCloseContents(content::WebContents* contents) { | 
| 35   // Don't try to close the tab when the whole browser is being closed, since | 64   // Don't try to close the tab when the whole browser is being closed, since | 
| 36   // that avoids the fast shutdown path where we just kill all the renderers. | 65   // that avoids the fast shutdown path where we just kill all the renderers. | 
| 37   if (is_attempting_to_close_browser_) |  | 
| 38     ClearUnloadState(contents, true); |  | 
| 39   return !is_attempting_to_close_browser_; | 66   return !is_attempting_to_close_browser_; | 
| 40 } | 67 } | 
| 41 | 68 | 
| 42 bool UnloadController::BeforeUnloadFired(content::WebContents* contents, | 69 bool UnloadController::BeforeUnloadFired(content::WebContents* contents, | 
| 43                                          bool proceed) { | 70                                          bool proceed) { | 
| 44   if (!is_attempting_to_close_browser_) { | 71   if (!is_attempting_to_close_browser_) { | 
| 45     if (!proceed) | 72     if (!proceed) { | 
| 46       contents->SetClosedByUserGesture(false); | 73       contents->SetClosedByUserGesture(false); | 
|  | 74     } else { | 
|  | 75       // No more dialogs are possible, so remove the tab and finish | 
|  | 76       // running unload listeners asynchrounously. | 
|  | 77       browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents); | 
|  | 78       DetachWebContents(contents); | 
|  | 79     } | 
| 47     return proceed; | 80     return proceed; | 
| 48   } | 81   } | 
| 49 | 82 | 
| 50   if (!proceed) { | 83   if (!proceed) { | 
| 51     CancelWindowClose(); | 84     CancelWindowClose(); | 
| 52     contents->SetClosedByUserGesture(false); | 85     contents->SetClosedByUserGesture(false); | 
| 53     return false; | 86     return false; | 
| 54   } | 87   } | 
| 55 | 88 | 
| 56   if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) { | 89   if (tab_needing_before_unload_ack_ == contents) { | 
| 57     // Now that beforeunload has fired, put the tab on the queue to fire | 90     // Now that beforeunload has fired, queue the tab to fire unload. | 
| 58     // unload. | 91     tab_needing_before_unload_ack_ = NULL; | 
| 59     tabs_needing_unload_fired_.insert(contents); | 92     tabs_needing_unload_.insert(contents); | 
| 60     ProcessPendingTabs(); | 93     ProcessPendingTabs(); | 
| 61     // We want to handle firing the unload event ourselves since we want to | 94     // We want to handle firing the unload event ourselves since we want to | 
| 62     // fire all the beforeunload events before attempting to fire the unload | 95     // fire all the beforeunload events before attempting to fire the unload | 
| 63     // events should the user cancel closing the browser. | 96     // events should the user cancel closing the browser. | 
| 64     return false; | 97     return false; | 
| 65   } | 98   } | 
| 66 | 99 | 
| 67   return true; | 100   return true; | 
| 68 } | 101 } | 
| 69 | 102 | 
| 70 bool UnloadController::ShouldCloseWindow() { | 103 bool UnloadController::ShouldCloseWindow() { | 
| 71   if (HasCompletedUnloadProcessing()) | 104   if (HasCompletedUnloadProcessing()) | 
| 72     return true; | 105     return true; | 
| 73 | 106 | 
| 74   is_attempting_to_close_browser_ = true; | 107   is_attempting_to_close_browser_ = true; | 
| 75 | 108 | 
| 76   if (!TabsNeedBeforeUnloadFired()) | 109   if (!TabsNeedBeforeUnloadFired()) | 
| 77     return true; | 110     return true; | 
| 78 | 111 | 
| 79   ProcessPendingTabs(); | 112   ProcessPendingTabs(); | 
| 80   return false; | 113   return false; | 
| 81 } | 114 } | 
| 82 | 115 | 
| 83 bool UnloadController::TabsNeedBeforeUnloadFired() { | 116 bool UnloadController::TabsNeedBeforeUnloadFired() { | 
| 84   if (tabs_needing_before_unload_fired_.empty()) { | 117   if (!tabs_needing_before_unload_.empty() || | 
| 85     for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { | 118       tab_needing_before_unload_ack_ != NULL) | 
| 86       content::WebContents* contents = | 119     return true; | 
| 87           browser_->tab_strip_model()->GetWebContentsAt(i); | 120 | 
| 88       if (contents->NeedToFireBeforeUnload()) | 121   if (!tabs_needing_unload_.empty()) | 
| 89         tabs_needing_before_unload_fired_.insert(contents); | 122     return false; | 
| 90     } | 123 | 
|  | 124   for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { | 
|  | 125     content::WebContents* contents = | 
|  | 126         browser_->tab_strip_model()->GetWebContentsAt(i); | 
|  | 127     if (contents->NeedToFireBeforeUnload()) | 
|  | 128       tabs_needing_before_unload_.insert(contents); | 
| 91   } | 129   } | 
| 92   return !tabs_needing_before_unload_fired_.empty(); | 130   return !tabs_needing_before_unload_.empty(); | 
| 93 } | 131 } | 
| 94 | 132 | 
| 95 //////////////////////////////////////////////////////////////////////////////// | 133 //////////////////////////////////////////////////////////////////////////////// | 
| 96 // UnloadController, content::NotificationObserver implementation: | 134 // UnloadController, content::NotificationObserver implementation: | 
| 97 | 135 | 
| 98 void UnloadController::Observe(int type, | 136 void UnloadController::Observe(int type, | 
| 99                                const content::NotificationSource& source, | 137                                const content::NotificationSource& source, | 
| 100                                const content::NotificationDetails& details) { | 138                                const content::NotificationDetails& details) { | 
| 101   switch (type) { | 139   switch (type) { | 
| 102     case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: | 140     case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: { | 
| 103       if (is_attempting_to_close_browser_) { | 141       content::WebContents* contents = | 
| 104         ClearUnloadState(content::Source<content::WebContents>(source).ptr(), | 142           content::Source<content::WebContents>(source).ptr(); | 
| 105                          false);  // See comment for ClearUnloadState(). | 143       registrar_.Remove(this, | 
| 106       } | 144                         content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 
|  | 145                         source); | 
|  | 146       ClearUnloadState(contents); | 
| 107       break; | 147       break; | 
|  | 148     } | 
| 108     default: | 149     default: | 
| 109       NOTREACHED() << "Got a notification we didn't register for."; | 150       NOTREACHED() << "Got a notification we didn't register for."; | 
| 110   } | 151   } | 
| 111 } | 152 } | 
| 112 | 153 | 
| 113 //////////////////////////////////////////////////////////////////////////////// | 154 //////////////////////////////////////////////////////////////////////////////// | 
| 114 // UnloadController, TabStripModelObserver implementation: | 155 // UnloadController, TabStripModelObserver implementation: | 
| 115 | 156 | 
| 116 void UnloadController::TabInsertedAt(content::WebContents* contents, | 157 void UnloadController::TabInsertedAt(content::WebContents* contents, | 
| 117                                      int index, | 158                                      int index, | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 144 void UnloadController::TabAttachedImpl(content::WebContents* contents) { | 185 void UnloadController::TabAttachedImpl(content::WebContents* contents) { | 
| 145   // If the tab crashes in the beforeunload or unload handler, it won't be | 186   // If the tab crashes in the beforeunload or unload handler, it won't be | 
| 146   // able to ack. But we know we can close it. | 187   // able to ack. But we know we can close it. | 
| 147   registrar_.Add( | 188   registrar_.Add( | 
| 148       this, | 189       this, | 
| 149       content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 190       content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 
| 150       content::Source<content::WebContents>(contents)); | 191       content::Source<content::WebContents>(contents)); | 
| 151 } | 192 } | 
| 152 | 193 | 
| 153 void UnloadController::TabDetachedImpl(content::WebContents* contents) { | 194 void UnloadController::TabDetachedImpl(content::WebContents* contents) { | 
| 154   if (is_attempting_to_close_browser_) | 195   if (tabs_needing_unload_ack_.find(contents) != | 
| 155     ClearUnloadState(contents, false); | 196       tabs_needing_unload_ack_.end()) { | 
|  | 197     // Tab needs unload to complete. | 
|  | 198     // It will send |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| when done. | 
|  | 199     return; | 
|  | 200   } | 
|  | 201 | 
| 156   registrar_.Remove(this, | 202   registrar_.Remove(this, | 
| 157                     content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 203                     content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 
| 158                     content::Source<content::WebContents>(contents)); | 204                     content::Source<content::WebContents>(contents)); | 
|  | 205 | 
|  | 206   if (is_attempting_to_close_browser_) | 
|  | 207     ClearUnloadState(contents); | 
|  | 208 } | 
|  | 209 | 
|  | 210 bool UnloadController::DetachWebContents(content::WebContents* contents) { | 
|  | 211   int index = browser_->tab_strip_model()->GetIndexOfWebContents(contents); | 
|  | 212   if (index != TabStripModel::kNoTab && | 
|  | 213       contents->NeedToFireBeforeUnload()) { | 
|  | 214     tabs_needing_unload_ack_.insert(contents); | 
|  | 215     browser_->tab_strip_model()->DetachWebContentsAt(index); | 
|  | 216     contents->SetDelegate(detached_delegate_.get()); | 
|  | 217     contents->OnUnloadDetachedStarted(); | 
|  | 218     return true; | 
|  | 219   } | 
|  | 220   return false; | 
| 159 } | 221 } | 
| 160 | 222 | 
| 161 void UnloadController::ProcessPendingTabs() { | 223 void UnloadController::ProcessPendingTabs() { | 
| 162   if (!is_attempting_to_close_browser_) { | 224   if (!is_attempting_to_close_browser_) { | 
| 163     // Because we might invoke this after a delay it's possible for the value of | 225     // Because we might invoke this after a delay it's possible for the value of | 
| 164     // is_attempting_to_close_browser_ to have changed since we scheduled the | 226     // is_attempting_to_close_browser_ to have changed since we scheduled the | 
| 165     // task. | 227     // task. | 
| 166     return; | 228     return; | 
| 167   } | 229   } | 
| 168 | 230 | 
|  | 231   if (tab_needing_before_unload_ack_ != NULL) { | 
|  | 232     // Wait for |BeforeUnloadFired| before proceeding. | 
|  | 233     return; | 
|  | 234   } | 
|  | 235 | 
|  | 236   // Process a beforeunload handler. | 
|  | 237   if (!tabs_needing_before_unload_.empty()) { | 
|  | 238     WebContentsSet::iterator it = tabs_needing_before_unload_.begin(); | 
|  | 239     content::WebContents* contents = *it; | 
|  | 240     tabs_needing_before_unload_.erase(it); | 
|  | 241     // Null check render_view_host here as this gets called on a PostTask and | 
|  | 242     // the tab's render_view_host may have been nulled out. | 
|  | 243     if (contents->GetRenderViewHost()) { | 
|  | 244       tab_needing_before_unload_ack_ = contents; | 
|  | 245       contents->OnCloseStarted(); | 
|  | 246       contents->GetRenderViewHost()->FirePageBeforeUnload(false); | 
|  | 247     } else { | 
|  | 248       ProcessPendingTabs(); | 
|  | 249     } | 
|  | 250     return; | 
|  | 251   } | 
|  | 252 | 
|  | 253   // Process all the unload handlers. (The beforeunload handlers have finished.) | 
|  | 254   if (!tabs_needing_unload_.empty()) { | 
|  | 255     browser_->OnWindowClosing(); | 
|  | 256 | 
|  | 257     // Run unload handlers detached since no more interaction is possible. | 
|  | 258     WebContentsSet::iterator it = tabs_needing_unload_.begin(); | 
|  | 259     while (it != tabs_needing_unload_.end()) { | 
|  | 260       WebContentsSet::iterator current = it++; | 
|  | 261       content::WebContents* contents = *current; | 
|  | 262       tabs_needing_unload_.erase(current); | 
|  | 263       // Null check render_view_host here as this gets called on a PostTask | 
|  | 264       // and the tab's render_view_host may have been nulled out. | 
|  | 265       if (contents->GetRenderViewHost()) { | 
|  | 266         contents->OnUnloadStarted(); | 
|  | 267         DetachWebContents(contents); | 
|  | 268         contents->GetRenderViewHost()->ClosePage(); | 
|  | 269       } | 
|  | 270     } | 
|  | 271 | 
|  | 272     // Get the browser hidden. | 
|  | 273     if (browser_->tab_strip_model()->empty()) { | 
|  | 274       browser_->TabStripEmpty(); | 
|  | 275     } else { | 
|  | 276       browser_->tab_strip_model()->CloseAllTabs();  // tabs not needing unload | 
|  | 277     } | 
|  | 278     return; | 
|  | 279   } | 
|  | 280 | 
| 169   if (HasCompletedUnloadProcessing()) { | 281   if (HasCompletedUnloadProcessing()) { | 
| 170     // We've finished all the unload events and can proceed to close the |  | 
| 171     // browser. |  | 
| 172     browser_->OnWindowClosing(); | 282     browser_->OnWindowClosing(); | 
|  | 283 | 
|  | 284     // Get the browser closed. | 
|  | 285     if (browser_->tab_strip_model()->empty()) { | 
|  | 286       browser_->TabStripEmpty(); | 
|  | 287     } else { | 
|  | 288       // There may be tabs if the last tab needing beforeunload crashed. | 
|  | 289       browser_->tab_strip_model()->CloseAllTabs(); | 
|  | 290     } | 
| 173     return; | 291     return; | 
| 174   } | 292   } | 
| 175 |  | 
| 176   // Process beforeunload tabs first. When that queue is empty, process |  | 
| 177   // unload tabs. |  | 
| 178   if (!tabs_needing_before_unload_fired_.empty()) { |  | 
| 179     content::WebContents* web_contents = |  | 
| 180         *(tabs_needing_before_unload_fired_.begin()); |  | 
| 181     // Null check render_view_host here as this gets called on a PostTask and |  | 
| 182     // the tab's render_view_host may have been nulled out. |  | 
| 183     if (web_contents->GetRenderViewHost()) { |  | 
| 184       web_contents->GetRenderViewHost()->FirePageBeforeUnload(false); |  | 
| 185     } else { |  | 
| 186       ClearUnloadState(web_contents, true); |  | 
| 187     } |  | 
| 188   } else if (!tabs_needing_unload_fired_.empty()) { |  | 
| 189     // We've finished firing all beforeunload events and can proceed with unload |  | 
| 190     // events. |  | 
| 191     // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting |  | 
| 192     // somewhere around here so that we have accurate measurements of shutdown |  | 
| 193     // time. |  | 
| 194     // TODO(ojan): We can probably fire all the unload events in parallel and |  | 
| 195     // get a perf benefit from that in the cases where the tab hangs in it's |  | 
| 196     // unload handler or takes a long time to page in. |  | 
| 197     content::WebContents* web_contents = *(tabs_needing_unload_fired_.begin()); |  | 
| 198     // Null check render_view_host here as this gets called on a PostTask and |  | 
| 199     // the tab's render_view_host may have been nulled out. |  | 
| 200     if (web_contents->GetRenderViewHost()) { |  | 
| 201       web_contents->GetRenderViewHost()->ClosePage(); |  | 
| 202     } else { |  | 
| 203       ClearUnloadState(web_contents, true); |  | 
| 204     } |  | 
| 205   } else { |  | 
| 206     NOTREACHED(); |  | 
| 207   } |  | 
| 208 } | 293 } | 
| 209 | 294 | 
| 210 bool UnloadController::HasCompletedUnloadProcessing() const { | 295 bool UnloadController::HasCompletedUnloadProcessing() const { | 
| 211   return is_attempting_to_close_browser_ && | 296   return is_attempting_to_close_browser_ && | 
| 212       tabs_needing_before_unload_fired_.empty() && | 297       tabs_needing_before_unload_.empty() && | 
| 213       tabs_needing_unload_fired_.empty(); | 298       tab_needing_before_unload_ack_ == NULL && | 
|  | 299       tabs_needing_unload_.empty() && | 
|  | 300       tabs_needing_unload_ack_.empty(); | 
| 214 } | 301 } | 
| 215 | 302 | 
| 216 void UnloadController::CancelWindowClose() { | 303 void UnloadController::CancelWindowClose() { | 
| 217   // Closing of window can be canceled from a beforeunload handler. | 304   // Closing of window can be canceled from a beforeunload handler. | 
| 218   DCHECK(is_attempting_to_close_browser_); | 305   DCHECK(is_attempting_to_close_browser_); | 
| 219   tabs_needing_before_unload_fired_.clear(); | 306   tabs_needing_before_unload_.clear(); | 
| 220   tabs_needing_unload_fired_.clear(); | 307   if (tab_needing_before_unload_ack_ != NULL) { | 
|  | 308     tab_needing_before_unload_ack_->OnCloseCanceled(); | 
|  | 309     tab_needing_before_unload_ack_ = NULL; | 
|  | 310   } | 
|  | 311   for (WebContentsSet::iterator it = tabs_needing_unload_.begin(); | 
|  | 312        it != tabs_needing_unload_.end(); it++) { | 
|  | 313     content::WebContents* contents = *it; | 
|  | 314     contents->OnCloseCanceled(); | 
|  | 315   } | 
|  | 316   tabs_needing_unload_.clear(); | 
|  | 317 | 
|  | 318   // No need to clear tabs_needing_unload_ack_. Those tabs are already detached. | 
|  | 319 | 
| 221   is_attempting_to_close_browser_ = false; | 320   is_attempting_to_close_browser_ = false; | 
| 222 | 321 | 
| 223   content::NotificationService::current()->Notify( | 322   content::NotificationService::current()->Notify( | 
| 224       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, | 323       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, | 
| 225       content::Source<Browser>(browser_), | 324       content::Source<Browser>(browser_), | 
| 226       content::NotificationService::NoDetails()); | 325       content::NotificationService::NoDetails()); | 
| 227 } | 326 } | 
| 228 | 327 | 
| 229 bool UnloadController::RemoveFromSet(UnloadListenerSet* set, | 328 void UnloadController::ClearUnloadState(content::WebContents* contents) { | 
| 230                                      content::WebContents* web_contents) { | 329   if (tabs_needing_unload_ack_.erase(contents) > 0) { | 
| 231   DCHECK(is_attempting_to_close_browser_); | 330     if (HasCompletedUnloadProcessing()) | 
|  | 331       PostTaskForProcessPendingTabs(); | 
|  | 332     return; | 
|  | 333   } | 
| 232 | 334 | 
| 233   UnloadListenerSet::iterator iter = | 335   if (!is_attempting_to_close_browser_) | 
| 234       std::find(set->begin(), set->end(), web_contents); | 336     return; | 
| 235   if (iter != set->end()) { | 337 | 
| 236     set->erase(iter); | 338   if (tab_needing_before_unload_ack_ == contents) { | 
| 237     return true; | 339     tab_needing_before_unload_ack_ = NULL; | 
|  | 340     PostTaskForProcessPendingTabs(); | 
|  | 341     return; | 
| 238   } | 342   } | 
| 239   return false; |  | 
| 240 } |  | 
| 241 | 343 | 
| 242 void UnloadController::ClearUnloadState(content::WebContents* web_contents, | 344   if (tabs_needing_before_unload_.erase(contents) > 0 || | 
| 243                                         bool process_now) { | 345       tabs_needing_unload_.erase(contents) > 0) { | 
| 244   if (is_attempting_to_close_browser_) { | 346     if (tab_needing_before_unload_ack_ == NULL) | 
| 245     RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents); | 347       PostTaskForProcessPendingTabs(); | 
| 246     RemoveFromSet(&tabs_needing_unload_fired_, web_contents); |  | 
| 247     if (process_now) { |  | 
| 248       ProcessPendingTabs(); |  | 
| 249     } else { |  | 
| 250       base::MessageLoop::current()->PostTask( |  | 
| 251           FROM_HERE, |  | 
| 252           base::Bind(&UnloadController::ProcessPendingTabs, |  | 
| 253                      weak_factory_.GetWeakPtr())); |  | 
| 254     } |  | 
| 255   } | 348   } | 
| 256 } | 349 } | 
| 257 | 350 | 
|  | 351 void UnloadController::PostTaskForProcessPendingTabs() { | 
|  | 352   base::MessageLoop::current()->PostTask( | 
|  | 353       FROM_HERE, | 
|  | 354       base::Bind(&UnloadController::ProcessPendingTabs, | 
|  | 355                  weak_factory_.GetWeakPtr())); | 
|  | 356 } | 
|  | 357 | 
| 258 }  // namespace chrome | 358 }  // namespace chrome | 
| OLD | NEW | 
|---|