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 |