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

Side by Side Diff: chrome/browser/ui/tabs/tab_strip_model.cc

Issue 1332003002: Add option to disallow the discarding of a tab that was previously discarded. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sky@ comments + fix tests. Created 5 years, 3 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 (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/tabs/tab_strip_model.h" 5 #include "chrome/browser/ui/tabs/tab_strip_model.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
11 11
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/stl_util.h" 13 #include "base/stl_util.h"
14 #include "chrome/app/chrome_command_ids.h" 14 #include "chrome/app/chrome_command_ids.h"
15 #include "chrome/browser/browser_shutdown.h" 15 #include "chrome/browser/browser_shutdown.h"
16 #include "chrome/browser/defaults.h" 16 #include "chrome/browser/defaults.h"
17 #include "chrome/browser/extensions/tab_helper.h" 17 #include "chrome/browser/extensions/tab_helper.h"
18 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" 19 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
20 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" 20 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
21 #include "chrome/browser/ui/tabs/tab_discard_state.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" 22 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h" 23 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
23 #include "chrome/browser/ui/tabs/tab_utils.h" 24 #include "chrome/browser/ui/tabs/tab_utils.h"
24 #include "chrome/browser/ui/web_contents_sizer.h" 25 #include "chrome/browser/ui/web_contents_sizer.h"
25 #include "chrome/common/url_constants.h" 26 #include "chrome/common/url_constants.h"
26 #include "components/web_modal/web_contents_modal_dialog_manager.h" 27 #include "components/web_modal/web_contents_modal_dialog_manager.h"
27 #include "content/public/browser/render_process_host.h" 28 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/user_metrics.h" 29 #include "content/public/browser/user_metrics.h"
29 #include "content/public/browser/web_contents.h" 30 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_contents_observer.h" 31 #include "content/public/browser/web_contents_observer.h"
(...skipping 10 matching lines...) Expand all
41 UMA_TAB_DISCARDING_DISCARD_TAB_AUDIO, 42 UMA_TAB_DISCARDING_DISCARD_TAB_AUDIO,
42 UMA_TAB_DISCARDING_TAB_DISCARDING_MAX 43 UMA_TAB_DISCARDING_TAB_DISCARDING_MAX
43 }; 44 };
44 45
45 // Records an UMA tab discarding event. 46 // Records an UMA tab discarding event.
46 void RecordUMATabDiscarding(UMATabDiscarding event) { 47 void RecordUMATabDiscarding(UMATabDiscarding event) {
47 UMA_HISTOGRAM_ENUMERATION("Tab.Discarding", event, 48 UMA_HISTOGRAM_ENUMERATION("Tab.Discarding", event,
48 UMA_TAB_DISCARDING_TAB_DISCARDING_MAX); 49 UMA_TAB_DISCARDING_TAB_DISCARDING_MAX);
49 } 50 }
50 51
52 // Records the number of discards that a tab has been through.
53 void RecordUMADiscardCount(int discard_count) {
54 UMA_HISTOGRAM_COUNTS("Tab.Discarding.DiscardCount", discard_count);
55 }
56
51 // Returns true if the specified transition is one of the types that cause the 57 // Returns true if the specified transition is one of the types that cause the
52 // opener relationships for the tab in which the transition occurred to be 58 // opener relationships for the tab in which the transition occurred to be
53 // forgotten. This is generally any navigation that isn't a link click (i.e. 59 // forgotten. This is generally any navigation that isn't a link click (i.e.
54 // any navigation that can be considered to be the start of a new task distinct 60 // any navigation that can be considered to be the start of a new task distinct
55 // from what had previously occurred in that tab). 61 // from what had previously occurred in that tab).
56 bool ShouldForgetOpenersForTransition(ui::PageTransition transition) { 62 bool ShouldForgetOpenersForTransition(ui::PageTransition transition) {
57 return transition == ui::PAGE_TRANSITION_TYPED || 63 return transition == ui::PAGE_TRANSITION_TYPED ||
58 transition == ui::PAGE_TRANSITION_AUTO_BOOKMARK || 64 transition == ui::PAGE_TRANSITION_AUTO_BOOKMARK ||
59 transition == ui::PAGE_TRANSITION_GENERATED || 65 transition == ui::PAGE_TRANSITION_GENERATED ||
60 transition == ui::PAGE_TRANSITION_KEYWORD || 66 transition == ui::PAGE_TRANSITION_KEYWORD ||
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 WebContents* opener() const { return opener_; } 168 WebContents* opener() const { return opener_; }
163 void set_opener(WebContents* value) { opener_ = value; } 169 void set_opener(WebContents* value) { opener_ = value; }
164 170
165 // Alters the properties of the WebContents. 171 // Alters the properties of the WebContents.
166 bool reset_group_on_select() const { return reset_group_on_select_; } 172 bool reset_group_on_select() const { return reset_group_on_select_; }
167 void set_reset_group_on_select(bool value) { reset_group_on_select_ = value; } 173 void set_reset_group_on_select(bool value) { reset_group_on_select_ = value; }
168 bool pinned() const { return pinned_; } 174 bool pinned() const { return pinned_; }
169 void set_pinned(bool value) { pinned_ = value; } 175 void set_pinned(bool value) { pinned_ = value; }
170 bool blocked() const { return blocked_; } 176 bool blocked() const { return blocked_; }
171 void set_blocked(bool value) { blocked_ = value; } 177 void set_blocked(bool value) { blocked_ = value; }
172 bool discarded() const { return discarded_; }
173 void set_discarded(bool value) { discarded_ = value; }
174 178
175 private: 179 private:
176 // Make sure that if someone deletes this WebContents out from under us, it 180 // Make sure that if someone deletes this WebContents out from under us, it
177 // is properly removed from the tab strip. 181 // is properly removed from the tab strip.
178 void WebContentsDestroyed() override; 182 void WebContentsDestroyed() override;
179 183
180 // Marks the tab as no longer discarded if it has been reloaded from another 184 // Marks the tab as no longer discarded if it has been reloaded from another
181 // source (ie: context menu). 185 // source (ie: context menu).
182 void DidStartLoading() override; 186 void DidStartLoading() override;
183 187
(...skipping 27 matching lines...) Expand all
211 // selection shifts to _any_ tab (including their opener), the group 215 // selection shifts to _any_ tab (including their opener), the group
212 // relationship is reset to avoid confusing close sequencing. 216 // relationship is reset to avoid confusing close sequencing.
213 bool reset_group_on_select_; 217 bool reset_group_on_select_;
214 218
215 // Is the tab pinned? 219 // Is the tab pinned?
216 bool pinned_; 220 bool pinned_;
217 221
218 // Is the tab interaction blocked by a modal dialog? 222 // Is the tab interaction blocked by a modal dialog?
219 bool blocked_; 223 bool blocked_;
220 224
221 // Has the tab data been discarded to save memory?
222 bool discarded_;
223
224 DISALLOW_COPY_AND_ASSIGN(WebContentsData); 225 DISALLOW_COPY_AND_ASSIGN(WebContentsData);
225 }; 226 };
226 227
227 TabStripModel::WebContentsData::WebContentsData(TabStripModel* tab_strip_model, 228 TabStripModel::WebContentsData::WebContentsData(TabStripModel* tab_strip_model,
228 WebContents* contents) 229 WebContents* contents)
229 : content::WebContentsObserver(contents), 230 : content::WebContentsObserver(contents),
230 contents_(contents), 231 contents_(contents),
231 tab_strip_model_(tab_strip_model), 232 tab_strip_model_(tab_strip_model),
232 group_(NULL), 233 group_(NULL),
233 opener_(NULL), 234 opener_(NULL),
234 reset_group_on_select_(false), 235 reset_group_on_select_(false),
235 pinned_(false), 236 pinned_(false),
236 blocked_(false), 237 blocked_(false) {}
237 discarded_(false) {
238 }
239 238
240 void TabStripModel::WebContentsData::SetWebContents(WebContents* contents) { 239 void TabStripModel::WebContentsData::SetWebContents(WebContents* contents) {
241 contents_ = contents; 240 contents_ = contents;
242 Observe(contents); 241 Observe(contents);
243 } 242 }
244 243
245 void TabStripModel::WebContentsData::WebContentsDestroyed() { 244 void TabStripModel::WebContentsData::WebContentsDestroyed() {
246 DCHECK_EQ(contents_, web_contents()); 245 DCHECK_EQ(contents_, web_contents());
247 246
248 // Note that we only detach the contents here, not close it - it's 247 // Note that we only detach the contents here, not close it - it's
249 // already been closed. We just want to undo our bookkeeping. 248 // already been closed. We just want to undo our bookkeeping.
250 int index = tab_strip_model_->GetIndexOfWebContents(web_contents()); 249 int index = tab_strip_model_->GetIndexOfWebContents(web_contents());
251 DCHECK_NE(TabStripModel::kNoTab, index); 250 DCHECK_NE(TabStripModel::kNoTab, index);
252 tab_strip_model_->DetachWebContentsAt(index); 251 tab_strip_model_->DetachWebContentsAt(index);
253 } 252 }
254 253
255 void TabStripModel::WebContentsData::DidStartLoading() { 254 void TabStripModel::WebContentsData::DidStartLoading() {
256 set_discarded(false); 255 TabDiscardState::SetDiscardState(contents_, false);
257 } 256 }
258 257
259 /////////////////////////////////////////////////////////////////////////////// 258 ///////////////////////////////////////////////////////////////////////////////
260 // TabStripModel, public: 259 // TabStripModel, public:
261 260
262 TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile) 261 TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile)
263 : delegate_(delegate), 262 : delegate_(delegate),
264 profile_(profile), 263 profile_(profile),
265 closing_all_(false), 264 closing_all_(false),
266 in_notify_(false), 265 in_notify_(false),
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 WebContents* null_contents = 393 WebContents* null_contents =
395 WebContents::Create(WebContents::CreateParams(profile())); 394 WebContents::Create(WebContents::CreateParams(profile()));
396 WebContents* old_contents = GetWebContentsAtImpl(index); 395 WebContents* old_contents = GetWebContentsAtImpl(index);
397 bool is_playing_audio = old_contents->WasRecentlyAudible(); 396 bool is_playing_audio = old_contents->WasRecentlyAudible();
398 // Copy over the state from the navigation controller so we preserve the 397 // Copy over the state from the navigation controller so we preserve the
399 // back/forward history and continue to display the correct title/favicon. 398 // back/forward history and continue to display the correct title/favicon.
400 null_contents->GetController().CopyStateFrom(old_contents->GetController()); 399 null_contents->GetController().CopyStateFrom(old_contents->GetController());
401 400
402 // Make sure we persist the last active time property. 401 // Make sure we persist the last active time property.
403 null_contents->SetLastActiveTime(old_contents->GetLastActiveTime()); 402 null_contents->SetLastActiveTime(old_contents->GetLastActiveTime());
403 // Copy over the discard count.
404 TabDiscardState::CopyState(old_contents, null_contents);
404 405
405 // Replace the tab we're discarding with the null version. 406 // Replace the tab we're discarding with the null version.
406 ReplaceWebContentsAt(index, null_contents); 407 ReplaceWebContentsAt(index, null_contents);
407 // Mark the tab so it will reload when we click. 408 // Mark the tab so it will reload when we click.
408 if (!contents_data_[index]->discarded()) { 409 if (!TabDiscardState::IsDiscarded(null_contents)) {
409 contents_data_[index]->set_discarded(true); 410 TabDiscardState::SetDiscardState(null_contents, true);
411 TabDiscardState::IncrementDiscardCount(null_contents);
410 RecordUMATabDiscarding(UMA_TAB_DISCARDING_DISCARD_TAB); 412 RecordUMATabDiscarding(UMA_TAB_DISCARDING_DISCARD_TAB);
413 RecordUMADiscardCount(TabDiscardState::DiscardCount(null_contents));
411 if (is_playing_audio) 414 if (is_playing_audio)
412 RecordUMATabDiscarding(UMA_TAB_DISCARDING_DISCARD_TAB_AUDIO); 415 RecordUMATabDiscarding(UMA_TAB_DISCARDING_DISCARD_TAB_AUDIO);
413 } 416 }
414 // Discard the old tab's renderer. 417 // Discard the old tab's renderer.
415 // TODO(jamescook): This breaks script connections with other tabs. 418 // TODO(jamescook): This breaks script connections with other tabs.
416 // We need to find a different approach that doesn't do that, perhaps based 419 // We need to find a different approach that doesn't do that, perhaps based
417 // on navigation to swappedout://. 420 // on navigation to swappedout://.
418 delete old_contents; 421 delete old_contents;
419 return null_contents; 422 return null_contents;
420 } 423 }
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 728
726 bool TabStripModel::IsTabPinned(int index) const { 729 bool TabStripModel::IsTabPinned(int index) const {
727 DCHECK(ContainsIndex(index)); 730 DCHECK(ContainsIndex(index));
728 return contents_data_[index]->pinned(); 731 return contents_data_[index]->pinned();
729 } 732 }
730 733
731 bool TabStripModel::IsTabBlocked(int index) const { 734 bool TabStripModel::IsTabBlocked(int index) const {
732 return contents_data_[index]->blocked(); 735 return contents_data_[index]->blocked();
733 } 736 }
734 737
735 bool TabStripModel::IsTabDiscarded(int index) const {
736 return contents_data_[index]->discarded();
737 }
738
739 int TabStripModel::IndexOfFirstNonPinnedTab() const { 738 int TabStripModel::IndexOfFirstNonPinnedTab() const {
740 for (size_t i = 0; i < contents_data_.size(); ++i) { 739 for (size_t i = 0; i < contents_data_.size(); ++i) {
741 if (!IsTabPinned(static_cast<int>(i))) 740 if (!IsTabPinned(static_cast<int>(i)))
742 return static_cast<int>(i); 741 return static_cast<int>(i);
743 } 742 }
744 // No pinned tabs. 743 // No pinned tabs.
745 return count(); 744 return count();
746 } 745 }
747 746
748 int TabStripModel::ConstrainInsertionIndex(int index, bool pinned_tab) { 747 int TabStripModel::ConstrainInsertionIndex(int index, bool pinned_tab) {
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after
1320 ? TabStripModelObserver::CHANGE_REASON_USER_GESTURE 1319 ? TabStripModelObserver::CHANGE_REASON_USER_GESTURE
1321 : TabStripModelObserver::CHANGE_REASON_NONE; 1320 : TabStripModelObserver::CHANGE_REASON_NONE;
1322 CHECK(!in_notify_); 1321 CHECK(!in_notify_);
1323 in_notify_ = true; 1322 in_notify_ = true;
1324 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, 1323 FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
1325 ActiveTabChanged(old_contents, 1324 ActiveTabChanged(old_contents,
1326 new_contents, 1325 new_contents,
1327 active_index(), 1326 active_index(),
1328 reason)); 1327 reason));
1329 in_notify_ = false; 1328 in_notify_ = false;
1330 // Activating a discarded tab reloads it, so it is no longer discarded.
1331 if (contents_data_[active_index()]->discarded()) {
1332 contents_data_[active_index()]->set_discarded(false);
1333 RecordUMATabDiscarding(UMA_TAB_DISCARDING_SWITCH_TO_DISCARDED_TAB);
1334 } else {
1335 RecordUMATabDiscarding(UMA_TAB_DISCARDING_SWITCH_TO_LOADED_TAB);
1336 }
1337 } 1329 }
1338 } 1330 }
1339 1331
1340 void TabStripModel::NotifyIfActiveOrSelectionChanged( 1332 void TabStripModel::NotifyIfActiveOrSelectionChanged(
1341 WebContents* old_contents, 1333 WebContents* old_contents,
1342 NotifyTypes notify_types, 1334 NotifyTypes notify_types,
1343 const ui::ListSelectionModel& old_model) { 1335 const ui::ListSelectionModel& old_model) {
1344 NotifyIfActiveTabChanged(old_contents, notify_types); 1336 NotifyIfActiveTabChanged(old_contents, notify_types);
1345 1337
1346 if (!selection_model().Equals(old_model)) { 1338 if (!selection_model().Equals(old_model)) {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
1437 1429
1438 void TabStripModel::FixOpenersAndGroupsReferencing(int index) { 1430 void TabStripModel::FixOpenersAndGroupsReferencing(int index) {
1439 WebContents* old_contents = GetWebContentsAtImpl(index); 1431 WebContents* old_contents = GetWebContentsAtImpl(index);
1440 for (WebContentsData* data : contents_data_) { 1432 for (WebContentsData* data : contents_data_) {
1441 if (data->group() == old_contents) 1433 if (data->group() == old_contents)
1442 data->set_group(contents_data_[index]->group()); 1434 data->set_group(contents_data_[index]->group());
1443 if (data->opener() == old_contents) 1435 if (data->opener() == old_contents)
1444 data->set_opener(contents_data_[index]->opener()); 1436 data->set_opener(contents_data_[index]->opener());
1445 } 1437 }
1446 } 1438 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698