Chromium Code Reviews| 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 06280c8b56d794536d92afb2e17ca9b0100fe7ff..fc828491186a45e15d64cfded4dbbe2541cf734a 100644 |
| --- a/ios/chrome/browser/tabs/tab_model.mm |
| +++ b/ios/chrome/browser/tabs/tab_model.mm |
| @@ -10,6 +10,7 @@ |
| #include "base/bind.h" |
| #include "base/logging.h" |
| +#import "base/mac/foundation_util.h" |
| #import "base/mac/scoped_nsobject.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/metrics/user_metrics_action.h" |
| @@ -32,6 +33,7 @@ |
| #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_closing_web_state_observer.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_observers_bridge.h" |
| @@ -51,6 +53,7 @@ |
| #include "ios/web/public/certificate_policy_cache.h" |
| #include "ios/web/public/navigation_item.h" |
| #import "ios/web/public/navigation_manager.h" |
| +#import "ios/web/public/serializable_user_data_manager.h" |
| #include "ios/web/public/web_thread.h" |
| #import "ios/web/web_state/ui/crw_web_controller.h" |
| #import "ios/web/web_state/web_state_impl.h" |
| @@ -74,6 +77,14 @@ NSString* const kTabModelOpenInBackgroundKey = @"shouldOpenInBackground"; |
| namespace { |
| +// The key under which the opener Tab ID is stored in the WebState's |
| +// serializable user data. |
| +NSString* const kOpenerIDKey = @"OpenerID"; |
| + |
| +// The key under which the opener navigation index is stored in the WebState's |
| +// serializable user data. |
| +NSString* const kOpenerNavigationIndexKey = @"OpenerNavigationIndex"; |
| + |
| // Updates CRWSessionCertificatePolicyManager's certificate policy cache. |
| void UpdateCertificatePolicyCacheFromWebState( |
| const scoped_refptr<web::CertificatePolicyCache>& policy_cache, |
| @@ -122,16 +133,29 @@ void CleanCertificatePolicyCache( |
| // Internal helper function returning the opener for a given Tab by |
| // checking the associated Tab tabId (should be removed once the opener |
| // is passed to the insertTab:atIndex: and replaceTab:withTab: methods). |
| -Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| - if (!tab.openerID) |
| - return nullptr; |
| - |
| - for (Tab* currentTab in tabs) { |
| - if ([tab.openerID isEqualToString:currentTab.tabId]) |
| - return currentTab; |
| +WebStateOpener GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| + web::SerializableUserDataManager* user_data_manager = |
| + web::SerializableUserDataManager::FromWebState(tab.webState); |
| + |
| + NSString* opener_id = base::mac::ObjCCast<NSString>( |
| + user_data_manager->GetValueForSerializationKey(kOpenerIDKey)); |
| + if (!opener_id || ![opener_id length]) |
| + return WebStateOpener(nullptr); |
| + |
| + NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( |
| + user_data_manager->GetValueForSerializationKey( |
| + kOpenerNavigationIndexKey)); |
| + if (!boxed_opener_navigation_index) |
| + return WebStateOpener(nullptr); |
| + |
| + for (Tab* current_tab in tabs) { |
| + if ([opener_id isEqualToString:current_tab.tabId]) { |
| + return WebStateOpener(current_tab.webState, |
| + [boxed_opener_navigation_index intValue]); |
| + } |
| } |
| - return nullptr; |
| + return WebStateOpener(nullptr); |
| } |
| } // anonymous namespace |
| @@ -158,11 +182,6 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| base::scoped_nsobject<WebStateListFastEnumerationHelper> |
| _fastEnumerationHelper; |
| - // Used to keep the Tabs alive while the corresponding WebStates are stored |
| - // in the WebStateList (as Tabs currently own their WebState). Remove once |
| - // WebState owns the associated Tab. |
| - base::scoped_nsobject<NSMutableSet<Tab*>> _tabRetainer; |
| - |
| // WebStateListObservers reacting to modifications of the model (may send |
| // notification, translate and forward events, update metrics, ...). |
| std::vector<std::unique_ptr<WebStateListObserver>> _webStateListObservers; |
| @@ -189,9 +208,6 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| // Session window for the contents of the tab model. |
| @property(nonatomic, readonly) SessionWindowIOS* windowForSavingSession; |
| -// Returns YES if tab URL host indicates that tab is an NTP tab. |
| -- (BOOL)isNTPTab:(Tab*)tab; |
| - |
| // Helper method that posts a notification with the given name with |tab| |
| // in the userInfo dictionary under the kTabModelTabKey. |
| - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; |
| @@ -202,21 +218,6 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window |
| persistState:(BOOL)persistState; |
| -// Helper method to insert |tab| at the given |index| recording |parentTab| as |
| -// the opener. Broadcasts the proper notifications about the change. The |
| -// receiver should be set as the parentTabModel for |tab|; this method doesn't |
| -// check that. |
| -- (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab; |
| - |
| -// Helper method to insert |tab| at the given |index| recording |parentTab| as |
| -// the opener. Broadcasts the proper notifications about the change. The |
| -// receiver should be set as the parentTabModel for |tab|; this method doesn't |
| -// check that. |
| -- (void)insertTab:(Tab*)tab |
| - atIndex:(NSUInteger)index |
| - opener:(Tab*)parentTab |
| - transition:(ui::PageTransition)transition; |
| - |
| @end |
| @implementation TabModel |
| @@ -237,16 +238,17 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| // Clear weak pointer to WebStateListMetricsObserver before destroying it. |
| _webStateListMetricsObserver = nullptr; |
| - // Unregister all observers before closing all the tabs. |
| - for (const auto& webStateListObserver : _webStateListObservers) |
| - _webStateList->RemoveObserver(webStateListObserver.get()); |
| - _webStateListObservers.clear(); |
| - |
| // Make sure the tabs do clean after themselves. It is important for |
| // removeObserver: to be called first otherwise a lot of unecessary work will |
|
rohitrao (ping after 24h)
2017/04/03 17:49:35
This removeObserver comment might be stale now? W
sdefresne
2017/04/04 13:47:56
The comment says that all observer registered with
|
| // happen on -closeAllTabs. |
| [self closeAllTabs]; |
| + // Unregister all observers after closing all the tabs as some of them are |
|
rohitrao (ping after 24h)
2017/04/03 17:49:35
We used to do this before closing all tabs. Do yo
sdefresne
2017/04/04 13:47:56
As _observers is empty (i.e. there are no TabModel
|
| + // required to properly clean up the Tabs. |
| + for (const auto& webStateListObserver : _webStateListObservers) |
| + _webStateList->RemoveObserver(webStateListObserver.get()); |
| + _webStateListObservers.clear(); |
| + |
| _clearPoliciesTaskTracker.TryCancelAll(); |
| [super dealloc]; |
| @@ -294,13 +296,11 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| sessionService:(SessionServiceIOS*)service |
| browserState:(ios::ChromeBrowserState*)browserState { |
| if ((self = [super init])) { |
| - _tabRetainer.reset([[NSMutableSet alloc] init]); |
| _observers.reset([[TabModelObservers observers] retain]); |
| _webStateListDelegate = |
| base::MakeUnique<TabModelWebStateListDelegate>(self); |
| - _webStateList = base::MakeUnique<WebStateList>( |
| - _webStateListDelegate.get(), WebStateList::WebStateBorrowed); |
| + _webStateList = base::MakeUnique<WebStateList>(_webStateListDelegate.get()); |
| _fastEnumerationHelper.reset([[WebStateListFastEnumerationHelper alloc] |
| initWithWebStateList:_webStateList.get() |
| @@ -323,6 +323,12 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| DCHECK(service); |
| _sessionService.reset([service retain]); |
| + _webStateListObservers.push_back(base::MakeUnique< |
| + WebStateListObserverBridge>([ |
| + [TabModelClosingWebStateObserver alloc] |
| + initWithTabModel:self |
| + restoreService:IOSChromeTabRestoreServiceFactory::GetForBrowserState( |
| + _browserState)])); |
| _webStateListObservers.push_back( |
| base::MakeUnique<SnapshotCacheWebStateListObserver>( |
| [SnapshotCache sharedInstance])); |
| @@ -475,27 +481,42 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| } |
| - (Tab*)insertTabWithLoadParams: |
| - (const web::NavigationManager::WebLoadParams&)params |
| + (const web::NavigationManager::WebLoadParams&)loadParams |
| opener:(Tab*)parentTab |
| openedByDOM:(BOOL)openedByDOM |
| atIndex:(NSUInteger)index |
| inBackground:(BOOL)inBackground { |
| DCHECK(_browserState); |
| - base::scoped_nsobject<Tab> tab([[Tab alloc] initWithBrowserState:_browserState |
| - opener:parentTab |
| - openedByDOM:openedByDOM |
| - model:self]); |
| - [tab webController].webUsageEnabled = webUsageEnabled_; |
| - [self insertTab:tab |
| - atIndex:index |
| - opener:parentTab |
| - transition:params.transition_type]; |
| + web::WebState::CreateParams createParams(self.browserState); |
| + createParams.created_with_opener = openedByDOM; |
| + std::unique_ptr<web::WebState> webState = web::WebState::Create(createParams); |
| + |
| + web::WebState* webStatePtr = webState.get(); |
| + if (index == TabModelConstants::kTabPositionAutomatically) { |
| + _webStateList->AppendWebState(loadParams.transition_type, |
| + std::move(webState), |
| + WebStateOpener(parentTab.webState)); |
| + } else { |
| + DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); |
| + const int insertion_index = static_cast<int>(index); |
| + _webStateList->InsertWebState(insertion_index, std::move(webState)); |
| + if (parentTab.webState) { |
| + _webStateList->SetOpenerOfWebStateAt(insertion_index, |
| + WebStateOpener(parentTab.webState)); |
| + } |
| + } |
| + |
| + Tab* tab = LegacyTabHelper::GetTabForWebState(webStatePtr); |
| + DCHECK(tab); |
| + |
| + [tab webController].webUsageEnabled = webUsageEnabled_; |
| if (!inBackground && _tabUsageRecorder) |
| _tabUsageRecorder->TabCreatedForSelection(tab); |
| - [[tab webController] loadWithParams:params]; |
| + [[tab webController] loadWithParams:loadParams]; |
| + |
| // Force the page to start loading even if it's in the background. |
| if (webUsageEnabled_) |
| [[tab webController] triggerPendingLoad]; |
| @@ -514,120 +535,23 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| return tab; |
| } |
| -- (Tab*)insertTabWithWebState:(std::unique_ptr<web::WebState>)webState |
| - atIndex:(NSUInteger)index { |
| - DCHECK(_browserState); |
| - DCHECK_EQ(webState->GetBrowserState(), _browserState); |
| - base::scoped_nsobject<Tab> tab( |
| - [[Tab alloc] initWithWebState:std::move(webState) model:self]); |
| - [tab webController].webUsageEnabled = webUsageEnabled_; |
| - [self insertTab:tab atIndex:index]; |
| - return tab; |
| -} |
| - |
| -- (void)insertTab:(Tab*)tab |
| - atIndex:(NSUInteger)index |
| - opener:(Tab*)parentTab |
| - transition:(ui::PageTransition)transition { |
| - DCHECK(tab); |
| - DCHECK(![_tabRetainer containsObject:tab]); |
| - |
| - [_tabRetainer addObject:tab]; |
| - if (index == TabModelConstants::kTabPositionAutomatically) { |
| - _webStateList->AppendWebState( |
| - transition, tab.webState, |
| - WebStateOpener(parentTab.webState, tab.openerNavigationIndex)); |
| - } else { |
| - DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); |
| - const int insertion_index = static_cast<int>(index); |
| - _webStateList->InsertWebState(insertion_index, tab.webState); |
| - if (parentTab.webState) { |
| - _webStateList->SetOpenerOfWebStateAt( |
| - insertion_index, |
| - WebStateOpener(parentTab.webState, tab.openerNavigationIndex)); |
| - } |
| - } |
| - |
| - // Persist the session due to a new tab being inserted. If this is a |
| - // background tab (will not become active), saving now will capture the |
| - // state properly. If it does eventually become active, another save will |
| - // be triggered to properly capture the end result. |
| - [self saveSessionImmediately:NO]; |
| -} |
| - |
| -- (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab { |
| - DCHECK(tab); |
| - DCHECK(![_tabRetainer containsObject:tab]); |
| - DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); |
| - |
| - [self insertTab:tab |
| - atIndex:index |
| - opener:parentTab |
| - transition:ui::PAGE_TRANSITION_GENERATED]; |
| -} |
| - |
| -- (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { |
| - DCHECK(tab); |
| - DCHECK(![_tabRetainer containsObject:tab]); |
| - DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); |
| - |
| - [self insertTab:tab atIndex:index opener:GetOpenerForTab(self, tab)]; |
| -} |
| - |
| - (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex { |
| - DCHECK([_tabRetainer containsObject:tab]); |
| DCHECK_LE(toIndex, static_cast<NSUInteger>(INT_MAX)); |
| int fromIndex = _webStateList->GetIndexOfWebState(tab.webState); |
| _webStateList->MoveWebStateAt(fromIndex, static_cast<int>(toIndex)); |
| } |
| -- (void)replaceTab:(Tab*)oldTab withTab:(Tab*)newTab { |
| - DCHECK([_tabRetainer containsObject:oldTab]); |
| - DCHECK(![_tabRetainer containsObject:newTab]); |
| - |
| - int index = _webStateList->GetIndexOfWebState(oldTab.webState); |
| - DCHECK_NE(index, WebStateList::kInvalidIndex); |
| - DCHECK_GE(index, 0); |
| - |
| - base::scoped_nsobject<Tab> tabSaver([oldTab retain]); |
| - [_tabRetainer removeObject:oldTab]; |
| - [_tabRetainer addObject:newTab]; |
| - [newTab setParentTabModel:self]; |
| - |
| - // The WebState is owned by the associated Tab, so it is safe to ignore |
| - // the result and won't cause a memory leak. Once the ownership is moved |
| - // to WebStateList, this function will return a std::unique_ptr<> and the |
| - // object destroyed as expected, so it will fine to ignore the result then |
| - // too. See http://crbug.com/546222 for progress of changing the ownership |
| - // of the WebStates. |
| - ignore_result(_webStateList->ReplaceWebStateAt(index, newTab.webState)); |
| - |
| - Tab* parentTab = GetOpenerForTab(self, newTab); |
| - if (parentTab) { |
| - _webStateList->SetOpenerOfWebStateAt( |
| - index, |
| - WebStateOpener(parentTab.webState, newTab.openerNavigationIndex)); |
| - } |
| - |
| - [oldTab setParentTabModel:nil]; |
| - [oldTab close]; |
| -} |
| - |
| - (void)closeTabAtIndex:(NSUInteger)index { |
| - DCHECK(index < self.count); |
| - [self closeTab:[self tabAtIndex:index]]; |
| + DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); |
| + _webStateList->CloseWebStateAt(static_cast<int>(index)); |
| } |
| - (void)closeTab:(Tab*)tab { |
| - // Ensure the tab stays alive long enough for us to send out the |
| - // notice of its destruction to the delegate. |
| - [_observers tabModel:self willRemoveTab:tab]; |
| - [tab close]; // Note it is not safe to access the tab after 'close'. |
| + [self closeTabAtIndex:[self indexOfTab:tab]]; |
| } |
| - (void)closeAllTabs { |
| - for (NSInteger i = self.count - 1; i >= 0; --i) |
| - [self closeTabAtIndex:i]; |
| + _webStateList->CloseAllWebStates(); |
| [[NSNotificationCenter defaultCenter] |
| postNotificationName:kTabModelAllTabsDidCloseNotification |
| object:self]; |
| @@ -725,50 +649,6 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| _browserState = nullptr; |
| } |
| -// Called when a tab is closing, but before its CRWWebController is destroyed. |
| -// Equivalent to DetachTabContentsAt() in Chrome's TabStripModel. |
| -- (void)didCloseTab:(Tab*)closedTab { |
| - DCHECK(closedTab); |
| - DCHECK([_tabRetainer containsObject:closedTab]); |
| - int closedTabIndex = _webStateList->GetIndexOfWebState(closedTab.webState); |
| - DCHECK_NE(closedTabIndex, WebStateList::kInvalidIndex); |
| - DCHECK_GE(closedTabIndex, 0); |
| - |
| - // Let the sessions::TabRestoreService know about that new tab. |
| - sessions::TabRestoreService* restoreService = |
| - _browserState |
| - ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState) |
| - : nullptr; |
| - web::NavigationManager* navigationManager = [closedTab navigationManager]; |
| - DCHECK(navigationManager); |
| - int itemCount = navigationManager->GetItemCount(); |
| - if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) { |
| - restoreService->CreateHistoricalTab( |
| - sessions::IOSLiveTab::GetForWebState(closedTab.webState), |
| - closedTabIndex); |
| - } |
| - |
| - base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]); |
| - |
| - // If a non-current Tab is closed, save the session (it will be saved by |
| - // TabModelObserversBridge if the currentTab has been closed). |
| - BOOL needToSaveSession = (closedTab != self.currentTab); |
| - |
| - DCHECK([_tabRetainer containsObject:closedTab]); |
| - [_tabRetainer removeObject:closedTab]; |
| - |
| - // The WebState is owned by the associated Tab, so it is safe to ignore |
| - // the result and won't cause a memory leak. Once the ownership is moved |
| - // to WebStateList, this function will return a std::unique_ptr<> and the |
| - // object destroyed as expected, so it will fine to ignore the result then |
| - // too. See http://crbug.com/546222 for progress of changing the ownership |
| - // of the WebStates. |
| - ignore_result(_webStateList->DetachWebStateAt(closedTabIndex)); |
| - |
| - if (needToSaveSession) |
| - [self saveSessionImmediately:NO]; |
| -} |
| - |
| - (void)navigationCommittedInTab:(Tab*)tab |
| previousItem:(web::NavigationItem*)previousItem { |
| if (self.offTheRecord) |
| @@ -828,9 +708,24 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| NSMutableArray<CRWSessionStorage*>* sessions = |
| [NSMutableArray arrayWithCapacity:[self count]]; |
| - for (Tab* tab in self) { |
| - DCHECK(tab.webState); |
| - [sessions addObject:tab.webState->BuildSessionStorage()]; |
| + for (int index = 0; index < _webStateList->count(); ++index) { |
| + web::WebState* webState = _webStateList->GetWebStateAt(index); |
| + web::SerializableUserDataManager* userDataManager = |
| + web::SerializableUserDataManager::FromWebState(webState); |
| + |
| + WebStateOpener opener = _webStateList->GetOpenerOfWebStateAt(index); |
| + if (opener.opener) { |
| + Tab* parentTab = LegacyTabHelper::GetTabForWebState(opener.opener); |
| + userDataManager->AddSerializableData(parentTab.tabId, kOpenerIDKey); |
| + userDataManager->AddSerializableData(@(opener.navigation_index), |
| + kOpenerNavigationIndexKey); |
| + } else { |
| + userDataManager->AddSerializableData([NSNull null], kOpenerIDKey); |
| + userDataManager->AddSerializableData([NSNull null], |
| + kOpenerNavigationIndexKey); |
| + } |
| + |
| + [sessions addObject:webState->BuildSessionStorage()]; |
| } |
| return [[[SessionWindowIOS alloc] |
| @@ -838,11 +733,6 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| selectedIndex:[self indexOfTab:self.currentTab]] autorelease]; |
| } |
| -- (BOOL)isNTPTab:(Tab*)tab { |
| - std::string host = tab.url.host(); |
| - return host == kChromeUINewTabHost || host == kChromeUIBookmarksHost; |
| -} |
| - |
| - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab { |
| // A scoped_nsobject is used rather than an NSDictionary with static |
| // initializer dictionaryWithObject, because that approach adds the dictionary |
| @@ -880,16 +770,19 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| for (CRWSessionStorage* session in sessions) { |
| std::unique_ptr<web::WebState> webState = |
| web::WebState::CreateWithStorageSession(params, session); |
| - base::scoped_nsobject<Tab> tab( |
| - [[Tab alloc] initWithWebState:std::move(webState) model:self]); |
| - [tab webController].webUsageEnabled = webUsageEnabled_; |
| - [tab webController].usePlaceholderOverlay = YES; |
| + _webStateList->InsertWebState(_webStateList->count(), std::move(webState)); |
| + } |
| + |
| + for (int index = oldCount; index < _webStateList->count(); ++index) { |
| + web::WebState* webState = _webStateList->GetWebStateAt(index); |
| + Tab* tab = LegacyTabHelper::GetTabForWebState(webState); |
| + tab.webController.webUsageEnabled = webUsageEnabled_; |
| + tab.webController.usePlaceholderOverlay = YES; |
| // Restore the CertificatePolicyCache (note that webState is invalid after |
| // passing it via move semantic to -initWithWebState:model:). |
| UpdateCertificatePolicyCacheFromWebState(policyCache, [tab webState]); |
| - [self insertTab:tab atIndex:self.count opener:nil]; |
| - [restoredTabs addObject:tab.get()]; |
| + [restoredTabs addObject:tab]; |
| } |
| DCHECK_EQ(sessions.count, [restoredTabs count]); |
| @@ -901,12 +794,9 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| DCHECK_GE(index, oldCount); |
| NSUInteger tabIndex = static_cast<NSUInteger>(index - oldCount); |
| Tab* tab = [restoredTabs objectAtIndex:tabIndex]; |
| - Tab* opener = GetOpenerForTab(restoredTabs.get(), tab); |
| - if (opener) { |
| - DCHECK(opener.webState); |
| - _webStateList->SetOpenerOfWebStateAt( |
| - index, WebStateOpener(opener.webState, tab.openerNavigationIndex)); |
| - } |
| + WebStateOpener opener = GetOpenerForTab(restoredTabs.get(), tab); |
| + if (opener.opener) |
| + _webStateList->SetOpenerOfWebStateAt(index, opener); |
| } |
| // Update the selected tab if there was a selected Tab in the saved session. |
| @@ -930,15 +820,8 @@ Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { |
| oldCount = 0; |
| } |
| } |
| - if (_tabUsageRecorder) { |
| - NSMutableArray<Tab*>* restoredTabs = |
| - [NSMutableArray arrayWithCapacity:_webStateList->count() - oldCount]; |
| - for (int index = oldCount; index < _webStateList->count(); ++index) { |
| - web::WebState* webState = _webStateList->GetWebStateAt(index); |
| - [restoredTabs addObject:LegacyTabHelper::GetTabForWebState(webState)]; |
| - } |
| + if (_tabUsageRecorder) |
| _tabUsageRecorder->InitialRestoredTabs(self.currentTab, restoredTabs); |
| - } |
| return closedNTPTab; |
| } |