Index: ios/chrome/browser/tabs/tab_model.mm |
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm |
index 7a5c68f84f4c48e2a8e148d0691eaf8d1d6f06d1..2a344082d667b86259ade56e52b5ad9f66d541aa 100644 |
--- a/ios/chrome/browser/tabs/tab_model.mm |
+++ b/ios/chrome/browser/tabs/tab_model.mm |
@@ -28,12 +28,16 @@ |
#import "ios/chrome/browser/sessions/session_window.h" |
#import "ios/chrome/browser/snapshots/snapshot_cache.h" |
#include "ios/chrome/browser/tab_parenting_global_observer.h" |
+#import "ios/chrome/browser/tabs/legacy_tab_helper.h" |
#import "ios/chrome/browser/tabs/tab.h" |
#import "ios/chrome/browser/tabs/tab_model_list.h" |
#import "ios/chrome/browser/tabs/tab_model_observers.h" |
#import "ios/chrome/browser/tabs/tab_model_order_controller.h" |
#import "ios/chrome/browser/tabs/tab_model_synced_window_delegate.h" |
#import "ios/chrome/browser/xcallback_parameters.h" |
+#import "ios/shared/chrome/browser/tabs/web_state_list.h" |
+#import "ios/shared/chrome/browser/tabs/web_state_list_fast_enumeration_helper.h" |
+#import "ios/shared/chrome/browser/tabs/web_state_list_observer.h" |
#import "ios/web/navigation/crw_session_certificate_policy_manager.h" |
#import "ios/web/navigation/crw_session_controller.h" |
#include "ios/web/public/browser_state.h" |
@@ -79,38 +83,51 @@ void UpdateCertificatePolicyCacheFromWebState( |
updateCertificatePolicyCache:policy_cache]; |
} |
-// Populates the certificate policy cache based on the WebStates of |tab_model|. |
+// Populates the certificate policy cache based on the WebStates of |
+// |web_state_list|. |
void RestoreCertificatePolicyCacheFromModel( |
const scoped_refptr<web::CertificatePolicyCache>& policy_cache, |
- TabModel* tab_model) { |
+ WebStateList* web_state_list) { |
DCHECK_CURRENTLY_ON(web::WebThread::UI); |
- for (Tab* tab in tab_model) |
- UpdateCertificatePolicyCacheFromWebState(policy_cache, tab.webState); |
+ for (size_t index = 0; index < web_state_list->count(); ++index) { |
+ UpdateCertificatePolicyCacheFromWebState( |
+ policy_cache, web_state_list->GetWebStateAt(index)); |
+ } |
} |
// Scrubs the certificate policy cache of all certificates policies except |
-// those for the current entries in |tab_model|. |
+// those for the current entries in |web_state_list|. |
void CleanCertificatePolicyCache( |
base::CancelableTaskTracker* task_tracker, |
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
const scoped_refptr<web::CertificatePolicyCache>& policy_cache, |
- TabModel* tab_model) { |
- DCHECK(tab_model); |
+ WebStateList* web_state_list) { |
DCHECK(policy_cache); |
+ DCHECK(web_state_list); |
DCHECK_CURRENTLY_ON(web::WebThread::UI); |
task_tracker->PostTaskAndReply( |
task_runner.get(), FROM_HERE, |
base::Bind(&web::CertificatePolicyCache::ClearCertificatePolicies, |
policy_cache), |
base::Bind(&RestoreCertificatePolicyCacheFromModel, policy_cache, |
- base::Unretained(tab_model))); |
+ base::Unretained(web_state_list))); |
} |
} // anonymous namespace |
-@interface TabModel ()<TabUsageRecorderDelegate> { |
- // Array of |Tab| objects. |
- base::scoped_nsobject<NSMutableArray> _tabs; |
+@interface TabModel ()<TabUsageRecorderDelegate, WebStateProxyFactory> { |
+ // Underlying shared model implementation. |
+ WebStateList _webStateList; |
+ |
+ // Helper providing NSFastEnumeration implementation over the WebStateList. |
+ base::scoped_nsobject<WebStateListFastEnumerationHelper> |
+ _fastEnumerationHelper; |
+ |
+ // Used to keep the Tabs alive while the corresponding WebStates are stored |
+ // in the WebStateList (as Tabs currently owns their WebState). Remove once |
rohitrao (ping after 24h)
2017/02/14 14:37:12
"own"
sdefresne
2017/02/14 16:45:46
Done.
|
+ // WebState owns the associated Tab. |
+ base::scoped_nsobject<NSMutableSet<Tab*>> _tabs; |
rohitrao (ping after 24h)
2017/02/14 14:37:12
Another naming option is to call this something li
sdefresne
2017/02/14 16:45:46
Done.
|
+ |
// Maintains policy for where new tabs go and the selection when a tab |
// is removed. |
base::scoped_nsobject<TabModelOrderController> _orderController; |
@@ -214,7 +231,7 @@ void CleanCertificatePolicyCache( |
} |
- (void)setCurrentTab:(Tab*)newTab { |
- DCHECK([_tabs containsObject:newTab]); |
+ DCHECK_NE([self indexOfTab:newTab], static_cast<NSUInteger>(NSNotFound)); |
if (_currentTab != newTab) { |
base::RecordAction(base::UserMetricsAction("MobileTabSwitched")); |
[self updateSnapshotCache:newTab]; |
@@ -238,19 +255,23 @@ void CleanCertificatePolicyCache( |
} |
- (BOOL)isEmpty { |
- return self.count == 0; |
+ return _webStateList.empty(); |
} |
- (NSUInteger)count { |
- return [_tabs count]; |
+ return _webStateList.count(); |
} |
- (instancetype)initWithSessionWindow:(SessionWindowIOS*)window |
sessionService:(SessionServiceIOS*)service |
browserState:(ios::ChromeBrowserState*)browserState { |
if ((self = [super init])) { |
- _observers.reset([[TabModelObservers |
- observersWithProtocol:@protocol(TabModelObserver)] retain]); |
+ _tabs.reset([[NSMutableSet alloc] init]); |
+ _observers.reset([[TabModelObservers observers] retain]); |
+ |
+ _fastEnumerationHelper.reset([[WebStateListFastEnumerationHelper alloc] |
+ initWithWebStateList:&_webStateList |
+ proxyFactory:self]); |
_browserState = browserState; |
DCHECK(_browserState); |
@@ -268,7 +289,6 @@ void CleanCertificatePolicyCache( |
} |
_syncedWindowDelegate.reset(new TabModelSyncedWindowDelegate(self)); |
- _tabs.reset([[NSMutableArray alloc] init]); |
if (window) { |
DCHECK([_observers empty]); |
// Restore the session and reset the session metrics (as the event have |
@@ -317,7 +337,7 @@ void CleanCertificatePolicyCache( |
- (void)saveSessionImmediately:(BOOL)immediately { |
// Do nothing if there are tabs in the model but no selected tab. This is |
// a transitional state. |
- if ((!_currentTab && [_tabs count]) || !_browserState) |
+ if ((!_currentTab && _webStateList.count()) || !_browserState) |
return; |
[_sessionService saveWindow:self.windowForSavingSession |
forBrowserState:_browserState |
@@ -325,17 +345,19 @@ void CleanCertificatePolicyCache( |
} |
- (Tab*)tabAtIndex:(NSUInteger)index { |
- return [_tabs objectAtIndex:index]; |
+ web::WebState* webState = _webStateList.GetWebStateAt(index); |
+ return LegacyTabHelper::GetTabForWebState(webState); |
} |
- (NSUInteger)indexOfTab:(Tab*)tab { |
- return [_tabs indexOfObject:tab]; |
+ size_t index = _webStateList.GetIndexOfWebState(tab.webState); |
+ return index == WebStateList::kInvalidIndex ? NSNotFound : index; |
} |
- (Tab*)tabWithWindowName:(NSString*)windowName { |
if (!windowName) |
return nil; |
- for (Tab* tab in _tabs.get()) { |
+ for (Tab* tab in self) { |
if ([windowName isEqualToString:tab.windowName]) { |
return tab; |
} |
@@ -354,8 +376,8 @@ void CleanCertificatePolicyCache( |
if (startIndex == NSNotFound) |
return nil; |
NSString* parentID = tab.tabId; |
- for (NSUInteger i = startIndex + 1; i < [_tabs count]; ++i) { |
- Tab* current = [_tabs objectAtIndex:i]; |
+ for (NSUInteger i = startIndex + 1; i < _webStateList.count(); ++i) { |
+ Tab* current = [self tabAtIndex:i]; |
DCHECK([current navigationManager]); |
CRWSessionController* sessionController = |
[current navigationManager]->GetSessionController(); |
@@ -380,7 +402,7 @@ void CleanCertificatePolicyCache( |
DCHECK([tab navigationManager]); |
NSInteger parentNavIndex = [tab navigationManager]->GetCurrentItemIndex(); |
for (NSUInteger i = 0; i < stopIndex; ++i) { |
- Tab* tabToCheck = [_tabs objectAtIndex:i]; |
+ Tab* tabToCheck = [self tabAtIndex:i]; |
DCHECK([tabToCheck navigationManager]); |
CRWSessionController* sessionController = |
[tabToCheck navigationManager]->GetSessionController(); |
@@ -407,8 +429,8 @@ void CleanCertificatePolicyCache( |
// tabs whose opener's id and opener's navigation index match. The navigation |
// index is used in addition to the session id to detect navigations changes |
// within the same session. |
- for (NSUInteger i = startIndex + 1; i < [_tabs count]; ++i) { |
- Tab* tabToCheck = [_tabs objectAtIndex:i]; |
+ for (NSUInteger i = startIndex + 1; i < _webStateList.count(); ++i) { |
+ Tab* tabToCheck = [self tabAtIndex:i]; |
DCHECK([tabToCheck navigationManager]); |
CRWSessionController* sessionController = |
[tabToCheck navigationManager]->GetSessionController(); |
@@ -428,7 +450,7 @@ void CleanCertificatePolicyCache( |
NSString* openerId = [tab navigationManager]->GetSessionController().openerId; |
if (!openerId.length) // Short-circuit if opener is empty. |
return nil; |
- for (Tab* iteratedTab in _tabs.get()) { |
+ for (Tab* iteratedTab in self) { |
if ([iteratedTab.tabId isEqualToString:openerId]) |
return iteratedTab; |
} |
@@ -521,10 +543,11 @@ void CleanCertificatePolicyCache( |
- (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { |
DCHECK(tab); |
- DCHECK(index <= [_tabs count]); |
+ DCHECK(![_tabs containsObject:tab]); |
[tab fetchFavicon]; |
- [_tabs insertObject:tab atIndex:index]; |
+ [_tabs addObject:tab]; |
+ _webStateList.InsertWebState(index, tab.webState); |
TabParentingGlobalObserver::GetInstance()->OnTabParented(tab.webState); |
[_observers tabModel:self didInsertTab:tab atIndex:index inForeground:NO]; |
[_observers tabModelDidChangeTabCount:self]; |
@@ -535,34 +558,29 @@ void CleanCertificatePolicyCache( |
// state properly. If it does eventually become active, another save will |
// be triggered to properly capture the end result. |
[self saveSessionImmediately:NO]; |
+ |
++_newTabCount; |
} |
- (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex { |
rohitrao (ping after 24h)
2017/02/14 14:37:12
DCHECK([_tabs containsObject:tab]);
|
- NSUInteger fromIndex = [self indexOfTab:tab]; |
- DCHECK_NE(NSNotFound, static_cast<NSInteger>(fromIndex)); |
- DCHECK_LT(toIndex, self.count); |
- if (fromIndex == NSNotFound || toIndex >= self.count || |
- fromIndex == toIndex) { |
- return; |
- } |
- |
- base::scoped_nsobject<Tab> tabSaver([tab retain]); |
- [_tabs removeObject:tab]; |
- [_tabs insertObject:tab atIndex:toIndex]; |
- |
+ size_t fromIndex = _webStateList.GetIndexOfWebState(tab.webState); |
+ _webStateList.MoveWebStateAt(fromIndex, toIndex); |
[_observers tabModel:self didMoveTab:tab fromIndex:fromIndex toIndex:toIndex]; |
} |
- (void)replaceTab:(Tab*)oldTab withTab:(Tab*)newTab { |
NSUInteger index = [self indexOfTab:oldTab]; |
DCHECK_NE(NSNotFound, static_cast<NSInteger>(index)); |
+ DCHECK([_tabs containsObject:oldTab]); |
+ DCHECK(![_tabs containsObject:newTab]); |
base::scoped_nsobject<Tab> tabSaver([oldTab retain]); |
[newTab fetchFavicon]; |
- [_tabs replaceObjectAtIndex:index withObject:newTab]; |
+ [_tabs removeObject:oldTab]; |
+ [_tabs addObject:newTab]; |
[newTab setParentTabModel:self]; |
+ _webStateList.ReplaceWebStateAt(index, newTab.webState); |
TabParentingGlobalObserver::GetInstance()->OnTabParented(newTab.webState); |
[_observers tabModel:self didReplaceTab:oldTab withTab:newTab atIndex:index]; |
@@ -578,8 +596,8 @@ void CleanCertificatePolicyCache( |
} |
- (void)closeTabAtIndex:(NSUInteger)index { |
- DCHECK(index < [_tabs count]); |
- [self closeTab:[_tabs objectAtIndex:index]]; |
+ DCHECK(index < _webStateList.count()); |
+ [self closeTab:[self tabAtIndex:index]]; |
} |
- (void)closeTab:(Tab*)tab { |
@@ -599,7 +617,7 @@ void CleanCertificatePolicyCache( |
} |
- (void)haltAllTabs { |
- for (Tab* tab in _tabs.get()) { |
+ for (Tab* tab in self) { |
[tab terminateNetworkActivity]; |
} |
} |
@@ -636,7 +654,7 @@ void CleanCertificatePolicyCache( |
} |
- (void)resetAllWebViews { |
- for (Tab* tab in _tabs.get()) { |
+ for (Tab* tab in self) { |
[tab.webController reinitializeWebViewAndReload:(tab == _currentTab)]; |
} |
} |
@@ -645,7 +663,7 @@ void CleanCertificatePolicyCache( |
if (webUsageEnabled_ == webUsageEnabled) |
return; |
webUsageEnabled_ = webUsageEnabled; |
- for (Tab* tab in _tabs.get()) { |
+ for (Tab* tab in self) { |
tab.webUsageEnabled = webUsageEnabled; |
} |
} |
@@ -660,7 +678,7 @@ void CleanCertificatePolicyCache( |
if (!_browserState) |
return referencedFiles; |
// Check the currently open tabs for external files. |
- for (Tab* tab in _tabs.get()) { |
+ for (Tab* tab in self) { |
if (UrlIsExternalFileReference(tab.url)) { |
NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName()); |
[referencedFiles addObject:fileName]; |
@@ -697,7 +715,7 @@ void CleanCertificatePolicyCache( |
// Called when a tab is closing, but before its CRWWebController is destroyed. |
// Equivalent to DetachTabContentsAt() in Chrome's TabStripModel. |
- (void)didCloseTab:(Tab*)closedTab { |
- NSUInteger closedTabIndex = [_tabs indexOfObject:closedTab]; |
+ NSUInteger closedTabIndex = [self indexOfTab:closedTab]; |
DCHECK(closedTab); |
DCHECK(closedTabIndex != NSNotFound); |
// Let the sessions::TabRestoreService know about that new tab. |
@@ -716,8 +734,8 @@ void CleanCertificatePolicyCache( |
// This needs to be called before the tab is removed from the list. |
Tab* newSelection = |
[_orderController determineNewSelectedTabFromRemovedTab:closedTab]; |
+ |
base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]); |
- [_tabs removeObject:closedTab]; |
// If closing the current tab, clear |_currentTab| before sending any |
// notification. This avoids various parts of the code getting confused |
@@ -726,6 +744,10 @@ void CleanCertificatePolicyCache( |
if (closedTab == _currentTab) |
_currentTab.reset(nil); |
+ DCHECK([_tabs containsObject:closedTab]); |
+ [_tabs removeObject:closedTab]; |
+ |
+ _webStateList.RemoveWebStateAt(closedTabIndex); |
[_observers tabModel:self didRemoveTab:closedTab atIndex:closedTabIndex]; |
[_observers tabModelDidChangeTabCount:self]; |
@@ -773,21 +795,28 @@ void CleanCertificatePolicyCache( |
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state |
objects:(id*)objects |
count:(NSUInteger)count { |
- return [_tabs countByEnumeratingWithState:state objects:objects count:count]; |
+ return [_fastEnumerationHelper countByEnumeratingWithState:state |
+ objects:objects |
+ count:count]; |
} |
#pragma mark - TabUsageRecorderDelegate |
- (NSUInteger)liveTabsCount { |
NSUInteger count = 0; |
- NSArray* tabs = _tabs.get(); |
- for (Tab* tab in tabs) { |
+ for (Tab* tab in self) { |
if ([tab.webController isViewAlive]) |
count++; |
} |
return count; |
} |
+#pragma mark - WebStateProxyFactory |
+ |
+- (id)proxyForWebState:(web::WebState*)webState { |
rohitrao (ping after 24h)
2017/02/14 14:37:12
What is this for?
|
+ return LegacyTabHelper::GetTabForWebState(webState); |
+} |
+ |
#pragma mark - Private methods |
- (SessionWindowIOS*)windowForSavingSession { |
@@ -952,7 +981,7 @@ void CleanCertificatePolicyCache( |
if (!sessions.count) |
return NO; |
- size_t oldCount = [_tabs count]; |
+ size_t oldCount = _webStateList.count(); |
web::WebState::CreateParams params(_browserState); |
scoped_refptr<web::CertificatePolicyCache> policyCache = |
web::BrowserState::GetCertificatePolicyCache(_browserState); |
@@ -961,20 +990,20 @@ void CleanCertificatePolicyCache( |
std::unique_ptr<web::WebState> webState = |
web::WebState::Create(params, session); |
DCHECK_EQ(webState->GetBrowserState(), _browserState); |
- Tab* tab = |
- [self insertTabWithWebState:std::move(webState) atIndex:[_tabs count]]; |
+ Tab* tab = [self insertTabWithWebState:std::move(webState) |
+ atIndex:_webStateList.count()]; |
tab.webController.usePlaceholderOverlay = YES; |
// Restore the CertificatePolicyCache (note that webState is invalid after |
// passing it via move semantic to -insertTabWithWebState:atIndex:). |
UpdateCertificatePolicyCacheFromWebState(policyCache, tab.webState); |
} |
- DCHECK_GT([_tabs count], oldCount); |
+ DCHECK_GT(_webStateList.count(), oldCount); |
// Update the selected tab if there was a selected Tab in the saved session. |
if (window.selectedIndex != NSNotFound) { |
NSUInteger selectedIndex = window.selectedIndex + oldCount; |
- DCHECK_LT(selectedIndex, [_tabs count]); |
+ DCHECK_LT(selectedIndex, _webStateList.count()); |
DCHECK([self tabAtIndex:selectedIndex]); |
[self changeSelectedTabFrom:_currentTab |
to:[self tabAtIndex:selectedIndex] |
@@ -984,7 +1013,7 @@ void CleanCertificatePolicyCache( |
// If there was only one tab and it was the new tab page, clobber it. |
BOOL closedNTPTab = NO; |
if (oldCount == 1) { |
- Tab* tab = [_tabs objectAtIndex:0]; |
+ Tab* tab = [self tabAtIndex:0]; |
if (tab.url == GURL(kChromeUINewTabURL)) { |
[self closeTab:tab]; |
closedNTPTab = YES; |
@@ -992,10 +1021,12 @@ void CleanCertificatePolicyCache( |
} |
} |
if (_tabUsageRecorder) { |
- _tabUsageRecorder->InitialRestoredTabs( |
- _currentTab, |
- [_tabs |
- subarrayWithRange:NSMakeRange(oldCount, [_tabs count] - oldCount)]); |
+ NSMutableArray<Tab*>* restoredTabs = |
+ [NSMutableArray arrayWithCapacity:_webStateList.count() - oldCount]; |
+ for (size_t index = oldCount; index < _webStateList.count(); ++index) { |
+ [restoredTabs addObject:[self tabAtIndex:index]]; |
+ } |
+ _tabUsageRecorder->InitialRestoredTabs(_currentTab, restoredTabs); |
} |
return closedNTPTab; |
} |
@@ -1020,7 +1051,8 @@ void CleanCertificatePolicyCache( |
CleanCertificatePolicyCache( |
&_clearPoliciesTaskTracker, |
web::WebThread::GetTaskRunnerForThread(web::WebThread::IO), |
- web::BrowserState::GetCertificatePolicyCache(_browserState), self); |
+ web::BrowserState::GetCertificatePolicyCache(_browserState), |
+ &_webStateList); |
if (_tabUsageRecorder) |
_tabUsageRecorder->AppDidEnterBackground(); |