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