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