Chromium Code Reviews| 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_serialisation.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <unordered_map> | |
| 9 | |
| 10 #include "base/logging.h" | |
| 11 #import "base/mac/foundation_util.h" | |
| 12 #import "ios/shared/chrome/browser/tabs/web_state_list.h" | |
| 13 #import "ios/shared/chrome/browser/tabs/web_state_opener.h" | |
| 14 #import "ios/web/public/serializable_user_data_manager.h" | |
| 15 #import "ios/web/public/web_state/web_state.h" | |
| 16 | |
| 17 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 18 #error "This file requires ARC support." | |
| 19 #endif | |
| 20 | |
| 21 namespace { | |
| 22 // Keys used to store information about the opener-opened relationship between | |
| 23 // the WebStates stored in the WebStateList. | |
| 24 NSString* const kOpenerIndexKey = @"OpenerIndex"; | |
| 25 NSString* const kOpenerNavigationIndexKey = @"OpenerNavigationIndex"; | |
| 26 | |
| 27 // Legacy keys used to store information about the opener-opener relationship | |
| 28 // before the M-60 release. Remove once M-70 has shipped. | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:18
I'd prefer a bug to track this rather than milesto
 
sdefresne
2017/03/27 16:14:44
Done.
 
 | |
| 29 NSString* const kObjectIDKey = @"TabID"; | |
| 30 NSString* const kOpenerIDKey = @"OpenerID"; | |
| 31 | |
| 32 // Hash functor for using NSString* as a key of std::unordered_map<>. | |
| 33 struct NSStringHash { | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
You're using ~15 lines of helpers here to enable u
 
sdefresne
2017/03/27 16:14:44
Done.
 
 | |
| 34 using argument_type = NSString*; | |
| 35 using result_type = size_t; | |
| 36 | |
| 37 result_type operator()(NSString* value) const { | |
| 38 return std::hash<NSUInteger>()([value hash]); | |
| 39 } | |
| 40 }; | |
| 41 | |
| 42 // Comparison functor for using NSString* as a key of std::unordered_map<>. | |
| 43 struct NSStringEqualTo : std::binary_function<NSString*, NSString*, bool> { | |
| 44 bool operator()(NSString* lhs, NSString* rhs) const { | |
| 45 return [lhs isEqualToString:rhs]; | |
| 46 } | |
| 47 }; | |
| 48 | |
| 49 // Returns the value bound to |key| casted to type T. If the value is missing | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
casted -> cast. Yay, English!
 
sdefresne
2017/03/27 16:14:44
Function was never used, removed.
 
 | |
| 50 // or not of type T, then returns nil. | |
| 51 template <typename T> | |
| 52 T* GetValueForSerialisationKey(web::WebState* web_state, NSString* key) { | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:18
Is using the same name as a web::SerializableUserD
 
sdefresne
2017/03/27 16:14:44
It was intentional. I've removed as it is not used
 
 | |
| 53 return base::mac::ObjCCast<T>( | |
| 54 web::SerializableUserDataManager::FromWebState(web_state) | |
| 55 ->GetValueForSerializationKey(key)); | |
| 56 } | |
| 57 | |
| 58 // Restores the WebStates opener-opened relationship. This function includes | |
| 59 // compatibility code to load sessions saved with M-59 or older; remove this | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:18
Same comment wrt milestones.
 
sdefresne
2017/03/27 16:14:44
Done.
 
 | |
| 60 // compatibility code once M-70 is released. | |
| 61 void RestoreOpenerRelationShip(WebStateList* web_state_list, int old_count) { | |
| 62 // Detect if version M-59 or older created the serialised session state by | |
| 63 // looking for the presence of kOpenerIndexKey in WebState's data manager. | |
| 64 bool pre_m60_saved_session = false; | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
legacy_saved_session?
 
sdefresne
2017/03/27 16:14:44
Ack.
 
 | |
| 65 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 66 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 67 web::SerializableUserDataManager* user_data_manager = | |
| 68 web::SerializableUserDataManager::FromWebState(web_state); | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
Doesn't your helper method on line 52 do this for
 
sdefresne
2017/03/27 16:14:44
I've removed the method.
 
 | |
| 69 | |
| 70 if (user_data_manager->GetValueForSerializationKey(kOpenerIndexKey)) | |
| 71 continue; | |
| 72 | |
| 73 pre_m60_saved_session = true; | |
| 74 break; | |
| 75 } | |
| 76 | |
| 77 if (pre_m60_saved_session) { | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
This is a 90-line method, so maybe extract the leg
 
sdefresne
2017/03/27 16:14:44
Done.
 
 | |
| 78 std::unordered_map<NSString*, web::WebState*, NSStringHash, NSStringEqualTo> | |
| 79 id_to_web_state; | |
| 80 | |
| 81 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 82 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 83 web::SerializableUserDataManager* user_data_manager = | |
| 84 web::SerializableUserDataManager::FromWebState(web_state); | |
| 85 | |
| 86 NSString* object_id = base::mac::ObjCCast<NSString>( | |
| 87 user_data_manager->GetValueForSerializationKey(kObjectIDKey)); | |
| 88 | |
| 89 // The value may be missing during tests, skip object. | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:18
Is this conditional *only* to support tests? If so
 
sdefresne
2017/03/27 16:14:44
Removed the comment as this is also to support "co
 
 | |
| 90 if (!object_id || ![object_id length]) | |
| 91 continue; | |
| 92 | |
| 93 DCHECK(id_to_web_state.find(object_id) == id_to_web_state.end()); | |
| 94 id_to_web_state.insert(std::make_pair(object_id, web_state)); | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
Any reason why the (to me) more readable
 id_to_w
 
sdefresne
2017/03/27 16:14:44
operator [] requires the value to be copyable, def
 
 | |
| 95 } | |
| 96 | |
| 97 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 98 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 99 web::SerializableUserDataManager* user_data_manager = | |
| 100 web::SerializableUserDataManager::FromWebState(web_state); | |
| 101 | |
| 102 NSString* opener_id = base::mac::ObjCCast<NSString>( | |
| 103 user_data_manager->GetValueForSerializationKey(kOpenerIDKey)); | |
| 104 | |
| 105 NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( | |
| 106 user_data_manager->GetValueForSerializationKey( | |
| 107 kOpenerNavigationIndexKey)); | |
| 108 | |
| 109 // The opener ID or opener navigation index may be missing, assume no | |
| 110 // opener in that case. | |
| 111 if (!opener_id || !boxed_opener_navigation_index || ![opener_id length]) | |
| 112 continue; | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
Also continue if the opener nav index < 0?
 
sdefresne
2017/03/27 16:14:44
No, negative value is used during the tests.
 
 | |
| 113 | |
| 114 // Assume no opener if the opener ID is not found in id_to_web_state | |
| 115 // (i.e. do not crash if saved state is partially broken). | |
| 116 auto iterator = id_to_web_state.find(opener_id); | |
| 117 if (iterator == id_to_web_state.end()) | |
| 118 continue; | |
| 119 | |
| 120 web_state_list->SetOpenerOfWebStateAt( | |
| 121 index, WebStateOpener(iterator->second, | |
| 122 [boxed_opener_navigation_index intValue])); | |
| 123 } | |
| 124 | |
| 125 return; | |
| 126 } | |
| 127 | |
| 128 for (int index = old_count; index < web_state_list->count(); ++index) { | |
| 129 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 130 web::SerializableUserDataManager* user_data_manager = | |
| 131 web::SerializableUserDataManager::FromWebState(web_state); | |
| 132 | |
| 133 NSNumber* boxed_opener_index = base::mac::ObjCCast<NSNumber>( | |
| 134 user_data_manager->GetValueForSerializationKey(kOpenerIndexKey)); | |
| 135 | |
| 136 NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( | |
| 137 user_data_manager->GetValueForSerializationKey( | |
| 138 kOpenerNavigationIndexKey)); | |
| 139 | |
| 140 // The opener index and opener navigation index will be set to NSNull if | |
| 141 // there is no opener, thus the cast to NSNumber will fail. In that case, | |
| 142 // assumes there is no opener. | |
| 143 if (!boxed_opener_index || !boxed_opener_navigation_index) | |
| 144 continue; | |
| 145 | |
| 146 // If opener index is out of bound then assume there is no opener. | |
| 147 int opener_index = [boxed_opener_index intValue] + old_count; | |
| 148 if (opener_index < old_count || opener_index >= web_state_list->count()) | |
| 149 continue; | |
| 150 | |
| 151 web::WebState* opener = web_state_list->GetWebStateAt(opener_index); | |
| 152 web_state_list->SetOpenerOfWebStateAt( | |
| 153 index, WebStateOpener(opener, [boxed_opener_index intValue])); | |
| 154 } | |
| 155 } | |
| 156 } // namespace | |
| 157 | |
| 158 NSArray<CRWSessionStorage*>* SerializeWebStateList( | |
| 159 WebStateList* web_state_list) { | |
| 160 NSMutableArray<CRWSessionStorage*>* serialized_session = | |
| 161 [NSMutableArray arrayWithCapacity:web_state_list->count()]; | |
| 162 | |
| 163 for (int index = 0; index < web_state_list->count(); ++index) { | |
| 164 web::WebState* web_state = web_state_list->GetWebStateAt(index); | |
| 165 WebStateOpener opener = web_state_list->GetOpenerOfWebStateAt(index); | |
| 166 | |
| 167 web::SerializableUserDataManager* user_data_manager = | |
| 168 web::SerializableUserDataManager::FromWebState(web_state); | |
| 169 | |
| 170 int opener_index = WebStateList::kInvalidIndex; | |
| 171 if (opener.opener) { | |
| 172 opener_index = web_state_list->GetIndexOfWebState(opener.opener); | |
| 173 DCHECK_NE(opener_index, WebStateList::kInvalidIndex); | |
| 174 user_data_manager->AddSerializableData(@(opener_index), kOpenerIndexKey); | |
| 175 user_data_manager->AddSerializableData(@(opener.navigation_index), | |
| 176 kOpenerNavigationIndexKey); | |
| 177 } else { | |
| 178 user_data_manager->AddSerializableData([NSNull null], kOpenerIndexKey); | |
| 179 user_data_manager->AddSerializableData([NSNull null], | |
| 180 kOpenerNavigationIndexKey); | |
| 181 } | |
| 182 | |
| 183 [serialized_session addObject:web_state->BuildSessionStorage()]; | |
| 184 } | |
| 185 | |
| 186 return serialized_session; | |
| 
 
marq (ping after 24h)
2017/03/24 10:37:17
[serialized_session copy] since the return value i
 
sdefresne
2017/03/27 16:14:44
Done.
 
 | |
| 187 } | |
| 188 | |
| 189 int DeserializeWebStateListFrom(WebStateList* web_state_list, | |
| 190 web::WebState::CreateParams params, | |
| 191 NSArray<CRWSessionStorage*>* sessions) { | |
| 192 int old_count = web_state_list->count(); | |
| 193 for (CRWSessionStorage* session in sessions) { | |
| 194 std::unique_ptr<web::WebState> web_state = | |
| 195 web::WebState::Create(params, session); | |
| 196 | |
| 197 web_state_list->InsertWebState(web_state_list->count(), | |
| 198 std::move(web_state)); | |
| 199 } | |
| 200 | |
| 201 RestoreOpenerRelationShip(web_state_list, old_count); | |
| 202 return web_state_list->count() - old_count; | |
| 203 } | |
| OLD | NEW |