| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #import "ios/shared/chrome/browser/tabs/web_state_list_serialization.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <unordered_map> | |
| 9 | |
| 10 #include "base/callback.h" | |
| 11 #include "base/logging.h" | |
| 12 #import "base/mac/foundation_util.h" | |
| 13 #import "ios/shared/chrome/browser/tabs/web_state_list.h" | |
| 14 #import "ios/shared/chrome/browser/tabs/web_state_opener.h" | |
| 15 #import "ios/web/public/serializable_user_data_manager.h" | |
| 16 #import "ios/web/public/web_state/web_state.h" | |
| 17 | |
| 18 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 19 #error "This file requires ARC support." | |
| 20 #endif | |
| 21 | |
| 22 namespace { | |
| 23 // Keys used to store information about the opener-opened relationship between | |
| 24 // the WebStates stored in the WebStateList. | |
| 25 NSString* const kOpenerIndexKey = @"OpenerIndex"; | |
| 26 NSString* const kOpenerNavigationIndexKey = @"OpenerNavigationIndex"; | |
| 27 | |
| 28 // Legacy keys used to store information about the opener-opener relationship | |
| 29 // before the M-60 release. Remove once M-70 has shipped. | |
| 30 NSString* const kObjectIDKey = @"TabID"; | |
| 31 NSString* const kOpenerIDKey = @"OpenerID"; | |
| 32 | |
| 33 // Returns whether the opener-opener relationship is encoded with legacy format. | |
| 34 // The legacy format (pre M-59) references the opener by id while the new format | |
| 35 // references it by index. | |
| 36 // TODO(crbug.com/704941): remove once no sessions uses the old format. | |
| 37 bool IsSessionUsingLegacyFormat(WebStateList* web_state_list, int old_count) { | |
| 38 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 39 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 40 web::SerializableUserDataManager* user_data_manager = | |
| 41 web::SerializableUserDataManager::FromWebState(web_state); | |
| 42 | |
| 43 if (!user_data_manager->GetValueForSerializationKey(kOpenerIndexKey)) | |
| 44 return true; | |
| 45 } | |
| 46 return false; | |
| 47 } | |
| 48 | |
| 49 // Restores the WebStates opener-opened relationship. The relationship is | |
| 50 // encoded using legacy format. | |
| 51 // TODO(crbug.com/704941): remove once no sessions uses the old format. | |
| 52 void RestoreRelationshipLegacy(WebStateList* web_state_list, int old_count) { | |
| 53 NSMutableDictionary<NSString*, NSValue*>* id_to_web_state = | |
| 54 [NSMutableDictionary dictionary]; | |
| 55 | |
| 56 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 57 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 58 web::SerializableUserDataManager* user_data_manager = | |
| 59 web::SerializableUserDataManager::FromWebState(web_state); | |
| 60 | |
| 61 NSString* object_id = base::mac::ObjCCast<NSString>( | |
| 62 user_data_manager->GetValueForSerializationKey(kObjectIDKey)); | |
| 63 | |
| 64 if (!object_id || ![object_id length]) | |
| 65 continue; | |
| 66 | |
| 67 if (id_to_web_state[object_id] != nil) | |
| 68 continue; | |
| 69 | |
| 70 id_to_web_state[object_id] = [NSValue valueWithPointer:web_state]; | |
| 71 } | |
| 72 | |
| 73 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 74 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 75 web::SerializableUserDataManager* user_data_manager = | |
| 76 web::SerializableUserDataManager::FromWebState(web_state); | |
| 77 | |
| 78 NSString* opener_id = base::mac::ObjCCast<NSString>( | |
| 79 user_data_manager->GetValueForSerializationKey(kOpenerIDKey)); | |
| 80 | |
| 81 NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( | |
| 82 user_data_manager->GetValueForSerializationKey( | |
| 83 kOpenerNavigationIndexKey)); | |
| 84 | |
| 85 if (!opener_id || !boxed_opener_navigation_index || ![opener_id length]) | |
| 86 continue; | |
| 87 | |
| 88 if (id_to_web_state[opener_id] == nil) | |
| 89 continue; | |
| 90 | |
| 91 web::WebState* opener_web_state = | |
| 92 static_cast<web::WebState*>(id_to_web_state[opener_id].pointerValue); | |
| 93 | |
| 94 web_state_list->SetOpenerOfWebStateAt( | |
| 95 index, WebStateOpener(opener_web_state, | |
| 96 [boxed_opener_navigation_index intValue])); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 // Restores the WebStates opener-opened relationship. | |
| 101 void RestoreRelationship(WebStateList* web_state_list, int old_count) { | |
| 102 if (IsSessionUsingLegacyFormat(web_state_list, old_count)) | |
| 103 return RestoreRelationshipLegacy(web_state_list, old_count); | |
| 104 | |
| 105 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 106 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 107 web::SerializableUserDataManager* user_data_manager = | |
| 108 web::SerializableUserDataManager::FromWebState(web_state); | |
| 109 | |
| 110 NSNumber* boxed_opener_index = base::mac::ObjCCast<NSNumber>( | |
| 111 user_data_manager->GetValueForSerializationKey(kOpenerIndexKey)); | |
| 112 | |
| 113 NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( | |
| 114 user_data_manager->GetValueForSerializationKey( | |
| 115 kOpenerNavigationIndexKey)); | |
| 116 | |
| 117 if (!boxed_opener_index || !boxed_opener_navigation_index) | |
| 118 continue; | |
| 119 | |
| 120 // If opener index is out of bound then assume there is no opener. | |
| 121 int opener_index = [boxed_opener_index intValue] + old_count; | |
| 122 if (opener_index < old_count || opener_index >= web_state_list->count()) | |
| 123 continue; | |
| 124 | |
| 125 web::WebState* opener = web_state_list->GetWebStateAt(opener_index); | |
| 126 web_state_list->SetOpenerOfWebStateAt( | |
| 127 index, | |
| 128 WebStateOpener(opener, [boxed_opener_navigation_index intValue])); | |
| 129 } | |
| 130 } | |
| 131 } // namespace | |
| 132 | |
| 133 NSArray<CRWSessionStorage*>* SerializeWebStateList( | |
| 134 WebStateList* web_state_list) { | |
| 135 NSMutableArray<CRWSessionStorage*>* serialized_session = | |
| 136 [NSMutableArray arrayWithCapacity:web_state_list->count()]; | |
| 137 | |
| 138 for (int index = 0; index < web_state_list->count(); ++index) { | |
| 139 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 140 WebStateOpener opener = web_state_list->GetOpenerOfWebStateAt(index); | |
| 141 | |
| 142 web::SerializableUserDataManager* user_data_manager = | |
| 143 web::SerializableUserDataManager::FromWebState(web_state); | |
| 144 | |
| 145 int opener_index = WebStateList::kInvalidIndex; | |
| 146 if (opener.opener) { | |
| 147 opener_index = web_state_list->GetIndexOfWebState(opener.opener); | |
| 148 DCHECK_NE(opener_index, WebStateList::kInvalidIndex); | |
| 149 user_data_manager->AddSerializableData(@(opener_index), kOpenerIndexKey); | |
| 150 user_data_manager->AddSerializableData(@(opener.navigation_index), | |
| 151 kOpenerNavigationIndexKey); | |
| 152 } else { | |
| 153 user_data_manager->AddSerializableData([NSNull null], kOpenerIndexKey); | |
| 154 user_data_manager->AddSerializableData([NSNull null], | |
| 155 kOpenerNavigationIndexKey); | |
| 156 } | |
| 157 | |
| 158 [serialized_session addObject:web_state->BuildSessionStorage()]; | |
| 159 } | |
| 160 | |
| 161 return [serialized_session copy]; | |
| 162 } | |
| 163 | |
| 164 void DeserializeWebStateList(WebStateList* web_state_list, | |
| 165 NSArray<CRWSessionStorage*>* sessions, | |
| 166 const WebStateFactory& web_state_factory) { | |
| 167 int old_count = web_state_list->count(); | |
| 168 for (CRWSessionStorage* session in sessions) { | |
| 169 std::unique_ptr<web::WebState> web_state = web_state_factory.Run(session); | |
| 170 web_state_list->InsertWebState(web_state_list->count(), | |
| 171 std::move(web_state)); | |
| 172 } | |
| 173 | |
| 174 RestoreRelationship(web_state_list, old_count); | |
| 175 } | |
| OLD | NEW |