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/fast_unload_controller.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
10 #include "chrome/browser/ui/browser_tabstrip.h" | 10 #include "chrome/browser/ui/browser_tabstrip.h" |
11 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" | 11 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" |
12 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 12 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
13 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" | 13 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" |
14 #include "chrome/common/chrome_notification_types.h" | 14 #include "chrome/common/chrome_notification_types.h" |
15 #include "content/public/browser/notification_service.h" | 15 #include "content/public/browser/notification_service.h" |
16 #include "content/public/browser/notification_source.h" | 16 #include "content/public/browser/notification_source.h" |
17 #include "content/public/browser/notification_types.h" | 17 #include "content/public/browser/notification_types.h" |
18 #include "content/public/browser/render_view_host.h" | 18 #include "content/public/browser/render_view_host.h" |
19 #include "content/public/browser/web_contents.h" | 19 #include "content/public/browser/web_contents.h" |
20 #include "content/public/browser/web_contents_delegate.h" | 20 #include "content/public/browser/web_contents_delegate.h" |
21 | 21 |
22 namespace chrome { | 22 namespace chrome { |
23 | 23 |
24 | 24 |
25 //////////////////////////////////////////////////////////////////////////////// | 25 //////////////////////////////////////////////////////////////////////////////// |
26 // DetachedWebContentsDelegate will delete web contents when they close. | 26 // DetachedWebContentsDelegate will delete web contents when they close. |
27 class UnloadController::DetachedWebContentsDelegate | 27 class FastUnloadController::DetachedWebContentsDelegate |
28 : public content::WebContentsDelegate { | 28 : public content::WebContentsDelegate { |
29 public: | 29 public: |
30 DetachedWebContentsDelegate() { } | 30 DetachedWebContentsDelegate() { } |
31 virtual ~DetachedWebContentsDelegate() { } | 31 virtual ~DetachedWebContentsDelegate() { } |
32 | 32 |
33 private: | 33 private: |
34 // WebContentsDelegate implementation. | 34 // WebContentsDelegate implementation. |
35 virtual bool ShouldSuppressDialogs() OVERRIDE { | 35 virtual bool ShouldSuppressDialogs() OVERRIDE { |
36 return true; // Return true so dialogs are suppressed. | 36 return true; // Return true so dialogs are suppressed. |
37 } | 37 } |
38 | 38 |
39 virtual void CloseContents(content::WebContents* source) OVERRIDE { | 39 virtual void CloseContents(content::WebContents* source) OVERRIDE { |
40 // Finished detached close. | 40 // Finished detached close. |
41 // UnloadController will observe | 41 // FastUnloadController will observe |
42 // |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|. | 42 // |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|. |
43 delete source; | 43 delete source; |
44 } | 44 } |
45 | 45 |
46 DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate); | 46 DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate); |
47 }; | 47 }; |
48 | 48 |
49 //////////////////////////////////////////////////////////////////////////////// | 49 //////////////////////////////////////////////////////////////////////////////// |
50 // UnloadController, public: | 50 // FastUnloadController, public: |
51 | 51 |
52 UnloadController::UnloadController(Browser* browser) | 52 FastUnloadController::FastUnloadController(Browser* browser) |
53 : browser_(browser), | 53 : browser_(browser), |
54 tab_needing_before_unload_ack_(NULL), | 54 tab_needing_before_unload_ack_(NULL), |
55 is_attempting_to_close_browser_(false), | 55 is_attempting_to_close_browser_(false), |
56 detached_delegate_(new DetachedWebContentsDelegate()), | 56 detached_delegate_(new DetachedWebContentsDelegate()), |
57 weak_factory_(this) { | 57 weak_factory_(this) { |
58 browser_->tab_strip_model()->AddObserver(this); | 58 browser_->tab_strip_model()->AddObserver(this); |
59 } | 59 } |
60 | 60 |
61 UnloadController::~UnloadController() { | 61 FastUnloadController::~FastUnloadController() { |
62 browser_->tab_strip_model()->RemoveObserver(this); | 62 browser_->tab_strip_model()->RemoveObserver(this); |
63 } | 63 } |
64 | 64 |
65 bool UnloadController::CanCloseContents(content::WebContents* contents) { | 65 bool FastUnloadController::CanCloseContents(content::WebContents* contents) { |
66 // Don't try to close the tab when the whole browser is being closed, since | 66 // Don't try to close the tab when the whole browser is being closed, since |
67 // that avoids the fast shutdown path where we just kill all the renderers. | 67 // that avoids the fast shutdown path where we just kill all the renderers. |
68 return !is_attempting_to_close_browser_; | 68 return !is_attempting_to_close_browser_; |
69 } | 69 } |
70 | 70 |
71 bool UnloadController::BeforeUnloadFired(content::WebContents* contents, | 71 bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents, |
72 bool proceed) { | 72 bool proceed) { |
73 if (!is_attempting_to_close_browser_) { | 73 if (!is_attempting_to_close_browser_) { |
74 if (!proceed) { | 74 if (!proceed) { |
75 contents->SetClosedByUserGesture(false); | 75 contents->SetClosedByUserGesture(false); |
76 } else { | 76 } else { |
77 // No more dialogs are possible, so remove the tab and finish | 77 // No more dialogs are possible, so remove the tab and finish |
78 // running unload listeners asynchrounously. | 78 // running unload listeners asynchrounously. |
79 browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents); | 79 browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents); |
80 DetachWebContents(contents); | 80 DetachWebContents(contents); |
81 } | 81 } |
82 return proceed; | 82 return proceed; |
(...skipping 12 matching lines...) Expand all Loading... |
95 ProcessPendingTabs(); | 95 ProcessPendingTabs(); |
96 // We want to handle firing the unload event ourselves since we want to | 96 // We want to handle firing the unload event ourselves since we want to |
97 // fire all the beforeunload events before attempting to fire the unload | 97 // fire all the beforeunload events before attempting to fire the unload |
98 // events should the user cancel closing the browser. | 98 // events should the user cancel closing the browser. |
99 return false; | 99 return false; |
100 } | 100 } |
101 | 101 |
102 return true; | 102 return true; |
103 } | 103 } |
104 | 104 |
105 bool UnloadController::ShouldCloseWindow() { | 105 bool FastUnloadController::ShouldCloseWindow() { |
106 if (HasCompletedUnloadProcessing()) | 106 if (HasCompletedUnloadProcessing()) |
107 return true; | 107 return true; |
108 | 108 |
109 is_attempting_to_close_browser_ = true; | 109 is_attempting_to_close_browser_ = true; |
110 | 110 |
111 if (!TabsNeedBeforeUnloadFired()) | 111 if (!TabsNeedBeforeUnloadFired()) |
112 return true; | 112 return true; |
113 | 113 |
114 ProcessPendingTabs(); | 114 ProcessPendingTabs(); |
115 return false; | 115 return false; |
116 } | 116 } |
117 | 117 |
118 bool UnloadController::TabsNeedBeforeUnloadFired() { | 118 bool FastUnloadController::TabsNeedBeforeUnloadFired() { |
119 if (!tabs_needing_before_unload_.empty() || | 119 if (!tabs_needing_before_unload_.empty() || |
120 tab_needing_before_unload_ack_ != NULL) | 120 tab_needing_before_unload_ack_ != NULL) |
121 return true; | 121 return true; |
122 | 122 |
123 if (!tabs_needing_unload_.empty()) | 123 if (!tabs_needing_unload_.empty()) |
124 return false; | 124 return false; |
125 | 125 |
126 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { | 126 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { |
127 content::WebContents* contents = | 127 content::WebContents* contents = |
128 browser_->tab_strip_model()->GetWebContentsAt(i); | 128 browser_->tab_strip_model()->GetWebContentsAt(i); |
129 if (contents->NeedToFireBeforeUnload()) | 129 if (contents->NeedToFireBeforeUnload()) |
130 tabs_needing_before_unload_.insert(contents); | 130 tabs_needing_before_unload_.insert(contents); |
131 } | 131 } |
132 return !tabs_needing_before_unload_.empty(); | 132 return !tabs_needing_before_unload_.empty(); |
133 } | 133 } |
134 | 134 |
135 //////////////////////////////////////////////////////////////////////////////// | 135 //////////////////////////////////////////////////////////////////////////////// |
136 // UnloadController, content::NotificationObserver implementation: | 136 // FastUnloadController, content::NotificationObserver implementation: |
137 | 137 |
138 void UnloadController::Observe(int type, | 138 void FastUnloadController::Observe( |
139 const content::NotificationSource& source, | 139 int type, |
140 const content::NotificationDetails& details) { | 140 const content::NotificationSource& source, |
| 141 const content::NotificationDetails& details) { |
141 switch (type) { | 142 switch (type) { |
142 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: { | 143 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: { |
143 registrar_.Remove(this, | 144 registrar_.Remove(this, |
144 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 145 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, |
145 source); | 146 source); |
146 content::WebContents* contents = | 147 content::WebContents* contents = |
147 content::Source<content::WebContents>(source).ptr(); | 148 content::Source<content::WebContents>(source).ptr(); |
148 ClearUnloadState(contents); | 149 ClearUnloadState(contents); |
149 break; | 150 break; |
150 } | 151 } |
151 default: | 152 default: |
152 NOTREACHED() << "Got a notification we didn't register for."; | 153 NOTREACHED() << "Got a notification we didn't register for."; |
153 } | 154 } |
154 } | 155 } |
155 | 156 |
156 //////////////////////////////////////////////////////////////////////////////// | 157 //////////////////////////////////////////////////////////////////////////////// |
157 // UnloadController, TabStripModelObserver implementation: | 158 // FastUnloadController, TabStripModelObserver implementation: |
158 | 159 |
159 void UnloadController::TabInsertedAt(content::WebContents* contents, | 160 void FastUnloadController::TabInsertedAt(content::WebContents* contents, |
160 int index, | 161 int index, |
161 bool foreground) { | 162 bool foreground) { |
162 TabAttachedImpl(contents); | 163 TabAttachedImpl(contents); |
163 } | 164 } |
164 | 165 |
165 void UnloadController::TabDetachedAt(content::WebContents* contents, | 166 void FastUnloadController::TabDetachedAt(content::WebContents* contents, |
166 int index) { | 167 int index) { |
167 TabDetachedImpl(contents); | 168 TabDetachedImpl(contents); |
168 } | 169 } |
169 | 170 |
170 void UnloadController::TabReplacedAt(TabStripModel* tab_strip_model, | 171 void FastUnloadController::TabReplacedAt(TabStripModel* tab_strip_model, |
171 content::WebContents* old_contents, | 172 content::WebContents* old_contents, |
172 content::WebContents* new_contents, | 173 content::WebContents* new_contents, |
173 int index) { | 174 int index) { |
174 TabDetachedImpl(old_contents); | 175 TabDetachedImpl(old_contents); |
175 TabAttachedImpl(new_contents); | 176 TabAttachedImpl(new_contents); |
176 } | 177 } |
177 | 178 |
178 void UnloadController::TabStripEmpty() { | 179 void FastUnloadController::TabStripEmpty() { |
179 // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not | 180 // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not |
180 // attempt to add tabs to the browser before it closes. | 181 // attempt to add tabs to the browser before it closes. |
181 is_attempting_to_close_browser_ = true; | 182 is_attempting_to_close_browser_ = true; |
182 } | 183 } |
183 | 184 |
184 //////////////////////////////////////////////////////////////////////////////// | 185 //////////////////////////////////////////////////////////////////////////////// |
185 // UnloadController, private: | 186 // FastUnloadController, private: |
186 | 187 |
187 void UnloadController::TabAttachedImpl(content::WebContents* contents) { | 188 void FastUnloadController::TabAttachedImpl(content::WebContents* contents) { |
188 // If the tab crashes in the beforeunload or unload handler, it won't be | 189 // If the tab crashes in the beforeunload or unload handler, it won't be |
189 // able to ack. But we know we can close it. | 190 // able to ack. But we know we can close it. |
190 registrar_.Add( | 191 registrar_.Add( |
191 this, | 192 this, |
192 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 193 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, |
193 content::Source<content::WebContents>(contents)); | 194 content::Source<content::WebContents>(contents)); |
194 } | 195 } |
195 | 196 |
196 void UnloadController::TabDetachedImpl(content::WebContents* contents) { | 197 void FastUnloadController::TabDetachedImpl(content::WebContents* contents) { |
197 if (tabs_needing_unload_ack_.find(contents) != | 198 if (tabs_needing_unload_ack_.find(contents) != |
198 tabs_needing_unload_ack_.end()) { | 199 tabs_needing_unload_ack_.end()) { |
199 // Tab needs unload to complete. | 200 // Tab needs unload to complete. |
200 // It will send |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| when done. | 201 // It will send |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| when done. |
201 return; | 202 return; |
202 } | 203 } |
203 | 204 |
204 // If WEB_CONTENTS_DISCONNECTED was received then the notification may have | 205 // If WEB_CONTENTS_DISCONNECTED was received then the notification may have |
205 // already been unregistered. | 206 // already been unregistered. |
206 const content::NotificationSource& source = | 207 const content::NotificationSource& source = |
207 content::Source<content::WebContents>(contents); | 208 content::Source<content::WebContents>(contents); |
208 if (registrar_.IsRegistered(this, | 209 if (registrar_.IsRegistered(this, |
209 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 210 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, |
210 source)) { | 211 source)) { |
211 registrar_.Remove(this, | 212 registrar_.Remove(this, |
212 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 213 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, |
213 source); | 214 source); |
214 } | 215 } |
215 | 216 |
216 if (is_attempting_to_close_browser_) | 217 if (is_attempting_to_close_browser_) |
217 ClearUnloadState(contents); | 218 ClearUnloadState(contents); |
218 } | 219 } |
219 | 220 |
220 bool UnloadController::DetachWebContents(content::WebContents* contents) { | 221 bool FastUnloadController::DetachWebContents(content::WebContents* contents) { |
221 int index = browser_->tab_strip_model()->GetIndexOfWebContents(contents); | 222 int index = browser_->tab_strip_model()->GetIndexOfWebContents(contents); |
222 if (index != TabStripModel::kNoTab && | 223 if (index != TabStripModel::kNoTab && |
223 contents->NeedToFireBeforeUnload()) { | 224 contents->NeedToFireBeforeUnload()) { |
224 tabs_needing_unload_ack_.insert(contents); | 225 tabs_needing_unload_ack_.insert(contents); |
225 browser_->tab_strip_model()->DetachWebContentsAt(index); | 226 browser_->tab_strip_model()->DetachWebContentsAt(index); |
226 contents->SetDelegate(detached_delegate_.get()); | 227 contents->SetDelegate(detached_delegate_.get()); |
227 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); | 228 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); |
228 core_tab_helper->OnUnloadDetachedStarted(); | 229 core_tab_helper->OnUnloadDetachedStarted(); |
229 return true; | 230 return true; |
230 } | 231 } |
231 return false; | 232 return false; |
232 } | 233 } |
233 | 234 |
234 void UnloadController::ProcessPendingTabs() { | 235 void FastUnloadController::ProcessPendingTabs() { |
235 if (!is_attempting_to_close_browser_) { | 236 if (!is_attempting_to_close_browser_) { |
236 // Because we might invoke this after a delay it's possible for the value of | 237 // Because we might invoke this after a delay it's possible for the value of |
237 // is_attempting_to_close_browser_ to have changed since we scheduled the | 238 // is_attempting_to_close_browser_ to have changed since we scheduled the |
238 // task. | 239 // task. |
239 return; | 240 return; |
240 } | 241 } |
241 | 242 |
242 if (tab_needing_before_unload_ack_ != NULL) { | 243 if (tab_needing_before_unload_ack_ != NULL) { |
243 // Wait for |BeforeUnloadFired| before proceeding. | 244 // Wait for |BeforeUnloadFired| before proceeding. |
244 return; | 245 return; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 if (browser_->tab_strip_model()->empty()) { | 302 if (browser_->tab_strip_model()->empty()) { |
302 browser_->TabStripEmpty(); | 303 browser_->TabStripEmpty(); |
303 } else { | 304 } else { |
304 // There may be tabs if the last tab needing beforeunload crashed. | 305 // There may be tabs if the last tab needing beforeunload crashed. |
305 browser_->tab_strip_model()->CloseAllTabs(); | 306 browser_->tab_strip_model()->CloseAllTabs(); |
306 } | 307 } |
307 return; | 308 return; |
308 } | 309 } |
309 } | 310 } |
310 | 311 |
311 bool UnloadController::HasCompletedUnloadProcessing() const { | 312 bool FastUnloadController::HasCompletedUnloadProcessing() const { |
312 return is_attempting_to_close_browser_ && | 313 return is_attempting_to_close_browser_ && |
313 tabs_needing_before_unload_.empty() && | 314 tabs_needing_before_unload_.empty() && |
314 tab_needing_before_unload_ack_ == NULL && | 315 tab_needing_before_unload_ack_ == NULL && |
315 tabs_needing_unload_.empty() && | 316 tabs_needing_unload_.empty() && |
316 tabs_needing_unload_ack_.empty(); | 317 tabs_needing_unload_ack_.empty(); |
317 } | 318 } |
318 | 319 |
319 void UnloadController::CancelWindowClose() { | 320 void FastUnloadController::CancelWindowClose() { |
320 // Closing of window can be canceled from a beforeunload handler. | 321 // Closing of window can be canceled from a beforeunload handler. |
321 DCHECK(is_attempting_to_close_browser_); | 322 DCHECK(is_attempting_to_close_browser_); |
322 tabs_needing_before_unload_.clear(); | 323 tabs_needing_before_unload_.clear(); |
323 if (tab_needing_before_unload_ack_ != NULL) { | 324 if (tab_needing_before_unload_ack_ != NULL) { |
324 | 325 |
325 CoreTabHelper* core_tab_helper = | 326 CoreTabHelper* core_tab_helper = |
326 CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_); | 327 CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_); |
327 core_tab_helper->OnCloseCanceled(); | 328 core_tab_helper->OnCloseCanceled(); |
328 tab_needing_before_unload_ack_ = NULL; | 329 tab_needing_before_unload_ack_ = NULL; |
329 } | 330 } |
330 for (WebContentsSet::iterator it = tabs_needing_unload_.begin(); | 331 for (WebContentsSet::iterator it = tabs_needing_unload_.begin(); |
331 it != tabs_needing_unload_.end(); it++) { | 332 it != tabs_needing_unload_.end(); it++) { |
332 content::WebContents* contents = *it; | 333 content::WebContents* contents = *it; |
333 | 334 |
334 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); | 335 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); |
335 core_tab_helper->OnCloseCanceled(); | 336 core_tab_helper->OnCloseCanceled(); |
336 } | 337 } |
337 tabs_needing_unload_.clear(); | 338 tabs_needing_unload_.clear(); |
338 | 339 |
339 // No need to clear tabs_needing_unload_ack_. Those tabs are already detached. | 340 // No need to clear tabs_needing_unload_ack_. Those tabs are already detached. |
340 | 341 |
341 is_attempting_to_close_browser_ = false; | 342 is_attempting_to_close_browser_ = false; |
342 | 343 |
343 content::NotificationService::current()->Notify( | 344 content::NotificationService::current()->Notify( |
344 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, | 345 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, |
345 content::Source<Browser>(browser_), | 346 content::Source<Browser>(browser_), |
346 content::NotificationService::NoDetails()); | 347 content::NotificationService::NoDetails()); |
347 } | 348 } |
348 | 349 |
349 void UnloadController::ClearUnloadState(content::WebContents* contents) { | 350 void FastUnloadController::ClearUnloadState(content::WebContents* contents) { |
350 if (tabs_needing_unload_ack_.erase(contents) > 0) { | 351 if (tabs_needing_unload_ack_.erase(contents) > 0) { |
351 if (HasCompletedUnloadProcessing()) | 352 if (HasCompletedUnloadProcessing()) |
352 PostTaskForProcessPendingTabs(); | 353 PostTaskForProcessPendingTabs(); |
353 return; | 354 return; |
354 } | 355 } |
355 | 356 |
356 if (!is_attempting_to_close_browser_) | 357 if (!is_attempting_to_close_browser_) |
357 return; | 358 return; |
358 | 359 |
359 if (tab_needing_before_unload_ack_ == contents) { | 360 if (tab_needing_before_unload_ack_ == contents) { |
360 tab_needing_before_unload_ack_ = NULL; | 361 tab_needing_before_unload_ack_ = NULL; |
361 PostTaskForProcessPendingTabs(); | 362 PostTaskForProcessPendingTabs(); |
362 return; | 363 return; |
363 } | 364 } |
364 | 365 |
365 if (tabs_needing_before_unload_.erase(contents) > 0 || | 366 if (tabs_needing_before_unload_.erase(contents) > 0 || |
366 tabs_needing_unload_.erase(contents) > 0) { | 367 tabs_needing_unload_.erase(contents) > 0) { |
367 if (tab_needing_before_unload_ack_ == NULL) | 368 if (tab_needing_before_unload_ack_ == NULL) |
368 PostTaskForProcessPendingTabs(); | 369 PostTaskForProcessPendingTabs(); |
369 } | 370 } |
370 } | 371 } |
371 | 372 |
372 void UnloadController::PostTaskForProcessPendingTabs() { | 373 void FastUnloadController::PostTaskForProcessPendingTabs() { |
373 base::MessageLoop::current()->PostTask( | 374 base::MessageLoop::current()->PostTask( |
374 FROM_HERE, | 375 FROM_HERE, |
375 base::Bind(&UnloadController::ProcessPendingTabs, | 376 base::Bind(&FastUnloadController::ProcessPendingTabs, |
376 weak_factory_.GetWeakPtr())); | 377 weak_factory_.GetWeakPtr())); |
377 } | 378 } |
378 | 379 |
379 } // namespace chrome | 380 } // namespace chrome |
OLD | NEW |