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 |