Chromium Code Reviews| 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 <cstdint> | 7 #include <cstdint> | 
| 8 #include <utility> | 8 #include <utility> | 
| 9 #include <vector> | 9 #include <vector> | 
| 10 | 10 | 
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 #import "ios/chrome/browser/tabs/tab_model_observers_bridge.h" | 40 #import "ios/chrome/browser/tabs/tab_model_observers_bridge.h" | 
| 41 #import "ios/chrome/browser/tabs/tab_model_selected_tab_observer.h" | 41 #import "ios/chrome/browser/tabs/tab_model_selected_tab_observer.h" | 
| 42 #import "ios/chrome/browser/tabs/tab_model_synced_window_delegate.h" | 42 #import "ios/chrome/browser/tabs/tab_model_synced_window_delegate.h" | 
| 43 #import "ios/chrome/browser/tabs/tab_model_web_state_list_delegate.h" | 43 #import "ios/chrome/browser/tabs/tab_model_web_state_list_delegate.h" | 
| 44 #import "ios/chrome/browser/tabs/tab_parenting_observer.h" | 44 #import "ios/chrome/browser/tabs/tab_parenting_observer.h" | 
| 45 #import "ios/chrome/browser/xcallback_parameters.h" | 45 #import "ios/chrome/browser/xcallback_parameters.h" | 
| 46 #import "ios/shared/chrome/browser/tabs/web_state_list.h" | 46 #import "ios/shared/chrome/browser/tabs/web_state_list.h" | 
| 47 #import "ios/shared/chrome/browser/tabs/web_state_list_fast_enumeration_helper.h " | 47 #import "ios/shared/chrome/browser/tabs/web_state_list_fast_enumeration_helper.h " | 
| 48 #import "ios/shared/chrome/browser/tabs/web_state_list_metrics_observer.h" | 48 #import "ios/shared/chrome/browser/tabs/web_state_list_metrics_observer.h" | 
| 49 #import "ios/shared/chrome/browser/tabs/web_state_list_observer.h" | 49 #import "ios/shared/chrome/browser/tabs/web_state_list_observer.h" | 
| 50 #import "ios/shared/chrome/browser/tabs/web_state_list_serialisation.h" | |
| 50 #import "ios/shared/chrome/browser/tabs/web_state_opener.h" | 51 #import "ios/shared/chrome/browser/tabs/web_state_opener.h" | 
| 51 #import "ios/web/navigation/crw_session_certificate_policy_manager.h" | 52 #import "ios/web/navigation/crw_session_certificate_policy_manager.h" | 
| 52 #import "ios/web/navigation/crw_session_controller.h" | 53 #import "ios/web/navigation/crw_session_controller.h" | 
| 53 #include "ios/web/public/browser_state.h" | 54 #include "ios/web/public/browser_state.h" | 
| 54 #include "ios/web/public/certificate_policy_cache.h" | 55 #include "ios/web/public/certificate_policy_cache.h" | 
| 55 #include "ios/web/public/navigation_item.h" | 56 #include "ios/web/public/navigation_item.h" | 
| 56 #import "ios/web/public/navigation_manager.h" | 57 #import "ios/web/public/navigation_manager.h" | 
| 57 #import "ios/web/public/serializable_user_data_manager.h" | 58 #import "ios/web/public/serializable_user_data_manager.h" | 
| 58 #include "ios/web/public/web_thread.h" | 59 #include "ios/web/public/web_thread.h" | 
| 59 #import "ios/web/web_state/ui/crw_web_controller.h" | 60 #import "ios/web/web_state/ui/crw_web_controller.h" | 
| (...skipping 11 matching lines...) Expand all Loading... | |
| 71 NSString* const kTabModelTabDeselectedNotification = | 72 NSString* const kTabModelTabDeselectedNotification = | 
| 72 @"kTabModelTabDeselectedNotification"; | 73 @"kTabModelTabDeselectedNotification"; | 
| 73 NSString* const kTabModelNewTabWillOpenNotification = | 74 NSString* const kTabModelNewTabWillOpenNotification = | 
| 74 @"kTabModelNewTabWillOpenNotification"; | 75 @"kTabModelNewTabWillOpenNotification"; | 
| 75 NSString* const kTabModelTabKey = @"tab"; | 76 NSString* const kTabModelTabKey = @"tab"; | 
| 76 NSString* const kTabModelPageLoadSuccess = @"pageLoadSuccess"; | 77 NSString* const kTabModelPageLoadSuccess = @"pageLoadSuccess"; | 
| 77 NSString* const kTabModelOpenInBackgroundKey = @"shouldOpenInBackground"; | 78 NSString* const kTabModelOpenInBackgroundKey = @"shouldOpenInBackground"; | 
| 78 | 79 | 
| 79 namespace { | 80 namespace { | 
| 80 | 81 | 
| 81 // The key under which the opener Tab ID is stored in the WebState's | |
| 82 // serializable user data. | |
| 83 NSString* const kOpenerIDKey = @"OpenerID"; | |
| 84 | |
| 85 // The key under which the opener navigation index is stored in the WebState's | |
| 86 // serializable user data. | |
| 87 NSString* const kOpenerNavigationIndexKey = @"OpenerNavigationIndex"; | |
| 88 | |
| 89 // Updates CRWSessionCertificatePolicyManager's certificate policy cache. | 82 // Updates CRWSessionCertificatePolicyManager's certificate policy cache. | 
| 90 void UpdateCertificatePolicyCacheFromWebState( | 83 void UpdateCertificatePolicyCacheFromWebState( | 
| 91 const scoped_refptr<web::CertificatePolicyCache>& policy_cache, | 84 const scoped_refptr<web::CertificatePolicyCache>& policy_cache, | 
| 92 web::WebState* web_state) { | 85 web::WebState* web_state) { | 
| 93 DCHECK(web_state); | 86 DCHECK(web_state); | 
| 94 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 87 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 
| 95 // TODO(crbug.com/454984): Remove CRWSessionController usage once certificate | 88 // TODO(crbug.com/454984): Remove CRWSessionController usage once certificate | 
| 96 // policy manager is moved to NavigationManager. | 89 // policy manager is moved to NavigationManager. | 
| 97 CRWSessionController* controller = static_cast<web::WebStateImpl*>(web_state) | 90 CRWSessionController* controller = static_cast<web::WebStateImpl*>(web_state) | 
| 98 ->GetNavigationManagerImpl() | 91 ->GetNavigationManagerImpl() | 
| (...skipping 25 matching lines...) Expand all Loading... | |
| 124 DCHECK(web_state_list); | 117 DCHECK(web_state_list); | 
| 125 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 118 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 
| 126 task_tracker->PostTaskAndReply( | 119 task_tracker->PostTaskAndReply( | 
| 127 task_runner.get(), FROM_HERE, | 120 task_runner.get(), FROM_HERE, | 
| 128 base::Bind(&web::CertificatePolicyCache::ClearCertificatePolicies, | 121 base::Bind(&web::CertificatePolicyCache::ClearCertificatePolicies, | 
| 129 policy_cache), | 122 policy_cache), | 
| 130 base::Bind(&RestoreCertificatePolicyCacheFromModel, policy_cache, | 123 base::Bind(&RestoreCertificatePolicyCacheFromModel, policy_cache, | 
| 131 base::Unretained(web_state_list))); | 124 base::Unretained(web_state_list))); | 
| 132 } | 125 } | 
| 133 | 126 | 
| 134 // Internal helper function returning the opener for a given Tab by | |
| 135 // checking the associated Tab tabId (should be removed once the opener | |
| 136 // is passed to the insertTab:atIndex: and replaceTab:withTab: methods). | |
| 137 WebStateOpener GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) { | |
| 138 web::SerializableUserDataManager* user_data_manager = | |
| 139 web::SerializableUserDataManager::FromWebState(tab.webState); | |
| 140 | |
| 141 NSString* opener_id = base::mac::ObjCCast<NSString>( | |
| 142 user_data_manager->GetValueForSerializationKey(kOpenerIDKey)); | |
| 143 if (!opener_id || ![opener_id length]) | |
| 144 return WebStateOpener(nullptr); | |
| 145 | |
| 146 NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( | |
| 147 user_data_manager->GetValueForSerializationKey( | |
| 148 kOpenerNavigationIndexKey)); | |
| 149 if (!boxed_opener_navigation_index) | |
| 150 return WebStateOpener(nullptr); | |
| 151 | |
| 152 for (Tab* current_tab in tabs) { | |
| 153 if ([opener_id isEqualToString:current_tab.tabId]) { | |
| 154 return WebStateOpener(current_tab.webState, | |
| 155 [boxed_opener_navigation_index intValue]); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 return WebStateOpener(nullptr); | |
| 160 } | |
| 161 | |
| 162 } // anonymous namespace | 127 } // anonymous namespace | 
| 163 | 128 | 
| 164 @interface TabModelWebStateProxyFactory : NSObject<WebStateProxyFactory> | 129 @interface TabModelWebStateProxyFactory : NSObject<WebStateProxyFactory> | 
| 165 @end | 130 @end | 
| 166 | 131 | 
| 167 @implementation TabModelWebStateProxyFactory | 132 @implementation TabModelWebStateProxyFactory | 
| 168 | 133 | 
| 169 - (id)proxyForWebState:(web::WebState*)webState { | 134 - (id)proxyForWebState:(web::WebState*)webState { | 
| 170 return LegacyTabHelper::GetTabForWebState(webState); | 135 return LegacyTabHelper::GetTabForWebState(webState); | 
| 171 } | 136 } | 
| (...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 698 | 663 | 
| 699 - (SessionWindowIOS*)windowForSavingSession { | 664 - (SessionWindowIOS*)windowForSavingSession { | 
| 700 // Background tabs will already have their state preserved, but not the | 665 // Background tabs will already have their state preserved, but not the | 
| 701 // fg tab. Do it now. | 666 // fg tab. Do it now. | 
| 702 [self.currentTab recordStateInHistory]; | 667 [self.currentTab recordStateInHistory]; | 
| 703 | 668 | 
| 704 // Build the array of sessions. Copy the session objects as the saving will | 669 // Build the array of sessions. Copy the session objects as the saving will | 
| 705 // be done on a separate thread. | 670 // be done on a separate thread. | 
| 706 // TODO(crbug.com/661986): This could get expensive especially since this | 671 // TODO(crbug.com/661986): This could get expensive especially since this | 
| 707 // window may never be saved (if another call comes in before the delay). | 672 // window may never be saved (if another call comes in before the delay). | 
| 708 NSMutableArray<CRWSessionStorage*>* sessions = | |
| 709 [NSMutableArray arrayWithCapacity:[self count]]; | |
| 710 | |
| 711 for (int index = 0; index < _webStateList->count(); ++index) { | |
| 712 web::WebState* webState = _webStateList->GetWebStateAt(index); | |
| 713 web::SerializableUserDataManager* userDataManager = | |
| 714 web::SerializableUserDataManager::FromWebState(webState); | |
| 715 | |
| 716 WebStateOpener opener = _webStateList->GetOpenerOfWebStateAt(index); | |
| 717 if (opener.opener) { | |
| 718 Tab* parentTab = LegacyTabHelper::GetTabForWebState(opener.opener); | |
| 719 userDataManager->AddSerializableData(parentTab.tabId, kOpenerIDKey); | |
| 720 userDataManager->AddSerializableData(@(opener.navigation_index), | |
| 721 kOpenerNavigationIndexKey); | |
| 722 } else { | |
| 723 userDataManager->AddSerializableData([NSNull null], kOpenerIDKey); | |
| 724 userDataManager->AddSerializableData([NSNull null], | |
| 725 kOpenerNavigationIndexKey); | |
| 726 } | |
| 727 | |
| 728 [sessions addObject:webState->BuildSessionStorage()]; | |
| 729 } | |
| 730 | |
| 731 return [[[SessionWindowIOS alloc] | 673 return [[[SessionWindowIOS alloc] | 
| 732 initWithSessions:sessions | 674 initWithSessions:SerializeWebStateList(_webStateList.get()) | 
| 733 selectedIndex:[self indexOfTab:self.currentTab]] autorelease]; | 675 selectedIndex:[self indexOfTab:self.currentTab]] autorelease]; | 
| 734 } | 676 } | 
| 735 | 677 | 
| 736 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab { | 678 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab { | 
| 737 // A scoped_nsobject is used rather than an NSDictionary with static | 679 // A scoped_nsobject is used rather than an NSDictionary with static | 
| 738 // initializer dictionaryWithObject, because that approach adds the dictionary | 680 // initializer dictionaryWithObject, because that approach adds the dictionary | 
| 739 // to the autorelease pool, which in turn holds Tab alive longer than | 681 // to the autorelease pool, which in turn holds Tab alive longer than | 
| 740 // necessary. | 682 // necessary. | 
| 741 base::scoped_nsobject<NSDictionary> userInfo( | 683 base::scoped_nsobject<NSDictionary> userInfo( | 
| 742 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]); | 684 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]); | 
| 743 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName | 685 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName | 
| 744 object:self | 686 object:self | 
| 745 userInfo:userInfo]; | 687 userInfo:userInfo]; | 
| 746 } | 688 } | 
| 747 | 689 | 
| 748 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window | 690 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window | 
| 749 persistState:(BOOL)persistState { | 691 persistState:(BOOL)persistState { | 
| 750 DCHECK(_browserState); | 692 DCHECK(_browserState); | 
| 751 DCHECK(window); | 693 DCHECK(window); | 
| 752 | 694 | 
| 753 NSArray* sessions = window.sessions; | 695 NSArray* sessions = window.sessions; | 
| 754 if (!sessions.count) | 696 if (!sessions.count) | 
| 755 return NO; | 697 return NO; | 
| 756 | 698 | 
| 757 int oldCount = _webStateList->count(); | 699 int oldCount = _webStateList->count(); | 
| 758 DCHECK_GE(oldCount, 0); | 700 DCHECK_GE(oldCount, 0); | 
| 759 | 701 | 
| 760 web::WebState::CreateParams params(_browserState); | 702 web::WebState::CreateParams params(_browserState); | 
| 703 int restoredCount = | |
| 704 DeserializeWebStateListFrom(_webStateList.get(), params, sessions); | |
| 705 | |
| 706 DCHECK_GE(restoredCount, 0); | |
| 707 DCHECK_EQ(sessions.count, static_cast<NSUInteger>(restoredCount)); | |
| 708 DCHECK_GT(_webStateList->count(), oldCount); | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
restoredCount must be >= 0, so can be 0.
Presumabl
 
sdefresne
2017/03/27 16:14:44
The method early return (see line 696) if sessions
 
marq (ping after 24h)
2017/03/28 15:47:24
Thanks -- a comment saying that because of line 69
 
 | |
| 709 | |
| 761 scoped_refptr<web::CertificatePolicyCache> policyCache = | 710 scoped_refptr<web::CertificatePolicyCache> policyCache = | 
| 762 web::BrowserState::GetCertificatePolicyCache(_browserState); | 711 web::BrowserState::GetCertificatePolicyCache(_browserState); | 
| 763 | 712 | 
| 764 base::scoped_nsobject<NSMutableArray<Tab*>> restoredTabs( | 713 base::scoped_nsobject<NSMutableArray<Tab*>> restoredTabs( | 
| 765 [[NSMutableArray alloc] initWithCapacity:sessions.count]); | 714 [[NSMutableArray alloc] initWithCapacity:restoredCount]); | 
| 766 | |
| 767 // Recreate all the restored Tabs and add them to the WebStateList without | |
| 768 // any opener-opened relationship (as the n-th restored Tab opener may be | |
| 769 // at an index larger than n). Then in a second pass fix the openers. | |
| 770 for (CRWSessionStorage* session in sessions) { | |
| 771 std::unique_ptr<web::WebState> webState = | |
| 772 web::WebState::Create(params, session); | |
| 773 _webStateList->InsertWebState(_webStateList->count(), std::move(webState)); | |
| 774 } | |
| 775 | 715 | 
| 776 for (int index = oldCount; index < _webStateList->count(); ++index) { | 716 for (int index = oldCount; index < _webStateList->count(); ++index) { | 
| 777 web::WebState* webState = _webStateList->GetWebStateAt(index); | 717 web::WebState* webState = _webStateList->GetWebStateAt(index); | 
| 778 Tab* tab = LegacyTabHelper::GetTabForWebState(webState); | 718 Tab* tab = LegacyTabHelper::GetTabForWebState(webState); | 
| 719 | |
| 779 tab.webController.webUsageEnabled = webUsageEnabled_; | 720 tab.webController.webUsageEnabled = webUsageEnabled_; | 
| 780 tab.webController.usePlaceholderOverlay = YES; | 721 tab.webController.usePlaceholderOverlay = YES; | 
| 781 | 722 | 
| 782 // Restore the CertificatePolicyCache (note that webState is invalid after | 723 // Restore the CertificatePolicyCache (note that webState is invalid after | 
| 783 // passing it via move semantic to -initWithWebState:model:). | 724 // passing it via move semantic to -initWithWebState:model:). | 
| 784 UpdateCertificatePolicyCacheFromWebState(policyCache, [tab webState]); | 725 UpdateCertificatePolicyCacheFromWebState(policyCache, [tab webState]); | 
| 785 [restoredTabs addObject:tab]; | 726 [restoredTabs addObject:tab]; | 
| 786 } | 727 } | 
| 787 | 728 | 
| 788 DCHECK_EQ(sessions.count, [restoredTabs count]); | 729 DCHECK_EQ(sessions.count, [restoredTabs count]); | 
| 789 DCHECK_GT(_webStateList->count(), oldCount); | 730 DCHECK_GT(_webStateList->count(), oldCount); | 
| 790 | 731 | 
| 791 // Fix openers now that all Tabs have been restored. Only look for an opener | |
| 792 // Tab in the newly restored Tabs and not in the already open Tabs. | |
| 793 for (int index = oldCount; index < _webStateList->count(); ++index) { | |
| 794 DCHECK_GE(index, oldCount); | |
| 795 NSUInteger tabIndex = static_cast<NSUInteger>(index - oldCount); | |
| 796 Tab* tab = [restoredTabs objectAtIndex:tabIndex]; | |
| 797 WebStateOpener opener = GetOpenerForTab(restoredTabs.get(), tab); | |
| 798 if (opener.opener) | |
| 799 _webStateList->SetOpenerOfWebStateAt(index, opener); | |
| 800 } | |
| 801 | |
| 802 // Update the selected tab if there was a selected Tab in the saved session. | 732 // Update the selected tab if there was a selected Tab in the saved session. | 
| 803 if (window.selectedIndex != NSNotFound) { | 733 if (window.selectedIndex != NSNotFound) { | 
| 804 NSUInteger selectedIndex = window.selectedIndex + oldCount; | 734 NSUInteger selectedIndex = window.selectedIndex + oldCount; | 
| 805 DCHECK_LT(selectedIndex, self.count); | 735 DCHECK_LT(selectedIndex, self.count); | 
| 806 DCHECK([self tabAtIndex:selectedIndex]); | 736 DCHECK([self tabAtIndex:selectedIndex]); | 
| 807 | 737 | 
| 808 if (persistState && self.currentTab) | 738 if (persistState && self.currentTab) | 
| 809 [self.currentTab recordStateInHistory]; | 739 [self.currentTab recordStateInHistory]; | 
| 810 _webStateList->ActivateWebStateAt(static_cast<int>(selectedIndex)); | 740 _webStateList->ActivateWebStateAt(static_cast<int>(selectedIndex)); | 
| 811 } | 741 } | 
| 812 | 742 | 
| 813 // If there was only one tab and it was the new tab page, clobber it. | 743 // If there was only one tab and it was the new tab page, clobber it. | 
| 814 BOOL closedNTPTab = NO; | 744 BOOL closedNTPTab = NO; | 
| 815 if (oldCount == 1) { | 745 if (oldCount == 1) { | 
| 816 Tab* tab = [self tabAtIndex:0]; | 746 Tab* tab = [self tabAtIndex:0]; | 
| 817 if (tab.url == GURL(kChromeUINewTabURL)) { | 747 if (tab.url == GURL(kChromeUINewTabURL)) { | 
| 818 [self closeTab:tab]; | 748 [self closeTab:tab]; | 
| 819 closedNTPTab = YES; | 749 closedNTPTab = YES; | 
| 820 oldCount = 0; | 750 oldCount = 0; | 
| 821 } | 751 } | 
| 822 } | 752 } | 
| 823 if (_tabUsageRecorder) | 753 if (_tabUsageRecorder) | 
| 824 _tabUsageRecorder->InitialRestoredTabs(self.currentTab, restoredTabs); | 754 _tabUsageRecorder->InitialRestoredTabs(self.currentTab, restoredTabs.get()); | 
| 825 return closedNTPTab; | 755 return closedNTPTab; | 
| 826 } | 756 } | 
| 827 | 757 | 
| 828 #pragma mark - Notification Handlers | 758 #pragma mark - Notification Handlers | 
| 829 | 759 | 
| 830 // Called when UIApplicationWillResignActiveNotification is received. | 760 // Called when UIApplicationWillResignActiveNotification is received. | 
| 831 - (void)willResignActive:(NSNotification*)notify { | 761 - (void)willResignActive:(NSNotification*)notify { | 
| 832 if (webUsageEnabled_ && self.currentTab) { | 762 if (webUsageEnabled_ && self.currentTab) { | 
| 833 [[SnapshotCache sharedInstance] | 763 [[SnapshotCache sharedInstance] | 
| 834 willBeSavedGreyWhenBackgrounding:self.currentTab.tabId]; | 764 willBeSavedGreyWhenBackgrounding:self.currentTab.tabId]; | 
| (...skipping 28 matching lines...) Expand all Loading... | |
| 863 } | 793 } | 
| 864 | 794 | 
| 865 // Called when UIApplicationWillEnterForegroundNotification is received. | 795 // Called when UIApplicationWillEnterForegroundNotification is received. | 
| 866 - (void)applicationWillEnterForeground:(NSNotification*)notify { | 796 - (void)applicationWillEnterForeground:(NSNotification*)notify { | 
| 867 if (_tabUsageRecorder) { | 797 if (_tabUsageRecorder) { | 
| 868 _tabUsageRecorder->AppWillEnterForeground(); | 798 _tabUsageRecorder->AppWillEnterForeground(); | 
| 869 } | 799 } | 
| 870 } | 800 } | 
| 871 | 801 | 
| 872 @end | 802 @end | 
| OLD | NEW |