| 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 |