Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1824)

Side by Side Diff: ios/chrome/browser/tabs/tab_model.mm

Issue 2697193004: Add opener-opened relationship between WebState in WebStateList. (Closed)
Patch Set: Fix copy-n-paste error. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 DCHECK(web_state_list); 110 DCHECK(web_state_list);
111 DCHECK_CURRENTLY_ON(web::WebThread::UI); 111 DCHECK_CURRENTLY_ON(web::WebThread::UI);
112 task_tracker->PostTaskAndReply( 112 task_tracker->PostTaskAndReply(
113 task_runner.get(), FROM_HERE, 113 task_runner.get(), FROM_HERE,
114 base::Bind(&web::CertificatePolicyCache::ClearCertificatePolicies, 114 base::Bind(&web::CertificatePolicyCache::ClearCertificatePolicies,
115 policy_cache), 115 policy_cache),
116 base::Bind(&RestoreCertificatePolicyCacheFromModel, policy_cache, 116 base::Bind(&RestoreCertificatePolicyCacheFromModel, policy_cache,
117 base::Unretained(web_state_list))); 117 base::Unretained(web_state_list)));
118 } 118 }
119 119
120 // Internal helper function returning the opener for a given Tab by
121 // checking the associated Tab tabId (should be removed once the opener
122 // is passed to the insertTab:atIndex: and replaceTab:withTab: methods).
123 Tab* GetOpenerForTab(id<NSFastEnumeration> tabs, Tab* tab) {
124 NSString* opener_id =
125 [tab navigationManager]->GetSessionController().openerId;
126 if (!opener_id)
127 return nullptr;
128
129 for (Tab* currentTab in tabs) {
130 if ([opener_id isEqualToString:currentTab.tabId])
131 return currentTab;
132 }
133
134 return nullptr;
135 }
136
120 } // anonymous namespace 137 } // anonymous namespace
121 138
122 @interface TabModelWebStateProxyFactory : NSObject<WebStateProxyFactory> 139 @interface TabModelWebStateProxyFactory : NSObject<WebStateProxyFactory>
123 @end 140 @end
124 141
125 @implementation TabModelWebStateProxyFactory 142 @implementation TabModelWebStateProxyFactory
126 143
127 - (id)proxyForWebState:(web::WebState*)webState { 144 - (id)proxyForWebState:(web::WebState*)webState {
128 return LegacyTabHelper::GetTabForWebState(webState); 145 return LegacyTabHelper::GetTabForWebState(webState);
129 } 146 }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 // Helper method that posts a notification with the given name with |tab| 227 // Helper method that posts a notification with the given name with |tab|
211 // in the userInfo dictionary under the kTabModelTabKey. 228 // in the userInfo dictionary under the kTabModelTabKey.
212 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; 229 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab;
213 230
214 // Helper method to restore a saved session and control if the state should 231 // Helper method to restore a saved session and control if the state should
215 // be persisted or not. Used to implement the public -restoreSessionWindow: 232 // be persisted or not. Used to implement the public -restoreSessionWindow:
216 // method and restoring session in the initialiser. 233 // method and restoring session in the initialiser.
217 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window 234 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window
218 persistState:(BOOL)persistState; 235 persistState:(BOOL)persistState;
219 236
237 // Helper method to insert |tab| at the given |index| recording |parentTab| as
238 // the opener. Broadcasts the proper notifications about the change. The
239 // receiver should be set as the parentTabModel for |tab|; this method doesn't
240 // check that.
241 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab;
242
220 @end 243 @end
221 244
222 @implementation TabModel 245 @implementation TabModel
223 246
224 @synthesize browserState = _browserState; 247 @synthesize browserState = _browserState;
225 @synthesize sessionID = _sessionID; 248 @synthesize sessionID = _sessionID;
226 @synthesize webUsageEnabled = webUsageEnabled_; 249 @synthesize webUsageEnabled = webUsageEnabled_;
227 250
228 #pragma mark - Overriden 251 #pragma mark - Overriden
229 252
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 return nil; 421 return nil;
399 for (Tab* tab in self) { 422 for (Tab* tab in self) {
400 if ([windowName isEqualToString:tab.windowName]) { 423 if ([windowName isEqualToString:tab.windowName]) {
401 return tab; 424 return tab;
402 } 425 }
403 } 426 }
404 return nil; 427 return nil;
405 } 428 }
406 429
407 - (Tab*)nextTabWithOpener:(Tab*)tab afterTab:(Tab*)afterTab { 430 - (Tab*)nextTabWithOpener:(Tab*)tab afterTab:(Tab*)afterTab {
408 NSUInteger startIndex = NSNotFound; 431 int startIndex = WebStateList::kInvalidIndex;
409 // Start looking after |afterTab|. If it's not found, start looking after
410 // |tab|. If it's not found either, bail.
411 if (afterTab) 432 if (afterTab)
412 startIndex = [self indexOfTab:afterTab]; 433 startIndex = _webStateList.GetIndexOfWebState(afterTab.webState);
413 if (startIndex == NSNotFound) 434
414 startIndex = [self indexOfTab:tab]; 435 if (startIndex == WebStateList::kInvalidIndex)
415 if (startIndex == NSNotFound) 436 startIndex = _webStateList.GetIndexOfWebState(tab.webState);
437
438 const int index = _webStateList.GetIndexOfNextWebStateOpenedBy(
439 tab.webState, startIndex, false);
440 if (index == WebStateList::kInvalidIndex)
416 return nil; 441 return nil;
417 NSString* parentID = tab.tabId; 442
418 for (NSUInteger i = startIndex + 1; i < self.count; ++i) { 443 DCHECK_GE(index, 0);
419 Tab* current = [self tabAtIndex:i]; 444 return [self tabAtIndex:static_cast<NSUInteger>(index)];
420 DCHECK([current navigationManager]);
421 CRWSessionController* sessionController =
422 [current navigationManager]->GetSessionController();
423 if ([sessionController.openerId isEqualToString:parentID])
424 return current;
425 }
426 return nil;
427 } 445 }
428 446
429 - (Tab*)lastTabWithOpener:(Tab*)tab { 447 - (Tab*)lastTabWithOpener:(Tab*)tab {
430 NSUInteger startIndex = [self indexOfTab:tab]; 448 int startIndex = _webStateList.GetIndexOfWebState(tab.webState);
431 if (startIndex == NSNotFound) 449 if (startIndex == WebStateList::kInvalidIndex)
432 return nil; 450 return nil;
433 // There is at least one tab in the model, because otherwise the above check
434 // would have returned.
435 NSString* parentID = tab.tabId;
436 DCHECK([tab navigationManager]);
437 NSInteger parentNavIndex = [tab navigationManager]->GetCurrentItemIndex();
438 451
439 Tab* match = nil; 452 const int index = _webStateList.GetIndexOfLastWebStateOpenedBy(
440 // Find the last tab in the first matching 'group'. A 'group' is a set of 453 tab.webState, startIndex, true);
441 // tabs whose opener's id and opener's navigation index match. The navigation 454 if (index == WebStateList::kInvalidIndex)
442 // index is used in addition to the session id to detect navigations changes 455 return nil;
443 // within the same session. 456
444 for (NSUInteger i = startIndex + 1; i < self.count; ++i) { 457 DCHECK_GE(index, 0);
445 Tab* tabToCheck = [self tabAtIndex:i]; 458 return [self tabAtIndex:static_cast<NSUInteger>(index)];
446 DCHECK([tabToCheck navigationManager]);
447 CRWSessionController* sessionController =
448 [tabToCheck navigationManager]->GetSessionController();
449 if ([sessionController.openerId isEqualToString:parentID] &&
450 sessionController.openerNavigationIndex == parentNavIndex) {
451 match = tabToCheck;
452 } else if (match) {
453 break;
454 }
455 }
456 return match;
457 } 459 }
458 460
459 - (Tab*)openerOfTab:(Tab*)tab { 461 - (Tab*)openerOfTab:(Tab*)tab {
460 if (![tab navigationManager]) 462 int index = _webStateList.GetIndexOfWebState(tab.webState);
463 if (index == WebStateList::kInvalidIndex)
461 return nil; 464 return nil;
462 NSString* openerId = [tab navigationManager]->GetSessionController().openerId; 465
463 if (!openerId.length) // Short-circuit if opener is empty. 466 web::WebState* opener = _webStateList.GetOpenerOfWebStateAt(index);
464 return nil; 467 return opener ? LegacyTabHelper::GetTabForWebState(opener) : nil;
465 for (Tab* iteratedTab in self) {
466 if ([iteratedTab.tabId isEqualToString:openerId])
467 return iteratedTab;
468 }
469 return nil;
470 } 468 }
471 469
472 - (Tab*)insertOrUpdateTabWithURL:(const GURL&)URL 470 - (Tab*)insertOrUpdateTabWithURL:(const GURL&)URL
473 referrer:(const web::Referrer&)referrer 471 referrer:(const web::Referrer&)referrer
474 transition:(ui::PageTransition)transition 472 transition:(ui::PageTransition)transition
475 windowName:(NSString*)windowName 473 windowName:(NSString*)windowName
476 opener:(Tab*)parentTab 474 opener:(Tab*)parentTab
477 openedByDOM:(BOOL)openedByDOM 475 openedByDOM:(BOOL)openedByDOM
478 atIndex:(NSUInteger)index 476 atIndex:(NSUInteger)index
479 inBackground:(BOOL)inBackground { 477 inBackground:(BOOL)inBackground {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 atIndex:(NSUInteger)index { 544 atIndex:(NSUInteger)index {
547 DCHECK(_browserState); 545 DCHECK(_browserState);
548 DCHECK_EQ(webState->GetBrowserState(), _browserState); 546 DCHECK_EQ(webState->GetBrowserState(), _browserState);
549 base::scoped_nsobject<Tab> tab( 547 base::scoped_nsobject<Tab> tab(
550 [[Tab alloc] initWithWebState:std::move(webState) model:self]); 548 [[Tab alloc] initWithWebState:std::move(webState) model:self]);
551 [tab webController].webUsageEnabled = webUsageEnabled_; 549 [tab webController].webUsageEnabled = webUsageEnabled_;
552 [self insertTab:tab atIndex:index]; 550 [self insertTab:tab atIndex:index];
553 return tab; 551 return tab;
554 } 552 }
555 553
556 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { 554 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab {
557 DCHECK(tab); 555 DCHECK(tab);
558 DCHECK(![_tabRetainer containsObject:tab]); 556 DCHECK(![_tabRetainer containsObject:tab]);
559 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); 557 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX));
560 558
561 [_tabRetainer addObject:tab]; 559 [_tabRetainer addObject:tab];
562 _webStateList.InsertWebState(static_cast<int>(index), tab.webState); 560 _webStateList.InsertWebState(static_cast<int>(index), tab.webState,
561 parentTab.webState);
563 562
564 // Persist the session due to a new tab being inserted. If this is a 563 // Persist the session due to a new tab being inserted. If this is a
565 // background tab (will not become active), saving now will capture the 564 // background tab (will not become active), saving now will capture the
566 // state properly. If it does eventually become active, another save will 565 // state properly. If it does eventually become active, another save will
567 // be triggered to properly capture the end result. 566 // be triggered to properly capture the end result.
568 [self saveSessionImmediately:NO]; 567 [self saveSessionImmediately:NO];
569 568
570 ++_newTabCount; 569 ++_newTabCount;
571 } 570 }
572 571
572 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index {
573 [self insertTab:tab atIndex:index opener:GetOpenerForTab(self, tab)];
574 }
575
573 - (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex { 576 - (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex {
574 DCHECK([_tabRetainer containsObject:tab]); 577 DCHECK([_tabRetainer containsObject:tab]);
575 DCHECK_LE(toIndex, static_cast<NSUInteger>(INT_MAX)); 578 DCHECK_LE(toIndex, static_cast<NSUInteger>(INT_MAX));
576 int fromIndex = _webStateList.GetIndexOfWebState(tab.webState); 579 int fromIndex = _webStateList.GetIndexOfWebState(tab.webState);
577 _webStateList.MoveWebStateAt(fromIndex, static_cast<int>(toIndex)); 580 _webStateList.MoveWebStateAt(fromIndex, static_cast<int>(toIndex));
578 } 581 }
579 582
580 - (void)replaceTab:(Tab*)oldTab withTab:(Tab*)newTab { 583 - (void)replaceTab:(Tab*)oldTab withTab:(Tab*)newTab {
581 DCHECK([_tabRetainer containsObject:oldTab]); 584 DCHECK([_tabRetainer containsObject:oldTab]);
582 DCHECK(![_tabRetainer containsObject:newTab]); 585 DCHECK(![_tabRetainer containsObject:newTab]);
583 586
584 int index = _webStateList.GetIndexOfWebState(oldTab.webState); 587 int index = _webStateList.GetIndexOfWebState(oldTab.webState);
585 DCHECK_NE(index, WebStateList::kInvalidIndex); 588 DCHECK_NE(index, WebStateList::kInvalidIndex);
586 DCHECK_GE(index, 0); 589 DCHECK_GE(index, 0);
587 590
588 base::scoped_nsobject<Tab> tabSaver([oldTab retain]); 591 base::scoped_nsobject<Tab> tabSaver([oldTab retain]);
589 [_tabRetainer removeObject:oldTab]; 592 [_tabRetainer removeObject:oldTab];
590 [_tabRetainer addObject:newTab]; 593 [_tabRetainer addObject:newTab];
591 [newTab setParentTabModel:self]; 594 [newTab setParentTabModel:self];
592 595
593 _webStateList.ReplaceWebStateAt(index, newTab.webState); 596 _webStateList.ReplaceWebStateAt(index, newTab.webState,
597 GetOpenerForTab(self, newTab).webState);
594 598
595 if (self.currentTab == oldTab) 599 if (self.currentTab == oldTab)
596 [self changeSelectedTabFrom:nil to:newTab persistState:NO]; 600 [self changeSelectedTabFrom:nil to:newTab persistState:NO];
597 601
598 [oldTab setParentTabModel:nil]; 602 [oldTab setParentTabModel:nil];
599 [oldTab close]; 603 [oldTab close];
600 } 604 }
601 605
602 - (void)closeTabAtIndex:(NSUInteger)index { 606 - (void)closeTabAtIndex:(NSUInteger)index {
603 DCHECK(index < self.count); 607 DCHECK(index < self.count);
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
882 index == self.count) { 886 index == self.count) {
883 // Also, any tab opened at the end of the TabStrip with a "TYPED" 887 // Also, any tab opened at the end of the TabStrip with a "TYPED"
884 // transition inherit group as well. This covers the cases where the user 888 // transition inherit group as well. This covers the cases where the user
885 // creates a New Tab (e.g. Ctrl+T, or clicks the New Tab button), or types 889 // creates a New Tab (e.g. Ctrl+T, or clicks the New Tab button), or types
886 // in the address bar and presses Alt+Enter. This allows for opening a new 890 // in the address bar and presses Alt+Enter. This allows for opening a new
887 // Tab to quickly look up something. When this Tab is closed, the old one 891 // Tab to quickly look up something. When this Tab is closed, the old one
888 // is re-selected, not the next-adjacent. 892 // is re-selected, not the next-adjacent.
889 // TODO(crbug.com/661988): Make this work. 893 // TODO(crbug.com/661988): Make this work.
890 } 894 }
891 895
892 [self insertTab:tab atIndex:index]; 896 [self insertTab:tab atIndex:index opener:parentTab];
893 897
894 if (!inBackground && _tabUsageRecorder) 898 if (!inBackground && _tabUsageRecorder)
895 _tabUsageRecorder->TabCreatedForSelection(tab); 899 _tabUsageRecorder->TabCreatedForSelection(tab);
896 900
897 [[tab webController] loadWithParams:params]; 901 [[tab webController] loadWithParams:params];
898 // Force the page to start loading even if it's in the background. 902 // Force the page to start loading even if it's in the background.
899 if (webUsageEnabled_) 903 if (webUsageEnabled_)
900 [[tab webController] triggerPendingLoad]; 904 [[tab webController] triggerPendingLoad];
901 NSDictionary* userInfo = @{ 905 NSDictionary* userInfo = @{
902 kTabModelTabKey : tab, 906 kTabModelTabKey : tab,
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 if (!sessions.count) 983 if (!sessions.count)
980 return NO; 984 return NO;
981 985
982 int oldCount = _webStateList.count(); 986 int oldCount = _webStateList.count();
983 DCHECK_GE(oldCount, 0); 987 DCHECK_GE(oldCount, 0);
984 988
985 web::WebState::CreateParams params(_browserState); 989 web::WebState::CreateParams params(_browserState);
986 scoped_refptr<web::CertificatePolicyCache> policyCache = 990 scoped_refptr<web::CertificatePolicyCache> policyCache =
987 web::BrowserState::GetCertificatePolicyCache(_browserState); 991 web::BrowserState::GetCertificatePolicyCache(_browserState);
988 992
993 base::scoped_nsobject<NSMutableArray<Tab*>> restoredTabs(
994 [[NSMutableArray alloc] initWithCapacity:sessions.count]);
995
996 // Recreate all the restored Tabs and add them to the WebStateList without
997 // any opener-opened relationship (as the n-th restored Tab opener may be
998 // at an index larger than n). Then in a second pass fix the openers.
989 for (CRWSessionStorage* session in sessions) { 999 for (CRWSessionStorage* session in sessions) {
990 std::unique_ptr<web::WebState> webState = 1000 std::unique_ptr<web::WebState> webState =
991 web::WebState::Create(params, session); 1001 web::WebState::Create(params, session);
992 DCHECK_EQ(webState->GetBrowserState(), _browserState); 1002 base::scoped_nsobject<Tab> tab(
993 Tab* tab = 1003 [[Tab alloc] initWithWebState:std::move(webState) model:self]);
994 [self insertTabWithWebState:std::move(webState) atIndex:self.count]; 1004 [tab webController].webUsageEnabled = webUsageEnabled_;
995 tab.webController.usePlaceholderOverlay = YES; 1005 [tab webController].usePlaceholderOverlay = YES;
996 1006
997 // Restore the CertificatePolicyCache (note that webState is invalid after 1007 // Restore the CertificatePolicyCache (note that webState is invalid after
998 // passing it via move semantic to -insertTabWithWebState:atIndex:). 1008 // passing it via move semantic to -insertTabWithWebState:atIndex:).
999 UpdateCertificatePolicyCacheFromWebState(policyCache, tab.webState); 1009 UpdateCertificatePolicyCacheFromWebState(policyCache, [tab webState]);
1010 [self insertTab:tab atIndex:self.count opener:nil];
1011 [restoredTabs addObject:tab.get()];
1000 } 1012 }
1013
1014 DCHECK_EQ(sessions.count, [restoredTabs count]);
1001 DCHECK_GT(_webStateList.count(), oldCount); 1015 DCHECK_GT(_webStateList.count(), oldCount);
1002 1016
1017 // Fix openers now that all Tabs have been restored. Only look for an opener
1018 // Tab in the newly restored Tabs and not in the already open Tabs.
1019 for (int index = oldCount; index < _webStateList.count(); ++index) {
1020 DCHECK_GE(index, oldCount);
1021 NSUInteger tabIndex = static_cast<NSUInteger>(index - oldCount);
1022 Tab* tab = [restoredTabs objectAtIndex:tabIndex];
1023 Tab* opener = GetOpenerForTab(restoredTabs.get(), tab);
1024 if (opener) {
1025 DCHECK(opener.webState);
1026 _webStateList.SetOpenerOfWebStateAt(index, opener.webState);
1027 }
1028 }
1029
1003 // Update the selected tab if there was a selected Tab in the saved session. 1030 // Update the selected tab if there was a selected Tab in the saved session.
1004 if (window.selectedIndex != NSNotFound) { 1031 if (window.selectedIndex != NSNotFound) {
1005 NSUInteger selectedIndex = window.selectedIndex + oldCount; 1032 NSUInteger selectedIndex = window.selectedIndex + oldCount;
1006 DCHECK_LT(selectedIndex, self.count); 1033 DCHECK_LT(selectedIndex, self.count);
1007 DCHECK([self tabAtIndex:selectedIndex]); 1034 DCHECK([self tabAtIndex:selectedIndex]);
1008 [self changeSelectedTabFrom:_currentTab 1035 [self changeSelectedTabFrom:_currentTab
1009 to:[self tabAtIndex:selectedIndex] 1036 to:[self tabAtIndex:selectedIndex]
1010 persistState:persistState]; 1037 persistState:persistState];
1011 } 1038 }
1012 1039
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 initWithWindowName:windowName 1127 initWithWindowName:windowName
1101 opener:parentTab 1128 opener:parentTab
1102 openedByDOM:NO 1129 openedByDOM:NO
1103 model:self 1130 model:self
1104 browserState:_browserState]); 1131 browserState:_browserState]);
1105 web::NavigationManager::WebLoadParams params(URL); 1132 web::NavigationManager::WebLoadParams params(URL);
1106 params.referrer = referrer; 1133 params.referrer = referrer;
1107 params.transition_type = ui::PAGE_TRANSITION_TYPED; 1134 params.transition_type = ui::PAGE_TRANSITION_TYPED;
1108 [[tab webController] loadWithParams:params]; 1135 [[tab webController] loadWithParams:params];
1109 [tab webController].webUsageEnabled = webUsageEnabled_; 1136 [tab webController].webUsageEnabled = webUsageEnabled_;
1110 [self insertTab:tab atIndex:index]; 1137 [self insertTab:tab atIndex:index opener:parentTab];
1111 return tab; 1138 return tab;
1112 } 1139 }
1113 1140
1114 @end 1141 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698