| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 #import "ios/chrome/browser/tabs/tab_model.h" | 5 #import "ios/chrome/browser/tabs/tab_model.h" |
| 6 | 6 |
| 7 #include <list> | 7 #include <list> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 @"kTabModelTabDeselectedNotification"; | 59 @"kTabModelTabDeselectedNotification"; |
| 60 NSString* const kTabModelNewTabWillOpenNotification = | 60 NSString* const kTabModelNewTabWillOpenNotification = |
| 61 @"kTabModelNewTabWillOpenNotification"; | 61 @"kTabModelNewTabWillOpenNotification"; |
| 62 NSString* const kTabModelTabKey = @"tab"; | 62 NSString* const kTabModelTabKey = @"tab"; |
| 63 NSString* const kTabModelPageLoadSuccess = @"pageLoadSuccess"; | 63 NSString* const kTabModelPageLoadSuccess = @"pageLoadSuccess"; |
| 64 NSString* const kTabModelOpenInBackgroundKey = @"shouldOpenInBackground"; | 64 NSString* const kTabModelOpenInBackgroundKey = @"shouldOpenInBackground"; |
| 65 | 65 |
| 66 namespace { | 66 namespace { |
| 67 | 67 |
| 68 // Updates CRWSessionCertificatePolicyManager's certificate policy cache. | 68 // Updates CRWSessionCertificatePolicyManager's certificate policy cache. |
| 69 void UpdateCertificatePolicyCacheFromWebState(web::WebStateImpl* webState) { | 69 void UpdateCertificatePolicyCacheFromWebState(web::WebStateImpl* web_state) { |
| 70 DCHECK([NSThread isMainThread]); | 70 DCHECK([NSThread isMainThread]); |
| 71 DCHECK(webState); | 71 DCHECK(web_state); |
| 72 scoped_refptr<web::CertificatePolicyCache> policy_cache = | 72 scoped_refptr<web::CertificatePolicyCache> policy_cache = |
| 73 web::BrowserState::GetCertificatePolicyCache(webState->GetBrowserState()); | 73 web::BrowserState::GetCertificatePolicyCache( |
| 74 web_state->GetBrowserState()); |
| 74 CRWSessionController* controller = | 75 CRWSessionController* controller = |
| 75 webState->GetNavigationManagerImpl().GetSessionController(); | 76 web_state->GetNavigationManagerImpl().GetSessionController(); |
| 76 [[controller sessionCertificatePolicyManager] | 77 [[controller sessionCertificatePolicyManager] |
| 77 updateCertificatePolicyCache:policy_cache]; | 78 updateCertificatePolicyCache:policy_cache]; |
| 78 } | 79 } |
| 79 | 80 |
| 80 // Populates the certificate policy cache based on the current entries of the | 81 // Populates the certificate policy cache based on the current entries of the |
| 81 // given tabs. | 82 // given tabs. |
| 82 void RestoreCertificatePolicyCacheFromTabs(NSArray* tabs) { | 83 void RestoreCertificatePolicyCacheFromTabs(WebStateList* web_state_list) { |
| 83 DCHECK([NSThread isMainThread]); | 84 DCHECK([NSThread isMainThread]); |
| 84 for (Tab* tab in tabs) { | 85 for (id<WebStateHandle> web_state in web_state_list) { |
| 85 UpdateCertificatePolicyCacheFromWebState(tab.webStateImpl); | 86 UpdateCertificatePolicyCacheFromWebState(web_state.webStateImpl); |
| 86 } | 87 } |
| 87 } | 88 } |
| 88 | 89 |
| 89 // Scrubs the certificate policy cache of all the certificate policies except | 90 // Scrubs the certificate policy cache of all the certificate policies except |
| 90 // those for the current entries of the given tabs. | 91 // those for the current entries of the given tabs. |
| 91 void CleanCertificatePolicyCache( | 92 void CleanCertificatePolicyCache( |
| 92 scoped_refptr<web::CertificatePolicyCache> policy_cache, | 93 scoped_refptr<web::CertificatePolicyCache> policy_cache, |
| 93 NSArray* tabs) { | 94 WebStateList* web_state_list) { |
| 94 DCHECK_CURRENTLY_ON(web::WebThread::IO); | 95 DCHECK_CURRENTLY_ON(web::WebThread::IO); |
| 95 DCHECK(policy_cache); | 96 DCHECK(policy_cache); |
| 96 policy_cache->ClearCertificatePolicies(); | 97 policy_cache->ClearCertificatePolicies(); |
| 97 web::WebThread::PostTask( | 98 web::WebThread::PostTask( |
| 98 web::WebThread::UI, FROM_HERE, | 99 web::WebThread::UI, FROM_HERE, |
| 99 base::Bind(&RestoreCertificatePolicyCacheFromTabs, tabs)); | 100 base::Bind(&RestoreCertificatePolicyCacheFromTabs, web_state_list)); |
| 101 } |
| 102 |
| 103 // Creates a NSArray<Tab*>* from |web_state_list|. This is for compatibility |
| 104 // with TabUsageRecorder existing API. That API will be refactored in later |
| 105 // CL and this method removed, see http://crbug.com/681867 for details. |
| 106 NSArray<Tab*>* GetTabsFromWebStateList(WebStateList* web_state_list) { |
| 107 NSMutableArray<Tab*>* mutableArray = [[NSMutableArray alloc] init]; |
| 108 for (Tab* tab in web_state_list) { |
| 109 [mutableArray addObject:tab]; |
| 110 } |
| 111 return [mutableArray copy]; |
| 100 } | 112 } |
| 101 | 113 |
| 102 } // anonymous namespace | 114 } // anonymous namespace |
| 103 | 115 |
| 104 @interface TabModelObservers : CRBProtocolObservers<TabModelObserver> | 116 @interface TabModelObservers : CRBProtocolObservers<TabModelObserver> |
| 105 @end | 117 @end |
| 106 @implementation TabModelObservers | 118 @implementation TabModelObservers |
| 107 @end | 119 @end |
| 108 | 120 |
| 109 @interface TabModel ()<TabUsageRecorderDelegate> { | 121 @interface TabModel ()<TabUsageRecorderDelegate> { |
| 110 // Array of |Tab| objects. | |
| 111 base::scoped_nsobject<NSMutableArray> _tabs; | |
| 112 // Maintains policy for where new tabs go and the selection when a tab | 122 // Maintains policy for where new tabs go and the selection when a tab |
| 113 // is removed. | 123 // is removed. |
| 114 base::scoped_nsobject<TabModelOrderController> _orderController; | 124 base::scoped_nsobject<TabModelOrderController> _orderController; |
| 115 // The delegate for sync. | 125 // The delegate for sync. |
| 116 std::unique_ptr<TabModelSyncedWindowDelegate> _syncedWindowDelegate; | 126 std::unique_ptr<TabModelSyncedWindowDelegate> _syncedWindowDelegate; |
| 117 // Currently selected tab. May be nil. | 127 // Currently selected tab. May be nil. |
| 118 base::WeakNSObject<Tab> _currentTab; | 128 base::WeakNSObject<Tab> _currentTab; |
| 119 | 129 |
| 120 // Counters for metrics. | 130 // Counters for metrics. |
| 121 int _openedTabCount; | 131 int _openedTabCount; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 [super dealloc]; | 200 [super dealloc]; |
| 191 } | 201 } |
| 192 | 202 |
| 193 #pragma mark - Public methods | 203 #pragma mark - Public methods |
| 194 | 204 |
| 195 - (Tab*)currentTab { | 205 - (Tab*)currentTab { |
| 196 return _currentTab.get(); | 206 return _currentTab.get(); |
| 197 } | 207 } |
| 198 | 208 |
| 199 - (void)setCurrentTab:(Tab*)newTab { | 209 - (void)setCurrentTab:(Tab*)newTab { |
| 200 DCHECK([_tabs containsObject:newTab]); | 210 DCHECK([self containsWebState:newTab]); |
| 201 if (_currentTab != newTab) { | 211 if (_currentTab != newTab) { |
| 202 base::RecordAction(base::UserMetricsAction("MobileTabSwitched")); | 212 base::RecordAction(base::UserMetricsAction("MobileTabSwitched")); |
| 203 [self updateSnapshotCache:newTab]; | 213 [self updateSnapshotCache:newTab]; |
| 204 } | 214 } |
| 205 if (_tabUsageRecorder) { | 215 if (_tabUsageRecorder) { |
| 206 _tabUsageRecorder->RecordTabSwitched(_currentTab, newTab); | 216 _tabUsageRecorder->RecordTabSwitched(_currentTab, newTab); |
| 207 } | 217 } |
| 208 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES]; | 218 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES]; |
| 209 } | 219 } |
| 210 | 220 |
| 211 - (TabModelSyncedWindowDelegate*)syncedWindowDelegate { | 221 - (TabModelSyncedWindowDelegate*)syncedWindowDelegate { |
| 212 return _syncedWindowDelegate.get(); | 222 return _syncedWindowDelegate.get(); |
| 213 } | 223 } |
| 214 | 224 |
| 215 - (TabUsageRecorder*)tabUsageRecorder { | 225 - (TabUsageRecorder*)tabUsageRecorder { |
| 216 return _tabUsageRecorder.get(); | 226 return _tabUsageRecorder.get(); |
| 217 } | 227 } |
| 218 | 228 |
| 219 - (BOOL)isOffTheRecord { | 229 - (BOOL)isOffTheRecord { |
| 220 return _browserState && _browserState->IsOffTheRecord(); | 230 return _browserState && _browserState->IsOffTheRecord(); |
| 221 } | 231 } |
| 222 | 232 |
| 223 - (BOOL)isEmpty { | 233 - (BOOL)isEmpty { |
| 224 return self.count == 0; | 234 return self.count == 0; |
| 225 } | 235 } |
| 226 | 236 |
| 227 - (NSUInteger)count { | |
| 228 return [_tabs count]; | |
| 229 } | |
| 230 | |
| 231 - (instancetype)initWithSessionWindow:(SessionWindowIOS*)window | 237 - (instancetype)initWithSessionWindow:(SessionWindowIOS*)window |
| 232 sessionService:(SessionServiceIOS*)service | 238 sessionService:(SessionServiceIOS*)service |
| 233 browserState:(ios::ChromeBrowserState*)browserState { | 239 browserState:(ios::ChromeBrowserState*)browserState { |
| 234 if ((self = [super init])) { | 240 if ((self = [super init])) { |
| 235 _observers.reset([[TabModelObservers | 241 _observers.reset([[TabModelObservers |
| 236 observersWithProtocol:@protocol(TabModelObserver)] retain]); | 242 observersWithProtocol:@protocol(TabModelObserver)] retain]); |
| 237 | 243 |
| 238 _browserState = browserState; | 244 _browserState = browserState; |
| 239 DCHECK(_browserState); | 245 DCHECK(_browserState); |
| 240 | 246 |
| 241 // There must be a valid session service defined to consume session windows. | 247 // There must be a valid session service defined to consume session windows. |
| 242 DCHECK(service); | 248 DCHECK(service); |
| 243 _sessionService.reset([service retain]); | 249 _sessionService.reset([service retain]); |
| 244 | 250 |
| 245 // Normal browser states are the only ones to get tab restore. Tab sync | 251 // Normal browser states are the only ones to get tab restore. Tab sync |
| 246 // handles incognito browser states by filtering on profile, so it's | 252 // handles incognito browser states by filtering on profile, so it's |
| 247 // important to the backend code to always have a sync window delegate. | 253 // important to the backend code to always have a sync window delegate. |
| 248 if (!_browserState->IsOffTheRecord()) { | 254 if (!_browserState->IsOffTheRecord()) { |
| 249 // Set up the usage recorder before tabs are created. | 255 // Set up the usage recorder before tabs are created. |
| 250 _tabUsageRecorder.reset(new TabUsageRecorder(self)); | 256 _tabUsageRecorder.reset(new TabUsageRecorder(self)); |
| 251 } | 257 } |
| 252 _syncedWindowDelegate.reset(new TabModelSyncedWindowDelegate(self)); | 258 _syncedWindowDelegate.reset(new TabModelSyncedWindowDelegate(self)); |
| 253 | 259 |
| 254 _tabs.reset([[NSMutableArray alloc] init]); | |
| 255 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; | 260 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; |
| 256 if (window) { | 261 if (window) { |
| 257 while (window.unclaimedSessions) { | 262 while (window.unclaimedSessions) { |
| 258 std::unique_ptr<web::WebStateImpl> webState = [window nextSession]; | 263 std::unique_ptr<web::WebStateImpl> webState = [window nextSession]; |
| 259 DCHECK_EQ(webState->GetBrowserState(), _browserState); | 264 DCHECK_EQ(webState->GetBrowserState(), _browserState); |
| 260 // Restore the CertificatePolicyCache. | 265 // Restore the CertificatePolicyCache. |
| 261 UpdateCertificatePolicyCacheFromWebState(webState.get()); | 266 UpdateCertificatePolicyCacheFromWebState(webState.get()); |
| 262 // Create a new tab for each entry in the window. Don't send delegate | 267 // Create a new tab for each entry in the window. Don't send delegate |
| 263 // notifications for each restored tab, only when all done. | 268 // notifications for each restored tab, only when all done. |
| 264 base::scoped_nsobject<Tab> tab( | 269 base::scoped_nsobject<Tab> tab( |
| 265 [[Tab alloc] initWithWebState:std::move(webState) model:self]); | 270 [[Tab alloc] initWithWebState:std::move(webState) model:self]); |
| 266 [tab webController].usePlaceholderOverlay = YES; | 271 [tab webController].usePlaceholderOverlay = YES; |
| 267 [tab fetchFavicon]; | 272 [tab fetchFavicon]; |
| 268 [_tabs addObject:tab]; | 273 [self addWebState:tab]; |
| 269 | 274 |
| 270 TabParentingGlobalObserver::GetInstance()->OnTabParented( | 275 TabParentingGlobalObserver::GetInstance()->OnTabParented( |
| 271 [tab webStateImpl]); | 276 [tab webStateImpl]); |
| 272 } | 277 } |
| 273 if ([_tabs count]) { | 278 if (self.count) { |
| 274 DCHECK(window.selectedIndex < [_tabs count]); | 279 DCHECK(window.selectedIndex < self.count); |
| 275 _currentTab.reset([self tabAtIndex:window.selectedIndex]); | 280 _currentTab.reset([self tabAtIndex:window.selectedIndex]); |
| 276 DCHECK(_currentTab); | 281 DCHECK(_currentTab); |
| 277 if (_tabUsageRecorder) | 282 if (_tabUsageRecorder) { |
| 278 _tabUsageRecorder->InitialRestoredTabs(_currentTab, _tabs); | 283 _tabUsageRecorder->InitialRestoredTabs(_currentTab, |
| 284 GetTabsFromWebStateList(self)); |
| 285 } |
| 279 // Perform initializations for affiliated objects which update the | 286 // Perform initializations for affiliated objects which update the |
| 280 // session information related to the current tab. | 287 // session information related to the current tab. |
| 281 [_currentTab updateLastVisitedTimestamp]; | 288 [_currentTab updateLastVisitedTimestamp]; |
| 282 [self saveSessionImmediately:NO]; | 289 [self saveSessionImmediately:NO]; |
| 283 } | 290 } |
| 284 } | 291 } |
| 285 | 292 |
| 286 _orderController.reset( | 293 _orderController.reset( |
| 287 [[TabModelOrderController alloc] initWithTabModel:self]); | 294 [[TabModelOrderController alloc] initWithTabModel:self]); |
| 288 // Register for resign active notification. | 295 // Register for resign active notification. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 310 - (instancetype)init { | 317 - (instancetype)init { |
| 311 NOTREACHED(); | 318 NOTREACHED(); |
| 312 return nil; | 319 return nil; |
| 313 } | 320 } |
| 314 | 321 |
| 315 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { | 322 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { |
| 316 DCHECK(_browserState); | 323 DCHECK(_browserState); |
| 317 DCHECK(window); | 324 DCHECK(window); |
| 318 if (!window.unclaimedSessions) | 325 if (!window.unclaimedSessions) |
| 319 return NO; | 326 return NO; |
| 320 size_t oldCount = [_tabs count]; | 327 size_t oldCount = self.count; |
| 321 size_t index = oldCount; | 328 size_t index = oldCount; |
| 322 while (window.unclaimedSessions) { | 329 while (window.unclaimedSessions) { |
| 323 std::unique_ptr<web::WebStateImpl> webState = [window nextSession]; | 330 std::unique_ptr<web::WebStateImpl> webState = [window nextSession]; |
| 324 DCHECK_EQ(webState->GetBrowserState(), _browserState); | 331 DCHECK_EQ(webState->GetBrowserState(), _browserState); |
| 325 Tab* tab = [self insertTabWithWebState:std::move(webState) atIndex:index++]; | 332 Tab* tab = [self insertTabWithWebState:std::move(webState) atIndex:index++]; |
| 326 tab.webController.usePlaceholderOverlay = YES; | 333 tab.webController.usePlaceholderOverlay = YES; |
| 327 // Restore the CertificatePolicyCache. Note that after calling Pass() | 334 // Restore the CertificatePolicyCache. Note that after calling Pass() |
| 328 // |webState| is invalid, so we need to get the webstate from |tab|. | 335 // |webState| is invalid, so we need to get the webstate from |tab|. |
| 329 UpdateCertificatePolicyCacheFromWebState(tab.webStateImpl); | 336 UpdateCertificatePolicyCacheFromWebState(tab.webStateImpl); |
| 330 } | 337 } |
| 331 DCHECK([_tabs count] > oldCount); | 338 DCHECK(self.count > oldCount); |
| 332 // If any tab was restored, the saved selected tab must be selected. | 339 // If any tab was restored, the saved selected tab must be selected. |
| 333 if ([_tabs count] > oldCount) { | 340 if (self.count > oldCount) { |
| 334 NSUInteger selectedIndex = window.selectedIndex; | 341 NSUInteger selectedIndex = window.selectedIndex; |
| 335 if (selectedIndex == NSNotFound) | 342 if (selectedIndex == NSNotFound) |
| 336 selectedIndex = oldCount; | 343 selectedIndex = oldCount; |
| 337 else | 344 else |
| 338 selectedIndex += oldCount; | 345 selectedIndex += oldCount; |
| 339 DCHECK(selectedIndex < [_tabs count]); | 346 DCHECK(selectedIndex < self.count); |
| 340 Tab* newTab = [self tabAtIndex:selectedIndex]; | 347 Tab* newTab = [self tabAtIndex:selectedIndex]; |
| 341 DCHECK(newTab); | 348 DCHECK(newTab); |
| 342 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES]; | 349 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES]; |
| 343 | 350 |
| 344 // If there was only one tab and it was the new tab page, clobber it. | 351 // If there was only one tab and it was the new tab page, clobber it. |
| 345 if (oldCount == 1) { | 352 if (oldCount == 1) { |
| 346 Tab* tab = [_tabs objectAtIndex:0]; | 353 Tab* tab = [self firstWebState]; |
| 347 if (tab.url == GURL(kChromeUINewTabURL)) { | 354 if (tab.url == GURL(kChromeUINewTabURL)) { |
| 348 [self closeTab:tab]; | 355 [self closeTab:tab]; |
| 349 if (_tabUsageRecorder) | 356 if (_tabUsageRecorder) { |
| 350 _tabUsageRecorder->InitialRestoredTabs(_currentTab, _tabs); | 357 _tabUsageRecorder->InitialRestoredTabs(_currentTab, |
| 358 GetTabsFromWebStateList(self)); |
| 359 } |
| 351 return YES; | 360 return YES; |
| 352 } | 361 } |
| 353 } | 362 } |
| 354 if (_tabUsageRecorder) { | 363 if (_tabUsageRecorder) { |
| 355 _tabUsageRecorder->InitialRestoredTabs( | 364 _tabUsageRecorder->InitialRestoredTabs( |
| 356 _currentTab, | 365 _currentTab, |
| 357 [_tabs subarrayWithRange:NSMakeRange(oldCount, | 366 [GetTabsFromWebStateList(self) |
| 358 [_tabs count] - oldCount)]); | 367 subarrayWithRange:NSMakeRange(oldCount, self.count - oldCount)]); |
| 359 } | 368 } |
| 360 } | 369 } |
| 361 return NO; | 370 return NO; |
| 362 } | 371 } |
| 363 | 372 |
| 364 - (void)saveSessionImmediately:(BOOL)immediately { | 373 - (void)saveSessionImmediately:(BOOL)immediately { |
| 365 // Do nothing if there are tabs in the model but no selected tab. This is | 374 // Do nothing if there are tabs in the model but no selected tab. This is |
| 366 // a transitional state. | 375 // a transitional state. |
| 367 if ((!_currentTab && [_tabs count]) || !_browserState) | 376 if ((!_currentTab && self.count) || !_browserState) |
| 368 return; | 377 return; |
| 369 [_sessionService saveWindow:self.windowForSavingSession | 378 [_sessionService saveWindow:self.windowForSavingSession |
| 370 forBrowserState:_browserState | 379 forBrowserState:_browserState |
| 371 immediately:immediately]; | 380 immediately:immediately]; |
| 372 } | 381 } |
| 373 | 382 |
| 374 - (Tab*)tabAtIndex:(NSUInteger)index { | 383 - (Tab*)tabAtIndex:(NSUInteger)index { |
| 375 return [_tabs objectAtIndex:index]; | 384 return [self webStateAtIndex:index]; |
| 376 } | 385 } |
| 377 | 386 |
| 378 - (NSUInteger)indexOfTab:(Tab*)tab { | 387 - (NSUInteger)indexOfTab:(Tab*)tab { |
| 379 return [_tabs indexOfObject:tab]; | 388 return [self indexOfWebState:tab]; |
| 380 } | 389 } |
| 381 | 390 |
| 382 - (Tab*)tabWithWindowName:(NSString*)windowName { | 391 - (Tab*)tabWithWindowName:(NSString*)windowName { |
| 383 if (!windowName) | 392 if (!windowName) |
| 384 return nil; | 393 return nil; |
| 385 for (Tab* tab in _tabs.get()) { | 394 for (Tab* tab in self) { |
| 386 if ([windowName isEqualToString:tab.windowName]) { | 395 if ([windowName isEqualToString:tab.windowName]) { |
| 387 return tab; | 396 return tab; |
| 388 } | 397 } |
| 389 } | 398 } |
| 390 return nil; | 399 return nil; |
| 391 } | 400 } |
| 392 | 401 |
| 393 - (Tab*)nextTabWithOpener:(Tab*)tab afterTab:(Tab*)afterTab { | 402 - (Tab*)nextTabWithOpener:(Tab*)tab afterTab:(Tab*)afterTab { |
| 394 NSUInteger startIndex = NSNotFound; | 403 NSUInteger startIndex = NSNotFound; |
| 395 // Start looking after |afterTab|. If it's not found, start looking after | 404 // Start looking after |afterTab|. If it's not found, start looking after |
| 396 // |tab|. If it's not found either, bail. | 405 // |tab|. If it's not found either, bail. |
| 397 if (afterTab) | 406 if (afterTab) |
| 398 startIndex = [self indexOfTab:afterTab]; | 407 startIndex = [self indexOfTab:afterTab]; |
| 399 if (startIndex == NSNotFound) | 408 if (startIndex == NSNotFound) |
| 400 startIndex = [self indexOfTab:tab]; | 409 startIndex = [self indexOfTab:tab]; |
| 401 if (startIndex == NSNotFound) | 410 if (startIndex == NSNotFound) |
| 402 return nil; | 411 return nil; |
| 403 NSString* parentID = [tab currentSessionID]; | 412 NSString* parentID = [tab currentSessionID]; |
| 404 for (NSUInteger i = startIndex + 1; i < [_tabs count]; ++i) { | 413 for (NSUInteger i = startIndex + 1; i < self.count; ++i) { |
| 405 Tab* current = [_tabs objectAtIndex:i]; | 414 Tab* current = [self webStateAtIndex:i]; |
| 406 DCHECK([current navigationManager]); | 415 DCHECK([current navigationManager]); |
| 407 CRWSessionController* sessionController = | 416 CRWSessionController* sessionController = |
| 408 [current navigationManager]->GetSessionController(); | 417 [current navigationManager]->GetSessionController(); |
| 409 if ([sessionController.openerId isEqualToString:parentID]) | 418 if ([sessionController.openerId isEqualToString:parentID]) |
| 410 return current; | 419 return current; |
| 411 } | 420 } |
| 412 return nil; | 421 return nil; |
| 413 } | 422 } |
| 414 | 423 |
| 415 - (Tab*)firstTabWithOpener:(Tab*)tab { | 424 - (Tab*)firstTabWithOpener:(Tab*)tab { |
| 416 if (!tab) | 425 if (!tab) |
| 417 return nil; | 426 return nil; |
| 418 NSUInteger stopIndex = [self indexOfTab:tab]; | 427 NSUInteger stopIndex = [self indexOfTab:tab]; |
| 419 if (stopIndex == NSNotFound) | 428 if (stopIndex == NSNotFound) |
| 420 return nil; | 429 return nil; |
| 421 NSString* parentID = [tab currentSessionID]; | 430 NSString* parentID = [tab currentSessionID]; |
| 422 // Match the navigation index as well as the session id, to better match the | 431 // Match the navigation index as well as the session id, to better match the |
| 423 // state of the tab. I.e. two tabs are opened via a link from tab A, and then | 432 // state of the tab. I.e. two tabs are opened via a link from tab A, and then |
| 424 // a new url is loaded into tab A, and more tabs opened from that url, the | 433 // a new url is loaded into tab A, and more tabs opened from that url, the |
| 425 // latter two tabs should not be grouped with the former two. The navigation | 434 // latter two tabs should not be grouped with the former two. The navigation |
| 426 // index is the simplest way to detect navigation changes. | 435 // index is the simplest way to detect navigation changes. |
| 427 DCHECK([tab navigationManager]); | 436 DCHECK([tab navigationManager]); |
| 428 NSInteger parentNavIndex = [tab navigationManager]->GetCurrentItemIndex(); | 437 NSInteger parentNavIndex = [tab navigationManager]->GetCurrentItemIndex(); |
| 429 for (NSUInteger i = 0; i < stopIndex; ++i) { | 438 for (NSUInteger i = 0; i < stopIndex; ++i) { |
| 430 Tab* tabToCheck = [_tabs objectAtIndex:i]; | 439 Tab* tabToCheck = [self webStateAtIndex:i]; |
| 431 DCHECK([tabToCheck navigationManager]); | 440 DCHECK([tabToCheck navigationManager]); |
| 432 CRWSessionController* sessionController = | 441 CRWSessionController* sessionController = |
| 433 [tabToCheck navigationManager]->GetSessionController(); | 442 [tabToCheck navigationManager]->GetSessionController(); |
| 434 if ([sessionController.openerId isEqualToString:parentID] && | 443 if ([sessionController.openerId isEqualToString:parentID] && |
| 435 sessionController.openerNavigationIndex == parentNavIndex) { | 444 sessionController.openerNavigationIndex == parentNavIndex) { |
| 436 return tabToCheck; | 445 return tabToCheck; |
| 437 } | 446 } |
| 438 } | 447 } |
| 439 return nil; | 448 return nil; |
| 440 } | 449 } |
| 441 | 450 |
| 442 - (Tab*)lastTabWithOpener:(Tab*)tab { | 451 - (Tab*)lastTabWithOpener:(Tab*)tab { |
| 443 NSUInteger startIndex = [self indexOfTab:tab]; | 452 NSUInteger startIndex = [self indexOfTab:tab]; |
| 444 if (startIndex == NSNotFound) | 453 if (startIndex == NSNotFound) |
| 445 return nil; | 454 return nil; |
| 446 // There is at least one tab in the model, because otherwise the above check | 455 // There is at least one tab in the model, because otherwise the above check |
| 447 // would have returned. | 456 // would have returned. |
| 448 NSString* parentID = [tab currentSessionID]; | 457 NSString* parentID = [tab currentSessionID]; |
| 449 DCHECK([tab navigationManager]); | 458 DCHECK([tab navigationManager]); |
| 450 NSInteger parentNavIndex = [tab navigationManager]->GetCurrentItemIndex(); | 459 NSInteger parentNavIndex = [tab navigationManager]->GetCurrentItemIndex(); |
| 451 | 460 |
| 452 Tab* match = nil; | 461 Tab* match = nil; |
| 453 // Find the last tab in the first matching 'group'. A 'group' is a set of | 462 // Find the last tab in the first matching 'group'. A 'group' is a set of |
| 454 // tabs whose opener's id and opener's navigation index match. The navigation | 463 // tabs whose opener's id and opener's navigation index match. The navigation |
| 455 // index is used in addition to the session id to detect navigations changes | 464 // index is used in addition to the session id to detect navigations changes |
| 456 // within the same session. | 465 // within the same session. |
| 457 for (NSUInteger i = startIndex + 1; i < [_tabs count]; ++i) { | 466 for (NSUInteger i = startIndex + 1; i < self.count; ++i) { |
| 458 Tab* tabToCheck = [_tabs objectAtIndex:i]; | 467 Tab* tabToCheck = [self webStateAtIndex:i]; |
| 459 DCHECK([tabToCheck navigationManager]); | 468 DCHECK([tabToCheck navigationManager]); |
| 460 CRWSessionController* sessionController = | 469 CRWSessionController* sessionController = |
| 461 [tabToCheck navigationManager]->GetSessionController(); | 470 [tabToCheck navigationManager]->GetSessionController(); |
| 462 if ([sessionController.openerId isEqualToString:parentID] && | 471 if ([sessionController.openerId isEqualToString:parentID] && |
| 463 sessionController.openerNavigationIndex == parentNavIndex) { | 472 sessionController.openerNavigationIndex == parentNavIndex) { |
| 464 match = tabToCheck; | 473 match = tabToCheck; |
| 465 } else if (match) { | 474 } else if (match) { |
| 466 break; | 475 break; |
| 467 } | 476 } |
| 468 } | 477 } |
| 469 return match; | 478 return match; |
| 470 } | 479 } |
| 471 | 480 |
| 472 - (Tab*)openerOfTab:(Tab*)tab { | 481 - (Tab*)openerOfTab:(Tab*)tab { |
| 473 if (![tab navigationManager]) | 482 if (![tab navigationManager]) |
| 474 return nil; | 483 return nil; |
| 475 NSString* opener = [tab navigationManager]->GetSessionController().openerId; | 484 NSString* opener = [tab navigationManager]->GetSessionController().openerId; |
| 476 if (!opener.length) // Short-circuit if opener is empty. | 485 if (!opener.length) // Short-circuit if opener is empty. |
| 477 return nil; | 486 return nil; |
| 478 for (Tab* iteratedTab in _tabs.get()) { | 487 for (Tab* iteratedTab in self) { |
| 479 if ([[iteratedTab currentSessionID] isEqualToString:opener]) | 488 if ([[iteratedTab currentSessionID] isEqualToString:opener]) |
| 480 return iteratedTab; | 489 return iteratedTab; |
| 481 } | 490 } |
| 482 return nil; | 491 return nil; |
| 483 } | 492 } |
| 484 | 493 |
| 485 - (Tab*)insertOrUpdateTabWithURL:(const GURL&)URL | 494 - (Tab*)insertOrUpdateTabWithURL:(const GURL&)URL |
| 486 referrer:(const web::Referrer&)referrer | 495 referrer:(const web::Referrer&)referrer |
| 487 transition:(ui::PageTransition)transition | 496 transition:(ui::PageTransition)transition |
| 488 windowName:(NSString*)windowName | 497 windowName:(NSString*)windowName |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 DCHECK_EQ(webState->GetBrowserState(), _browserState); | 570 DCHECK_EQ(webState->GetBrowserState(), _browserState); |
| 562 base::scoped_nsobject<Tab> tab( | 571 base::scoped_nsobject<Tab> tab( |
| 563 [[Tab alloc] initWithWebState:std::move(webState) model:self]); | 572 [[Tab alloc] initWithWebState:std::move(webState) model:self]); |
| 564 [tab webController].webUsageEnabled = webUsageEnabled_; | 573 [tab webController].webUsageEnabled = webUsageEnabled_; |
| 565 [self insertTab:tab atIndex:index]; | 574 [self insertTab:tab atIndex:index]; |
| 566 return tab; | 575 return tab; |
| 567 } | 576 } |
| 568 | 577 |
| 569 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { | 578 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { |
| 570 DCHECK(tab); | 579 DCHECK(tab); |
| 571 DCHECK(index <= [_tabs count]); | 580 DCHECK(index <= self.count); |
| 572 [tab fetchFavicon]; | 581 [tab fetchFavicon]; |
| 573 [_tabs insertObject:tab atIndex:index]; | 582 [self insertWebState:tab atIndex:index]; |
| 574 | 583 |
| 575 [_observers tabModel:self didInsertTab:tab atIndex:index inForeground:NO]; | 584 [_observers tabModel:self didInsertTab:tab atIndex:index inForeground:NO]; |
| 576 [_observers tabModelDidChangeTabCount:self]; | 585 [_observers tabModelDidChangeTabCount:self]; |
| 577 | 586 |
| 578 base::RecordAction(base::UserMetricsAction("MobileNewTabOpened")); | 587 base::RecordAction(base::UserMetricsAction("MobileNewTabOpened")); |
| 579 // Persist the session due to a new tab being inserted. If this is a | 588 // Persist the session due to a new tab being inserted. If this is a |
| 580 // background tab (will not become active), saving now will capture the | 589 // background tab (will not become active), saving now will capture the |
| 581 // state properly. If it does eventually become active, another save will | 590 // state properly. If it does eventually become active, another save will |
| 582 // be triggered to properly capture the end result. | 591 // be triggered to properly capture the end result. |
| 583 [self saveSessionImmediately:NO]; | 592 [self saveSessionImmediately:NO]; |
| 584 ++_newTabCount; | 593 ++_newTabCount; |
| 585 } | 594 } |
| 586 | 595 |
| 587 - (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex { | 596 - (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex { |
| 588 NSUInteger fromIndex = [self indexOfTab:tab]; | 597 NSUInteger fromIndex = [self indexOfTab:tab]; |
| 589 DCHECK_NE(NSNotFound, static_cast<NSInteger>(fromIndex)); | 598 DCHECK_NE(NSNotFound, static_cast<NSInteger>(fromIndex)); |
| 590 DCHECK_LT(toIndex, self.count); | 599 DCHECK_LT(toIndex, self.count); |
| 591 if (fromIndex == NSNotFound || toIndex >= self.count || | 600 if (fromIndex == NSNotFound || toIndex >= self.count || |
| 592 fromIndex == toIndex) { | 601 fromIndex == toIndex) { |
| 593 return; | 602 return; |
| 594 } | 603 } |
| 595 | 604 |
| 596 base::scoped_nsobject<Tab> tabSaver([tab retain]); | 605 base::scoped_nsobject<Tab> tabSaver([tab retain]); |
| 597 [_tabs removeObject:tab]; | 606 [self removeWebState:tab]; |
| 598 [_tabs insertObject:tab atIndex:toIndex]; | 607 [self insertWebState:tab atIndex:toIndex]; |
| 599 | 608 |
| 600 [_observers tabModel:self didMoveTab:tab fromIndex:fromIndex toIndex:toIndex]; | 609 [_observers tabModel:self didMoveTab:tab fromIndex:fromIndex toIndex:toIndex]; |
| 601 } | 610 } |
| 602 | 611 |
| 603 - (void)replaceTab:(Tab*)oldTab | 612 - (void)replaceTab:(Tab*)oldTab |
| 604 withTab:(Tab*)newTab | 613 withTab:(Tab*)newTab |
| 605 keepOldTabOpen:(BOOL)keepOldTabOpen { | 614 keepOldTabOpen:(BOOL)keepOldTabOpen { |
| 606 NSUInteger index = [self indexOfTab:oldTab]; | 615 NSUInteger index = [self indexOfTab:oldTab]; |
| 607 DCHECK_NE(NSNotFound, static_cast<NSInteger>(index)); | 616 DCHECK_NE(NSNotFound, static_cast<NSInteger>(index)); |
| 608 | 617 |
| 609 base::scoped_nsobject<Tab> tabSaver([oldTab retain]); | 618 base::scoped_nsobject<Tab> tabSaver([oldTab retain]); |
| 610 [newTab fetchFavicon]; | 619 [newTab fetchFavicon]; |
| 611 [_tabs replaceObjectAtIndex:index withObject:newTab]; | 620 [self replaceWebStateAtIndex:index withWebState:newTab]; |
| 612 [newTab setParentTabModel:self]; | 621 [newTab setParentTabModel:self]; |
| 613 | 622 |
| 614 [_observers tabModel:self didReplaceTab:oldTab withTab:newTab atIndex:index]; | 623 [_observers tabModel:self didReplaceTab:oldTab withTab:newTab atIndex:index]; |
| 615 | 624 |
| 616 if (self.currentTab == oldTab) | 625 if (self.currentTab == oldTab) |
| 617 [self changeSelectedTabFrom:nil to:newTab persistState:NO]; | 626 [self changeSelectedTabFrom:nil to:newTab persistState:NO]; |
| 618 | 627 |
| 619 [oldTab setParentTabModel:nil]; | 628 [oldTab setParentTabModel:nil]; |
| 620 if (!keepOldTabOpen) | 629 if (!keepOldTabOpen) |
| 621 [oldTab close]; | 630 [oldTab close]; |
| 622 | 631 |
| 623 // Record a tab clobber, since swapping tabs bypasses the tab code that would | 632 // Record a tab clobber, since swapping tabs bypasses the tab code that would |
| 624 // normally log clobbers. | 633 // normally log clobbers. |
| 625 base::RecordAction(base::UserMetricsAction("MobileTabClobbered")); | 634 base::RecordAction(base::UserMetricsAction("MobileTabClobbered")); |
| 626 } | 635 } |
| 627 | 636 |
| 628 - (void)closeTabAtIndex:(NSUInteger)index { | 637 - (void)closeTabAtIndex:(NSUInteger)index { |
| 629 DCHECK(index < [_tabs count]); | 638 DCHECK(index < self.count); |
| 630 [self closeTab:[_tabs objectAtIndex:index]]; | 639 [self closeTab:[self webStateAtIndex:index]]; |
| 631 } | 640 } |
| 632 | 641 |
| 633 - (void)closeTab:(Tab*)tab { | 642 - (void)closeTab:(Tab*)tab { |
| 634 // Ensure the tab stays alive long enough for us to send out the | 643 // Ensure the tab stays alive long enough for us to send out the |
| 635 // notice of its destruction to the delegate. | 644 // notice of its destruction to the delegate. |
| 636 [_observers tabModel:self willRemoveTab:tab]; | 645 [_observers tabModel:self willRemoveTab:tab]; |
| 637 [tab close]; // Note it is not safe to access the tab after 'close'. | 646 [tab close]; // Note it is not safe to access the tab after 'close'. |
| 638 } | 647 } |
| 639 | 648 |
| 640 - (void)closeAllTabs { | 649 - (void)closeAllTabs { |
| 641 // If this changes, _closedTabCount metrics need to be adjusted. | 650 // If this changes, _closedTabCount metrics need to be adjusted. |
| 642 for (NSInteger i = self.count - 1; i >= 0; --i) | 651 for (NSInteger i = self.count - 1; i >= 0; --i) |
| 643 [self closeTabAtIndex:i]; | 652 [self closeTabAtIndex:i]; |
| 644 [[NSNotificationCenter defaultCenter] | 653 [[NSNotificationCenter defaultCenter] |
| 645 postNotificationName:kTabModelAllTabsDidCloseNotification | 654 postNotificationName:kTabModelAllTabsDidCloseNotification |
| 646 object:self]; | 655 object:self]; |
| 647 } | 656 } |
| 648 | 657 |
| 649 - (void)haltAllTabs { | 658 - (void)haltAllTabs { |
| 650 for (Tab* tab in _tabs.get()) { | 659 for (Tab* tab in self) { |
| 651 [tab terminateNetworkActivity]; | 660 [tab terminateNetworkActivity]; |
| 652 } | 661 } |
| 653 } | 662 } |
| 654 | 663 |
| 655 - (void)notifyTabChanged:(Tab*)tab { | 664 - (void)notifyTabChanged:(Tab*)tab { |
| 656 [_observers tabModel:self didChangeTab:tab]; | 665 [_observers tabModel:self didChangeTab:tab]; |
| 657 } | 666 } |
| 658 | 667 |
| 659 - (void)addObserver:(id<TabModelObserver>)observer { | 668 - (void)addObserver:(id<TabModelObserver>)observer { |
| 660 [_observers addObserver:observer]; | 669 [_observers addObserver:observer]; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 677 200, 50); | 686 200, 50); |
| 678 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.NewTabCounts", _newTabCount, 1, 200, 50); | 687 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.NewTabCounts", _newTabCount, 1, 200, 50); |
| 679 } | 688 } |
| 680 | 689 |
| 681 - (void)notifyTabSnapshotChanged:(Tab*)tab withImage:(UIImage*)image { | 690 - (void)notifyTabSnapshotChanged:(Tab*)tab withImage:(UIImage*)image { |
| 682 DCHECK([NSThread isMainThread]); | 691 DCHECK([NSThread isMainThread]); |
| 683 [_observers tabModel:self didChangeTabSnapshot:tab withImage:image]; | 692 [_observers tabModel:self didChangeTabSnapshot:tab withImage:image]; |
| 684 } | 693 } |
| 685 | 694 |
| 686 - (void)resetAllWebViews { | 695 - (void)resetAllWebViews { |
| 687 for (Tab* tab in _tabs.get()) { | 696 for (Tab* tab in self) { |
| 688 [tab.webController reinitializeWebViewAndReload:(tab == _currentTab)]; | 697 [tab.webController reinitializeWebViewAndReload:(tab == _currentTab)]; |
| 689 } | 698 } |
| 690 } | 699 } |
| 691 | 700 |
| 692 - (void)setWebUsageEnabled:(BOOL)webUsageEnabled { | 701 - (void)setWebUsageEnabled:(BOOL)webUsageEnabled { |
| 693 if (webUsageEnabled_ == webUsageEnabled) | 702 if (webUsageEnabled_ == webUsageEnabled) |
| 694 return; | 703 return; |
| 695 webUsageEnabled_ = webUsageEnabled; | 704 webUsageEnabled_ = webUsageEnabled; |
| 696 for (Tab* tab in _tabs.get()) { | 705 for (Tab* tab in self) { |
| 697 tab.webUsageEnabled = webUsageEnabled; | 706 tab.webUsageEnabled = webUsageEnabled; |
| 698 } | 707 } |
| 699 } | 708 } |
| 700 | 709 |
| 701 - (void)setPrimary:(BOOL)primary { | 710 - (void)setPrimary:(BOOL)primary { |
| 702 if (_tabUsageRecorder) | 711 if (_tabUsageRecorder) |
| 703 _tabUsageRecorder->RecordPrimaryTabModelChange(primary, _currentTab); | 712 _tabUsageRecorder->RecordPrimaryTabModelChange(primary, _currentTab); |
| 704 } | 713 } |
| 705 | 714 |
| 706 - (NSSet*)currentlyReferencedExternalFiles { | 715 - (NSSet*)currentlyReferencedExternalFiles { |
| 707 NSMutableSet* referencedFiles = [NSMutableSet set]; | 716 NSMutableSet* referencedFiles = [NSMutableSet set]; |
| 708 if (!_browserState) | 717 if (!_browserState) |
| 709 return referencedFiles; | 718 return referencedFiles; |
| 710 // Check the currently open tabs for external files. | 719 // Check the currently open tabs for external files. |
| 711 for (Tab* tab in _tabs.get()) { | 720 for (Tab* tab in self) { |
| 712 if (UrlIsExternalFileReference(tab.url)) { | 721 if (UrlIsExternalFileReference(tab.url)) { |
| 713 NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName()); | 722 NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName()); |
| 714 [referencedFiles addObject:fileName]; | 723 [referencedFiles addObject:fileName]; |
| 715 } | 724 } |
| 716 } | 725 } |
| 717 // Do the same for the recently closed tabs. | 726 // Do the same for the recently closed tabs. |
| 718 sessions::TabRestoreService* restoreService = | 727 sessions::TabRestoreService* restoreService = |
| 719 IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState); | 728 IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState); |
| 720 DCHECK(restoreService); | 729 DCHECK(restoreService); |
| 721 for (const auto& entry : restoreService->entries()) { | 730 for (const auto& entry : restoreService->entries()) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 738 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 747 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 739 if (_browserState) { | 748 if (_browserState) { |
| 740 UnregisterTabModelFromChromeBrowserState(_browserState, self); | 749 UnregisterTabModelFromChromeBrowserState(_browserState, self); |
| 741 } | 750 } |
| 742 _browserState = nullptr; | 751 _browserState = nullptr; |
| 743 } | 752 } |
| 744 | 753 |
| 745 // Called when a tab is closing, but before its CRWWebController is destroyed. | 754 // Called when a tab is closing, but before its CRWWebController is destroyed. |
| 746 // Equivalent to DetachTabContentsAt() in Chrome's TabStripModel. | 755 // Equivalent to DetachTabContentsAt() in Chrome's TabStripModel. |
| 747 - (void)didCloseTab:(Tab*)closedTab { | 756 - (void)didCloseTab:(Tab*)closedTab { |
| 748 NSUInteger closedTabIndex = [_tabs indexOfObject:closedTab]; | 757 NSUInteger closedTabIndex = [self indexOfWebState:closedTab]; |
| 749 DCHECK(closedTab); | 758 DCHECK(closedTab); |
| 750 DCHECK(closedTabIndex != NSNotFound); | 759 DCHECK(closedTabIndex != NSNotFound); |
| 751 // Let the sessions::TabRestoreService know about that new tab. | 760 // Let the sessions::TabRestoreService know about that new tab. |
| 752 sessions::TabRestoreService* restoreService = | 761 sessions::TabRestoreService* restoreService = |
| 753 _browserState | 762 _browserState |
| 754 ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState) | 763 ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState) |
| 755 : nullptr; | 764 : nullptr; |
| 756 web::NavigationManagerImpl* navigationManager = [closedTab navigationManager]; | 765 web::NavigationManagerImpl* navigationManager = [closedTab navigationManager]; |
| 757 DCHECK(navigationManager); | 766 DCHECK(navigationManager); |
| 758 int itemCount = navigationManager->GetItemCount(); | 767 int itemCount = navigationManager->GetItemCount(); |
| 759 if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) { | 768 if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) { |
| 760 restoreService->CreateHistoricalTab( | 769 restoreService->CreateHistoricalTab( |
| 761 sessions::IOSLiveTab::GetForWebState(closedTab.webStateImpl), | 770 sessions::IOSLiveTab::GetForWebState(closedTab.webStateImpl), |
| 762 static_cast<int>(closedTabIndex)); | 771 static_cast<int>(closedTabIndex)); |
| 763 } | 772 } |
| 764 // This needs to be called before the tab is removed from the list. | 773 // This needs to be called before the tab is removed from the list. |
| 765 Tab* newSelection = | 774 Tab* newSelection = |
| 766 [_orderController determineNewSelectedTabFromRemovedTab:closedTab]; | 775 [_orderController determineNewSelectedTabFromRemovedTab:closedTab]; |
| 767 base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]); | 776 base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]); |
| 768 [_tabs removeObject:closedTab]; | 777 [self removeWebState:closedTab]; |
| 769 | 778 |
| 770 // If closing the current tab, clear |_currentTab| before sending any | 779 // If closing the current tab, clear |_currentTab| before sending any |
| 771 // notification. This avoids various parts of the code getting confused | 780 // notification. This avoids various parts of the code getting confused |
| 772 // when the current tab isn't in the tab model. | 781 // when the current tab isn't in the tab model. |
| 773 Tab* savedCurrentTab = _currentTab; | 782 Tab* savedCurrentTab = _currentTab; |
| 774 if (closedTab == _currentTab) | 783 if (closedTab == _currentTab) |
| 775 _currentTab.reset(nil); | 784 _currentTab.reset(nil); |
| 776 | 785 |
| 777 [_observers tabModel:self didRemoveTab:closedTab atIndex:closedTabIndex]; | 786 [_observers tabModel:self didRemoveTab:closedTab atIndex:closedTabIndex]; |
| 778 [_observers tabModelDidChangeTabCount:self]; | 787 [_observers tabModelDidChangeTabCount:self]; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 809 if (previousURL.ReplaceComponents(replacements) == | 818 if (previousURL.ReplaceComponents(replacements) == |
| 810 currentURL.ReplaceComponents(replacements)) { | 819 currentURL.ReplaceComponents(replacements)) { |
| 811 return; | 820 return; |
| 812 } | 821 } |
| 813 } | 822 } |
| 814 | 823 |
| 815 int tabCount = static_cast<int>(self.count); | 824 int tabCount = static_cast<int>(self.count); |
| 816 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tabCount, 1, 200, 50); | 825 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tabCount, 1, 200, 50); |
| 817 } | 826 } |
| 818 | 827 |
| 819 #pragma mark - NSFastEnumeration | |
| 820 | |
| 821 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state | |
| 822 objects:(id*)objects | |
| 823 count:(NSUInteger)count { | |
| 824 return [_tabs countByEnumeratingWithState:state objects:objects count:count]; | |
| 825 } | |
| 826 | |
| 827 #pragma mark - TabUsageRecorderDelegate | 828 #pragma mark - TabUsageRecorderDelegate |
| 828 | 829 |
| 829 - (NSUInteger)liveTabsCount { | 830 - (NSUInteger)liveTabsCount { |
| 830 NSUInteger count = 0; | 831 NSUInteger count = 0; |
| 831 NSArray* tabs = _tabs.get(); | 832 for (Tab* tab in self) { |
| 832 for (Tab* tab in tabs) { | |
| 833 if ([tab.webController isViewAlive]) | 833 if ([tab.webController isViewAlive]) |
| 834 count++; | 834 count++; |
| 835 } | 835 } |
| 836 return count; | 836 return count; |
| 837 } | 837 } |
| 838 | 838 |
| 839 #pragma mark - Private methods | 839 #pragma mark - Private methods |
| 840 | 840 |
| 841 - (SessionWindowIOS*)windowForSavingSession { | 841 - (SessionWindowIOS*)windowForSavingSession { |
| 842 // Background tabs will already have their state preserved, but not the | 842 // Background tabs will already have their state preserved, but not the |
| 843 // fg tab. Do it now. | 843 // fg tab. Do it now. |
| 844 [_currentTab recordStateInHistory]; | 844 [_currentTab recordStateInHistory]; |
| 845 | 845 |
| 846 // Build the array of sessions. Copy the session objects as the saving will | 846 // Build the array of sessions. Copy the session objects as the saving will |
| 847 // be done on a separate thread. | 847 // be done on a separate thread. |
| 848 // TODO(crbug.com/661986): This could get expensive especially since this | 848 // TODO(crbug.com/661986): This could get expensive especially since this |
| 849 // window may never be saved (if another call comes in before the delay). | 849 // window may never be saved (if another call comes in before the delay). |
| 850 SessionWindowIOS* window = [[[SessionWindowIOS alloc] init] autorelease]; | 850 SessionWindowIOS* window = [[[SessionWindowIOS alloc] init] autorelease]; |
| 851 for (Tab* tab in _tabs.get()) { | 851 for (Tab* tab in self) { |
| 852 DCHECK(tab.webStateImpl); | 852 DCHECK(tab.webStateImpl); |
| 853 std::unique_ptr<web::WebStateImpl> webStateCopy( | 853 std::unique_ptr<web::WebStateImpl> webStateCopy( |
| 854 tab.webStateImpl->CopyForSessionWindow()); | 854 tab.webStateImpl->CopyForSessionWindow()); |
| 855 [window addSession:std::move(webStateCopy)]; | 855 [window addSession:std::move(webStateCopy)]; |
| 856 } | 856 } |
| 857 window.selectedIndex = [self indexOfTab:_currentTab]; | 857 window.selectedIndex = [self indexOfTab:_currentTab]; |
| 858 return window; | 858 return window; |
| 859 } | 859 } |
| 860 | 860 |
| 861 - (BOOL)isNTPTab:(Tab*)tab { | 861 - (BOOL)isNTPTab:(Tab*)tab { |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 - (void)applicationDidEnterBackground:(NSNotification*)notify { | 1006 - (void)applicationDidEnterBackground:(NSNotification*)notify { |
| 1007 if (!_browserState) | 1007 if (!_browserState) |
| 1008 return; | 1008 return; |
| 1009 // Evict all the certificate policies except for the current entries of the | 1009 // Evict all the certificate policies except for the current entries of the |
| 1010 // active sessions. | 1010 // active sessions. |
| 1011 scoped_refptr<web::CertificatePolicyCache> policy_cache = | 1011 scoped_refptr<web::CertificatePolicyCache> policy_cache = |
| 1012 web::BrowserState::GetCertificatePolicyCache(_browserState); | 1012 web::BrowserState::GetCertificatePolicyCache(_browserState); |
| 1013 DCHECK(policy_cache); | 1013 DCHECK(policy_cache); |
| 1014 web::WebThread::PostTask( | 1014 web::WebThread::PostTask( |
| 1015 web::WebThread::IO, FROM_HERE, | 1015 web::WebThread::IO, FROM_HERE, |
| 1016 base::Bind(&CleanCertificatePolicyCache, policy_cache, _tabs)); | 1016 base::Bind(&CleanCertificatePolicyCache, policy_cache, self)); |
| 1017 | 1017 |
| 1018 if (_tabUsageRecorder) | 1018 if (_tabUsageRecorder) |
| 1019 _tabUsageRecorder->AppDidEnterBackground(); | 1019 _tabUsageRecorder->AppDidEnterBackground(); |
| 1020 | 1020 |
| 1021 // Normally, the session is saved after some timer expires but since the app | 1021 // Normally, the session is saved after some timer expires but since the app |
| 1022 // is about to enter the background send YES to save the session immediately. | 1022 // is about to enter the background send YES to save the session immediately. |
| 1023 [self saveSessionImmediately:YES]; | 1023 [self saveSessionImmediately:YES]; |
| 1024 | 1024 |
| 1025 // Write out a grey version of the current website to disk. | 1025 // Write out a grey version of the current website to disk. |
| 1026 if (webUsageEnabled_ && _currentTab) { | 1026 if (webUsageEnabled_ && _currentTab) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 web::NavigationManager::WebLoadParams params(URL); | 1065 web::NavigationManager::WebLoadParams params(URL); |
| 1066 params.referrer = referrer; | 1066 params.referrer = referrer; |
| 1067 params.transition_type = ui::PAGE_TRANSITION_TYPED; | 1067 params.transition_type = ui::PAGE_TRANSITION_TYPED; |
| 1068 [[tab webController] loadWithParams:params]; | 1068 [[tab webController] loadWithParams:params]; |
| 1069 [tab webController].webUsageEnabled = webUsageEnabled_; | 1069 [tab webController].webUsageEnabled = webUsageEnabled_; |
| 1070 [self insertTab:tab atIndex:index]; | 1070 [self insertTab:tab atIndex:index]; |
| 1071 return tab; | 1071 return tab; |
| 1072 } | 1072 } |
| 1073 | 1073 |
| 1074 @end | 1074 @end |
| OLD | NEW |