Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(739)

Side by Side Diff: chrome/browser/sessions/tab_loader.cc

Issue 1052733002: Decouple TabLoader from SessionRestore. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/sessions/tab_loader.h" 5 #include "chrome/browser/sessions/tab_loader.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_finder.h" 13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h" 14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "content/public/browser/navigation_controller.h" 15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/notification_service.h" 16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/notification_types.h" 17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_widget_host.h" 18 #include "content/public/browser/render_widget_host.h"
19 #include "content/public/browser/render_widget_host_view.h" 19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/web_contents.h" 20 #include "content/public/browser/web_contents.h"
21 21
22 using content::NavigationController; 22 using content::NavigationController;
23 using content::RenderWidgetHost; 23 using content::RenderWidgetHost;
24 using content::WebContents; 24 using content::WebContents;
25 25
26 // static
27 TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) {
28 if (!shared_tab_loader_)
29 shared_tab_loader_ = new TabLoader(restore_started);
30 return shared_tab_loader_;
31 }
32
33 void TabLoader::ScheduleLoad(NavigationController* controller) {
34 CheckNotObserving(controller);
35 DCHECK(controller);
36 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
37 tabs_to_load_.end());
38 tabs_to_load_.push_back(controller);
39 RegisterForNotifications(controller);
40 }
41
42 void TabLoader::TabIsLoading(NavigationController* controller) {
43 CheckNotObserving(controller);
44 DCHECK(controller);
45 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
46 tabs_loading_.end());
47 tabs_loading_.insert(controller);
48 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
49 DCHECK(render_widget_host);
50 render_widget_hosts_loading_.insert(render_widget_host);
51 RegisterForNotifications(controller);
52 }
53
54 void TabLoader::StartLoading() {
55 // When multiple profiles are using the same TabLoader, another profile might
56 // already have started loading. In that case, the tabs scheduled for loading
57 // by this profile are already in the loading queue, and they will get loaded
58 // eventually.
59 if (delegate_)
60 return;
61
62 registrar_.Add(
63 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
64 content::NotificationService::AllSources());
65 this_retainer_ = this;
66 // Create a TabLoaderDelegate which will allow OS specific behavior for tab
67 // loading.
68 if (!delegate_) {
69 delegate_ = TabLoaderDelegate::Create(this);
70 // There is already at least one tab loading (the active tab). As such we
71 // only have to start the timeout timer here.
72 StartTimer();
73 }
74 }
75
76 void TabLoader::SetTabLoadingEnabled(bool enable_tab_loading) {
77 if (enable_tab_loading == loading_enabled_)
78 return;
79 loading_enabled_ = enable_tab_loading;
80 if (loading_enabled_)
81 LoadNextTab();
82 else
83 force_load_timer_.Stop();
84 }
85
86 TabLoader::TabLoader(base::TimeTicks restore_started)
87 : memory_pressure_listener_(
88 base::Bind(&TabLoader::OnMemoryPressure, base::Unretained(this))),
89 force_load_delay_multiplier_(1),
90 loading_enabled_(true),
91 got_first_foreground_load_(false),
92 got_first_paint_(false),
93 tab_count_(0),
94 restore_started_(restore_started),
95 max_parallel_tab_loads_(0) {
96 }
97
98 TabLoader::~TabLoader() {
99 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
100 tabs_loading_.empty() && tabs_to_load_.empty());
101 shared_tab_loader_ = nullptr;
102 }
103
104 void TabLoader::LoadNextTab() {
105 // LoadNextTab should only get called after we have started the tab
106 // loading.
107 CHECK(delegate_);
108 if (!tabs_to_load_.empty()) {
109 NavigationController* tab = tabs_to_load_.front();
110 DCHECK(tab);
111 tabs_loading_.insert(tab);
112 if (tabs_loading_.size() > max_parallel_tab_loads_)
113 max_parallel_tab_loads_ = tabs_loading_.size();
114 tabs_to_load_.pop_front();
115 tab->LoadIfNecessary();
116 content::WebContents* contents = tab->GetWebContents();
117 if (contents) {
118 Browser* browser = chrome::FindBrowserWithWebContents(contents);
119 if (browser &&
120 browser->tab_strip_model()->GetActiveWebContents() != contents) {
121 // By default tabs are marked as visible. As only the active tab is
122 // visible we need to explicitly tell non-active tabs they are hidden.
123 // Without this call non-active tabs are not marked as backgrounded.
124 //
125 // NOTE: We need to do this here rather than when the tab is added to
126 // the Browser as at that time not everything has been created, so that
127 // the call would do nothing.
128 contents->WasHidden();
129 }
130 }
131 }
132
133 if (!tabs_to_load_.empty())
134 StartTimer();
135 }
136
137 void TabLoader::StartTimer() {
138 force_load_timer_.Stop();
139 force_load_timer_.Start(FROM_HERE,
140 delegate_->GetTimeoutBeforeLoadingNextTab() *
141 force_load_delay_multiplier_,
142 this, &TabLoader::ForceLoadTimerFired);
143 }
144
145 void TabLoader::Observe(int type, 26 void TabLoader::Observe(int type,
146 const content::NotificationSource& source, 27 const content::NotificationSource& source,
147 const content::NotificationDetails& details) { 28 const content::NotificationDetails& details) {
148 switch (type) { 29 switch (type) {
149 case content::NOTIFICATION_LOAD_START: { 30 case content::NOTIFICATION_LOAD_START: {
150 // Add this render_widget_host to the set of those we're waiting for 31 // Add this render_widget_host to the set of those we're waiting for
151 // paints on. We want to only record stats for paints that occur after 32 // paints on. We want to only record stats for paints that occur after
152 // a load has finished. 33 // a load has finished.
153 NavigationController* tab = 34 NavigationController* tab =
154 content::Source<NavigationController>(source).ptr(); 35 content::Source<NavigationController>(source).ptr();
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 } 134 }
254 // Delete ourselves when we're not waiting for any more notifications. If this 135 // Delete ourselves when we're not waiting for any more notifications. If this
255 // was not the last reference, a SessionRestoreImpl holding a reference will 136 // was not the last reference, a SessionRestoreImpl holding a reference will
256 // eventually call StartLoading (which assigns this_retainer_), or drop the 137 // eventually call StartLoading (which assigns this_retainer_), or drop the
257 // reference without initiating a load. 138 // reference without initiating a load.
258 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 139 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
259 tabs_loading_.empty() && tabs_to_load_.empty()) 140 tabs_loading_.empty() && tabs_to_load_.empty())
260 this_retainer_ = nullptr; 141 this_retainer_ = nullptr;
261 } 142 }
262 143
144 void TabLoader::SetTabLoadingEnabled(bool enable_tab_loading) {
145 if (enable_tab_loading == loading_enabled_)
146 return;
147 loading_enabled_ = enable_tab_loading;
148 if (loading_enabled_)
149 LoadNextTab();
150 else
151 force_load_timer_.Stop();
152 }
153
154 // static
155 void TabLoader::RestoreTabs(const std::vector<RestoredTab>& tabs,
156 const base::TimeTicks& restore_started) {
157 if (!shared_tab_loader_)
158 shared_tab_loader_ = new TabLoader(restore_started);
159
160 shared_tab_loader_->StartLoading(tabs);
161 }
162
163 TabLoader::TabLoader(base::TimeTicks restore_started)
164 : memory_pressure_listener_(
165 base::Bind(&TabLoader::OnMemoryPressure, base::Unretained(this))),
166 force_load_delay_multiplier_(1),
167 loading_enabled_(true),
168 got_first_foreground_load_(false),
169 got_first_paint_(false),
170 tab_count_(0),
171 restore_started_(restore_started),
172 max_parallel_tab_loads_(0) {
173 }
174
175 TabLoader::~TabLoader() {
176 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
177 tabs_loading_.empty() && tabs_to_load_.empty());
178 shared_tab_loader_ = nullptr;
179 }
180
181 void TabLoader::StartLoading(const std::vector<RestoredTab>& tabs) {
182 // Add the tabs to the list of tabs loading/to load and register them for
183 // notifications.
184 for (int i = 0; i < static_cast<int>(tabs.size()); i++) {
sky 2015/04/01 22:41:46 Don't static cast like this. Easiest way is to use
Georges Khalil 2015/04/01 23:30:21 Done.
185 if (!tabs[i].is_active)
186 tabs_to_load_.push_back(&tabs[i].contents->GetController());
187 else
188 tabs_loading_.insert(&tabs[i].contents->GetController());
189 RegisterForNotifications(&tabs[i].contents->GetController());
190 }
191 // When multiple profiles are using the same TabLoader, another profile might
192 // already have started loading. In that case, the tabs scheduled for loading
193 // by this profile are already in the loading queue, and they will get loaded
194 // eventually.
195 if (delegate_)
196 return;
197
198 registrar_.Add(
199 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
200 content::NotificationService::AllSources());
201 this_retainer_ = this;
202 // Create a TabLoaderDelegate which will allow OS specific behavior for tab
203 // loading.
204 if (!delegate_) {
205 delegate_ = TabLoaderDelegate::Create(this);
206 // There is already at least one tab loading (the active tab). As such we
207 // only have to start the timeout timer here.
208 StartTimer();
209 }
210 }
211
212 void TabLoader::ScheduleLoad(NavigationController* controller) {
213 CheckNotObserving(controller);
214 DCHECK(controller);
215 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
216 tabs_to_load_.end());
217 tabs_to_load_.push_back(controller);
218 RegisterForNotifications(controller);
219 }
220
221 void TabLoader::TabIsLoading(NavigationController* controller) {
222 CheckNotObserving(controller);
223 DCHECK(controller);
224 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
225 tabs_loading_.end());
226 tabs_loading_.insert(controller);
227 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
228 DCHECK(render_widget_host);
229 render_widget_hosts_loading_.insert(render_widget_host);
230 RegisterForNotifications(controller);
231 }
232
233 void TabLoader::LoadNextTab() {
234 // LoadNextTab should only get called after we have started the tab
235 // loading.
236 CHECK(delegate_);
237 if (!tabs_to_load_.empty()) {
238 NavigationController* tab = tabs_to_load_.front();
239 DCHECK(tab);
240 tabs_loading_.insert(tab);
241 if (tabs_loading_.size() > max_parallel_tab_loads_)
242 max_parallel_tab_loads_ = tabs_loading_.size();
243 tabs_to_load_.pop_front();
244 tab->LoadIfNecessary();
245 content::WebContents* contents = tab->GetWebContents();
246 if (contents) {
247 Browser* browser = chrome::FindBrowserWithWebContents(contents);
248 if (browser &&
249 browser->tab_strip_model()->GetActiveWebContents() != contents) {
250 // By default tabs are marked as visible. As only the active tab is
251 // visible we need to explicitly tell non-active tabs they are hidden.
252 // Without this call non-active tabs are not marked as backgrounded.
253 //
254 // NOTE: We need to do this here rather than when the tab is added to
255 // the Browser as at that time not everything has been created, so that
256 // the call would do nothing.
257 contents->WasHidden();
258 }
259 }
260 }
261
262 if (!tabs_to_load_.empty())
263 StartTimer();
264 }
265
266 void TabLoader::StartTimer() {
267 force_load_timer_.Stop();
268 force_load_timer_.Start(FROM_HERE,
269 delegate_->GetTimeoutBeforeLoadingNextTab() *
270 force_load_delay_multiplier_,
271 this, &TabLoader::ForceLoadTimerFired);
272 }
273
263 void TabLoader::RemoveTab(NavigationController* tab) { 274 void TabLoader::RemoveTab(NavigationController* tab) {
264 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 275 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
265 content::Source<WebContents>(tab->GetWebContents())); 276 content::Source<WebContents>(tab->GetWebContents()));
266 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, 277 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
267 content::Source<NavigationController>(tab)); 278 content::Source<NavigationController>(tab));
268 registrar_.Remove(this, content::NOTIFICATION_LOAD_START, 279 registrar_.Remove(this, content::NOTIFICATION_LOAD_START,
269 content::Source<NavigationController>(tab)); 280 content::Source<NavigationController>(tab));
270 281
271 TabsLoading::iterator i = tabs_loading_.find(tab); 282 TabsLoading::iterator i = tabs_loading_.find(tab);
272 if (i != tabs_loading_.end()) 283 if (i != tabs_loading_.end())
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 tabs_to_load_.pop_front(); 373 tabs_to_load_.pop_front();
363 RemoveTab(controller); 374 RemoveTab(controller);
364 } 375 }
365 // By calling |LoadNextTab| explicitly, we make sure that the 376 // By calling |LoadNextTab| explicitly, we make sure that the
366 // |NOTIFICATION_SESSION_RESTORE_DONE| event gets sent. 377 // |NOTIFICATION_SESSION_RESTORE_DONE| event gets sent.
367 LoadNextTab(); 378 LoadNextTab();
368 } 379 }
369 380
370 // static 381 // static
371 TabLoader* TabLoader::shared_tab_loader_ = nullptr; 382 TabLoader* TabLoader::shared_tab_loader_ = nullptr;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698