Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: ios/web/navigation/crw_session_controller.mm

Issue 2737203002: Remove CRWSessionEntry. (Closed)
Patch Set: fix XCode-clang build Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/web/navigation/crw_session_controller.h" 5 #import "ios/web/navigation/crw_session_controller.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <utility> 10 #include <utility>
11 #include <vector>
12 11
13 #include "base/format_macros.h" 12 #include "base/format_macros.h"
14 #include "base/logging.h" 13 #include "base/logging.h"
15 #import "base/mac/foundation_util.h" 14 #import "base/mac/foundation_util.h"
16 #import "base/mac/scoped_nsobject.h" 15 #import "base/mac/scoped_nsobject.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/strings/sys_string_conversions.h" 17 #include "base/strings/sys_string_conversions.h"
18 #include "ios/web/history_state_util.h" 18 #include "ios/web/history_state_util.h"
19 #import "ios/web/navigation/crw_session_certificate_policy_manager.h" 19 #import "ios/web/navigation/crw_session_certificate_policy_manager.h"
20 #import "ios/web/navigation/crw_session_controller+private_constructors.h" 20 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
21 #import "ios/web/navigation/crw_session_entry.h"
22 #import "ios/web/navigation/navigation_item_impl.h" 21 #import "ios/web/navigation/navigation_item_impl.h"
23 #include "ios/web/navigation/navigation_manager_facade_delegate.h" 22 #include "ios/web/navigation/navigation_manager_facade_delegate.h"
24 #import "ios/web/navigation/navigation_manager_impl.h" 23 #import "ios/web/navigation/navigation_manager_impl.h"
25 #include "ios/web/navigation/time_smoother.h" 24 #include "ios/web/navigation/time_smoother.h"
26 #include "ios/web/public/browser_state.h" 25 #include "ios/web/public/browser_state.h"
27 #include "ios/web/public/browser_url_rewriter.h" 26 #include "ios/web/public/browser_url_rewriter.h"
28 #include "ios/web/public/referrer.h" 27 #include "ios/web/public/referrer.h"
29 #include "ios/web/public/ssl_status.h" 28 #include "ios/web/public/ssl_status.h"
30 #import "ios/web/public/web_client.h" 29 #import "ios/web/public/web_client.h"
31 30
32 #if !defined(__has_feature) || !__has_feature(objc_arc) 31 #if !defined(__has_feature) || !__has_feature(objc_arc)
33 #error "This file requires ARC support." 32 #error "This file requires ARC support."
34 #endif 33 #endif
35 34
36 @interface CRWSessionController () { 35 @interface CRWSessionController () {
37 // Weak pointer back to the owning NavigationManager. This is to facilitate 36 // Weak pointer back to the owning NavigationManager. This is to facilitate
38 // the incremental merging of the two classes. 37 // the incremental merging of the two classes.
39 web::NavigationManagerImpl* _navigationManager; 38 web::NavigationManagerImpl* _navigationManager;
40 39
41 // Identifies the index of the current navigation in the CRWSessionEntry 40 // Identifies the index of the current navigation in the NavigationItem
42 // array. 41 // array.
43 NSInteger _currentNavigationIndex; 42 NSInteger _currentNavigationIndex;
44 // Identifies the index of the previous navigation in the CRWSessionEntry 43 // Identifies the index of the previous navigation in the NavigationItem
45 // array. 44 // array.
46 NSInteger _previousNavigationIndex; 45 NSInteger _previousNavigationIndex;
47 // Ordered array of |CRWSessionEntry| objects, one for each site in session
48 // history. End of the list is the most recent load.
49 NSMutableArray* _entries;
50
51 // An entry we haven't gotten a response for yet. This will be discarded
52 // when we navigate again. It's used only so we know what the currently
53 // displayed tab is. It backs the property of the same name and should only
54 // be set through its setter.
55 base::scoped_nsobject<CRWSessionEntry> _pendingEntry;
56
57 // The transient entry, if any. A transient entry is discarded on any
58 // navigation, and is used for representing interstitials that need to be
59 // represented in the session. It backs the property of the same name and
60 // should only be set through its setter.
61 base::scoped_nsobject<CRWSessionEntry> _transientEntry;
62 46
63 // Stores the certificate policies decided by the user. 47 // Stores the certificate policies decided by the user.
64 CRWSessionCertificatePolicyManager* _sessionCertificatePolicyManager; 48 CRWSessionCertificatePolicyManager* _sessionCertificatePolicyManager;
65 49
66 // The browser state associated with this CRWSessionController; 50 // The browser state associated with this CRWSessionController;
67 web::BrowserState* _browserState; // weak 51 web::BrowserState* _browserState; // weak
68 52
69 // Time smoother for navigation entry timestamps; see comment in 53 // Time smoother for navigation item timestamps; see comment in
70 // navigation_controller_impl.h 54 // navigation_controller_impl.h
71 web::TimeSmoother _timeSmoother; 55 web::TimeSmoother _timeSmoother;
56
57 // Backing objects for properties of the same name.
58 web::ScopedNavigationItemImplList _items;
59 // |_pendingItem| only contains a NavigationItem for non-history navigations.
60 // For back/forward navigations within session history, _pendingItemIndex will
61 // be equal to -1, and self.pendingItem will return an item contained within
62 // |_items|.
63 std::unique_ptr<web::NavigationItemImpl> _pendingItem;
64 std::unique_ptr<web::NavigationItemImpl> _transientItem;
72 } 65 }
73 66
74 // Redefine as readwrite. 67 // Redefine as readwrite.
75 @property(nonatomic, readwrite, assign) NSInteger currentNavigationIndex; 68 @property(nonatomic, readwrite, assign) NSInteger currentNavigationIndex;
76 69
77 // TODO(rohitrao): These properties must be redefined readwrite to work around a 70 // TODO(rohitrao): These properties must be redefined readwrite to work around a
78 // clang bug. crbug.com/228650 71 // clang bug. crbug.com/228650
79 @property(nonatomic, readwrite, strong) NSArray* entries;
80 @property(nonatomic, readwrite, strong) 72 @property(nonatomic, readwrite, strong)
81 CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; 73 CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager;
82 74
83 // Expose setters for serialization properties. These are exposed in a category 75 // Expose setters for serialization properties. These are exposed in a category
84 // in SessionStorageBuilder, and will be removed as ownership of 76 // in SessionStorageBuilder, and will be removed as ownership of
85 // their backing ivars moves to NavigationManagerImpl. 77 // their backing ivars moves to NavigationManagerImpl.
86 @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM; 78 @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM;
87 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex; 79 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex;
88 80
89 // Removes all entries after currentNavigationIndex_. 81 // Removes all items after currentNavigationIndex_.
90 - (void)clearForwardItems; 82 - (void)clearForwardItems;
91 // Discards the transient entry, if any. 83 // Discards the transient item, if any.
92 - (void)discardTransientItem; 84 - (void)discardTransientItem;
93 // Create a new autoreleased session entry. 85 // Creates a NavigationItemImpl with the specified properties.
94 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url 86 - (std::unique_ptr<web::NavigationItemImpl>)
95 referrer:(const web::Referrer&)referrer 87 itemWithURL:(const GURL&)url
96 transition:(ui::PageTransition)transition 88 referrer:(const web::Referrer&)referrer
97 initiationType: 89 transition:(ui::PageTransition)transition
98 (web::NavigationInitiationType)initiationType; 90 initiationType:(web::NavigationInitiationType)initiationType;
99 // Returns YES if the PageTransition for the underlying navigationItem at 91 // Returns YES if the PageTransition for the underlying navigationItem at
100 // |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK. 92 // |index| in |items| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
101 - (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index; 93 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index;
102 // Returns a NavigationItemList containing the NavigationItems from |entries|. 94
103 - (web::NavigationItemList)itemListForEntryList:(NSArray*)entries;
104 @end 95 @end
105 96
106 @implementation CRWSessionController 97 @implementation CRWSessionController
107 98
108 @synthesize currentNavigationIndex = _currentNavigationIndex; 99 @synthesize currentNavigationIndex = _currentNavigationIndex;
109 @synthesize previousNavigationIndex = _previousNavigationIndex; 100 @synthesize previousNavigationIndex = _previousNavigationIndex;
110 @synthesize pendingItemIndex = _pendingItemIndex; 101 @synthesize pendingItemIndex = _pendingItemIndex;
111 @synthesize entries = _entries;
112 @synthesize openedByDOM = _openedByDOM; 102 @synthesize openedByDOM = _openedByDOM;
113 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager; 103 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager;
114 104
115 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState 105 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState
116 openedByDOM:(BOOL)openedByDOM { 106 openedByDOM:(BOOL)openedByDOM {
117 self = [super init]; 107 self = [super init];
118 if (self) { 108 if (self) {
119 _openedByDOM = openedByDOM; 109 _openedByDOM = openedByDOM;
120 _browserState = browserState; 110 _browserState = browserState;
121 _entries = [NSMutableArray array];
122 _currentNavigationIndex = -1; 111 _currentNavigationIndex = -1;
123 _previousNavigationIndex = -1; 112 _previousNavigationIndex = -1;
124 _pendingItemIndex = -1; 113 _pendingItemIndex = -1;
125 _sessionCertificatePolicyManager = 114 _sessionCertificatePolicyManager =
126 [[CRWSessionCertificatePolicyManager alloc] init]; 115 [[CRWSessionCertificatePolicyManager alloc] init];
127 } 116 }
128 return self; 117 return self;
129 } 118 }
130 119
131 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState 120 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState
132 navigationItems:(web::ScopedNavigationItemList)items 121 navigationItems:(web::ScopedNavigationItemList)items
133 currentIndex:(NSUInteger)currentIndex { 122 currentIndex:(NSUInteger)currentIndex {
134 self = [super init]; 123 self = [super init];
135 if (self) { 124 if (self) {
136 _browserState = browserState; 125 _browserState = browserState;
137 126 _items = web::CreateScopedNavigationItemImplList(std::move(items));
138 // Create entries array from list of navigations. 127 _currentNavigationIndex =
139 _entries = [[NSMutableArray alloc] initWithCapacity:items.size()]; 128 std::min(static_cast<NSInteger>(currentIndex),
140 for (auto& item : items) { 129 static_cast<NSInteger>(_items.size()) - 1);
141 base::scoped_nsobject<CRWSessionEntry> entry(
142 [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]);
143 [_entries addObject:entry];
144 }
145 self.currentNavigationIndex = currentIndex;
146 // Prior to M34, 0 was used as "no index" instead of -1; adjust for that.
147 if (![_entries count])
148 self.currentNavigationIndex = -1;
149 if (_currentNavigationIndex >= static_cast<NSInteger>(items.size())) {
150 self.currentNavigationIndex = static_cast<NSInteger>(items.size()) - 1;
151 }
152 _previousNavigationIndex = -1; 130 _previousNavigationIndex = -1;
153 _pendingItemIndex = -1; 131 _pendingItemIndex = -1;
154 _sessionCertificatePolicyManager = 132 _sessionCertificatePolicyManager =
155 [[CRWSessionCertificatePolicyManager alloc] init]; 133 [[CRWSessionCertificatePolicyManager alloc] init];
156 } 134 }
157 return self; 135 return self;
158 } 136 }
159 137
160 - (id)copyWithZone:(NSZone*)zone { 138 #pragma mark - Accessors
161 CRWSessionController* copy = [[[self class] alloc] init];
162 copy->_openedByDOM = _openedByDOM;
163 copy->_currentNavigationIndex = _currentNavigationIndex;
164 copy->_previousNavigationIndex = _previousNavigationIndex;
165 copy->_pendingItemIndex = _pendingItemIndex;
166 copy->_entries =
167 [[NSMutableArray alloc] initWithArray:_entries copyItems:YES];
168 copy->_sessionCertificatePolicyManager =
169 [_sessionCertificatePolicyManager copy];
170 return copy;
171 }
172 139
173 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex { 140 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
174 if (_currentNavigationIndex != currentNavigationIndex) { 141 if (_currentNavigationIndex != currentNavigationIndex) {
175 _currentNavigationIndex = currentNavigationIndex; 142 _currentNavigationIndex = currentNavigationIndex;
176 if (_navigationManager) 143 if (_navigationManager)
177 _navigationManager->RemoveTransientURLRewriters(); 144 _navigationManager->RemoveTransientURLRewriters();
178 } 145 }
179 } 146 }
180 147
181 - (void)setPendingItemIndex:(NSInteger)index { 148 - (void)setPendingItemIndex:(NSInteger)pendingItemIndex {
182 DCHECK_GE(index, -1); 149 DCHECK_GE(pendingItemIndex, -1);
183 DCHECK_LT(index, static_cast<NSInteger>(_entries.count)); 150 DCHECK_LT(pendingItemIndex, static_cast<NSInteger>(self.items.size()));
184 _pendingItemIndex = index; 151 _pendingItemIndex = pendingItemIndex;
185 CRWSessionEntry* entry = index != -1 ? _entries[index] : nil; 152 DCHECK(_pendingItemIndex == -1 || self.pendingItem);
186 _pendingEntry.reset(entry);
187 DCHECK(_pendingItemIndex == -1 || _pendingEntry);
188 } 153 }
189 154
155 - (const web::ScopedNavigationItemImplList&)items {
156 return _items;
157 }
158
159 - (web::NavigationItemImpl*)currentItem {
160 if (self.transientItem)
161 return self.transientItem;
162 if (self.pendingItem)
163 return self.pendingItem;
164 return self.lastCommittedItem;
165 }
166
167 - (web::NavigationItemImpl*)visibleItem {
168 if (self.transientItem)
169 return self.transientItem;
170 // Only return the |pendingItem| for new (non-history), browser-initiated
171 // navigations in order to prevent URL spoof attacks.
172 web::NavigationItemImpl* pendingItem = self.pendingItem;
173 if (pendingItem) {
174 bool isUserInitiated = pendingItem->NavigationInitiationType() ==
175 web::NavigationInitiationType::USER_INITIATED;
176 bool safeToShowPending = isUserInitiated && _pendingItemIndex == -1;
177
178 if (safeToShowPending)
179 return pendingItem;
180 }
181 return self.lastCommittedItem;
182 }
183
184 - (web::NavigationItemImpl*)pendingItem {
185 if (self.pendingItemIndex == -1)
186 return _pendingItem.get();
187 return self.items[self.pendingItemIndex].get();
188 }
189
190 - (web::NavigationItemImpl*)transientItem {
191 return _transientItem.get();
192 }
193
194 - (web::NavigationItemImpl*)lastCommittedItem {
195 NSInteger index = self.currentNavigationIndex;
196 return index == -1 ? nullptr : self.items[index].get();
197 }
198
199 - (web::NavigationItemImpl*)previousItem {
200 NSInteger index = self.previousNavigationIndex;
201 return index == -1 || self.items.empty() ? nullptr : self.items[index].get();
202 }
203
204 - (web::NavigationItemImpl*)lastUserItem {
205 if (self.items.empty())
206 return nil;
207
208 NSInteger index = self.currentNavigationIndex;
209 // This will return the first NavigationItem if all other items are
210 // redirects, regardless of the transition state of the first item.
211 while (index > 0 && [self isRedirectTransitionForItemAtIndex:index])
212 --index;
213
214 return self.items[index].get();
215 }
216
217 - (web::NavigationItemList)backwardItems {
218 web::NavigationItemList items;
219 for (size_t index = _currentNavigationIndex; index > 0; --index) {
220 if (![self isRedirectTransitionForItemAtIndex:index])
221 items.push_back(self.items[index - 1].get());
222 }
223 return items;
224 }
225
226 - (web::NavigationItemList)forwardItems {
227 web::NavigationItemList items;
228 NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
229 while (lastNonRedirectedIndex < self.items.size()) {
230 web::NavigationItem* item = self.items[lastNonRedirectedIndex].get();
231 if (!ui::PageTransitionIsRedirect(item->GetTransitionType()))
232 items.push_back(item);
233 ++lastNonRedirectedIndex;
234 }
235 return items;
236 }
237
238 #pragma mark - NSObject
239
240 - (NSString*)description {
241 // Create description for |items|.
242 NSMutableString* itemsDescription = [NSMutableString stringWithString:@"[\n"];
243 #ifndef NDEBUG
244 for (const auto& item : self.items)
245 [itemsDescription appendFormat:@"%@\n", item->GetDescription()];
246 #endif
247 [itemsDescription appendString:@"]"];
248 // Create description for |pendingItem| and |transientItem|.
249 NSString* pendingItemDescription = @"(null)";
250 NSString* transientItemDescription = @"(null)";
251 #ifndef NDEBUG
252 if (self.pendingItem)
253 pendingItemDescription = self.pendingItem->GetDescription();
254 if (self.transientItem)
255 transientItemDescription = self.transientItem->GetDescription();
256 #else
257 if (self.pendingItem) {
258 pendingItemDescription =
259 [NSString stringWithFormat:@"%p", self.pendingItem];
260 }
261 if (self.transientItem) {
262 transientItemDescription =
263 [NSString stringWithFormat:@"%p", self.transientItem];
264 }
265 #endif
266 return [NSString stringWithFormat:@"current index: %" PRIdNS
267 @"\nprevious index: %" PRIdNS
268 @"\npending"
269 @" index: %" PRIdNS
270 @"\n%@\npending: %@\ntransient: %@\n",
271 _currentNavigationIndex,
272 _previousNavigationIndex, _pendingItemIndex,
273 itemsDescription, pendingItemDescription,
274 transientItemDescription];
275 }
276
277 #pragma mark - NSCopying
278
279 - (id)copyWithZone:(NSZone*)zone {
280 CRWSessionController* copy = [[[self class] alloc] init];
281 copy->_openedByDOM = _openedByDOM;
282 copy->_currentNavigationIndex = _currentNavigationIndex;
283 copy->_previousNavigationIndex = _previousNavigationIndex;
284 copy->_pendingItemIndex = _pendingItemIndex;
285 copy->_sessionCertificatePolicyManager =
286 [_sessionCertificatePolicyManager copy];
287 web::ScopedNavigationItemImplList itemCopies(self.items.size());
288 for (size_t index = 0; index < self.items.size(); ++index) {
289 itemCopies[index] =
290 base::MakeUnique<web::NavigationItemImpl>(*self.items[index]);
291 }
292 std::swap(copy->_items, itemCopies);
293 return copy;
294 }
295
296 #pragma mark - Public
297
190 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager { 298 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager {
191 _navigationManager = navigationManager; 299 _navigationManager = navigationManager;
192 if (_navigationManager) { 300 if (_navigationManager) {
193 // _browserState will be nullptr if CRWSessionController has been 301 // _browserState will be nullptr if CRWSessionController has been
194 // initialized with -initWithCoder: method. Take _browserState from 302 // initialized with -initWithCoder: method. Take _browserState from
195 // NavigationManagerImpl if that's the case. 303 // NavigationManagerImpl if that's the case.
196 if (!_browserState) { 304 if (!_browserState) {
197 _browserState = _navigationManager->GetBrowserState(); 305 _browserState = _navigationManager->GetBrowserState();
198 } 306 }
199 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState()); 307 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState());
200 } 308 }
201 } 309 }
202 310
203 - (void)setBrowserState:(web::BrowserState*)browserState { 311 - (void)setBrowserState:(web::BrowserState*)browserState {
204 _browserState = browserState; 312 _browserState = browserState;
205 DCHECK(!_navigationManager || 313 DCHECK(!_navigationManager ||
206 _navigationManager->GetBrowserState() == _browserState); 314 _navigationManager->GetBrowserState() == _browserState);
207 } 315 }
208 316
209 - (NSString*)description {
210 return [NSString stringWithFormat:@"current index: %" PRIdNS
211 @"\nprevious index: %" PRIdNS
212 @"\npending index: %" PRIdNS
213 @"\n%@\npending: %@\ntransient: %@\n",
214 _currentNavigationIndex,
215 _previousNavigationIndex, _pendingItemIndex,
216 _entries, _pendingEntry.get(),
217 _transientEntry.get()];
218 }
219
220 - (web::NavigationItemList)items {
221 return [self itemListForEntryList:self.entries];
222 }
223
224 - (NSUInteger)itemCount {
225 return self.entries.count;
226 }
227
228 - (web::NavigationItemImpl*)currentItem {
229 return self.currentEntry.navigationItemImpl;
230 }
231
232 - (web::NavigationItemImpl*)visibleItem {
233 return self.visibleEntry.navigationItemImpl;
234 }
235
236 - (web::NavigationItemImpl*)pendingItem {
237 return self.pendingEntry.navigationItemImpl;
238 }
239
240 - (web::NavigationItemImpl*)transientItem {
241 return self.transientEntry.navigationItemImpl;
242 }
243
244 - (web::NavigationItemImpl*)lastCommittedItem {
245 return self.lastCommittedEntry.navigationItemImpl;
246 }
247
248 - (web::NavigationItemImpl*)previousItem {
249 return self.previousEntry.navigationItemImpl;
250 }
251
252 - (web::NavigationItemImpl*)lastUserItem {
253 return self.lastUserEntry.navigationItemImpl;
254 }
255
256 - (web::NavigationItemList)backwardItems {
257 return [self itemListForEntryList:self.backwardEntries];
258 }
259
260 - (web::NavigationItemList)forwardItems {
261 return [self itemListForEntryList:self.forwardEntries];
262 }
263
264 // Returns the current entry in the session list, or the pending entry if there
265 // is a navigation in progress.
266 - (CRWSessionEntry*)currentEntry {
267 if (_transientEntry)
268 return _transientEntry.get();
269 if (_pendingEntry)
270 return _pendingEntry.get();
271 return [self lastCommittedEntry];
272 }
273
274 // See NavigationController::GetVisibleEntry for the motivation for this
275 // distinction.
276 - (CRWSessionEntry*)visibleEntry {
277 if (_transientEntry)
278 return _transientEntry.get();
279 // Only return the pending_entry for new (non-history), browser-initiated
280 // navigations in order to prevent URL spoof attacks.
281 web::NavigationItemImpl* pendingItem = [_pendingEntry navigationItemImpl];
282
283 if (pendingItem) {
284 bool isUserInitiated = pendingItem->NavigationInitiationType() ==
285 web::NavigationInitiationType::USER_INITIATED;
286 bool safeToShowPending = isUserInitiated && _pendingItemIndex == -1;
287
288 if (safeToShowPending)
289 return _pendingEntry.get();
290 }
291
292 return [self lastCommittedEntry];
293 }
294
295 - (CRWSessionEntry*)pendingEntry {
296 return _pendingEntry.get();
297 }
298
299 - (CRWSessionEntry*)transientEntry {
300 return _transientEntry.get();
301 }
302
303 - (CRWSessionEntry*)lastCommittedEntry {
304 if (_currentNavigationIndex == -1)
305 return nil;
306 return [_entries objectAtIndex:_currentNavigationIndex];
307 }
308
309 // Returns the previous entry in the session list, or nil if there isn't any.
310 - (CRWSessionEntry*)previousEntry {
311 if ((_previousNavigationIndex < 0) || (![_entries count]))
312 return nil;
313 return [_entries objectAtIndex:_previousNavigationIndex];
314 }
315
316 - (void)addPendingItem:(const GURL&)url 317 - (void)addPendingItem:(const GURL&)url
317 referrer:(const web::Referrer&)ref 318 referrer:(const web::Referrer&)ref
318 transition:(ui::PageTransition)trans 319 transition:(ui::PageTransition)trans
319 initiationType:(web::NavigationInitiationType)initiationType { 320 initiationType:(web::NavigationInitiationType)initiationType {
320 [self discardTransientItem]; 321 [self discardTransientItem];
321 _pendingItemIndex = -1; 322 self.pendingItemIndex = -1;
322 323
323 // Don't create a new entry if it's already the same as the current entry, 324 // Don't create a new item if it's already the same as the current item,
324 // allowing this routine to be called multiple times in a row without issue. 325 // allowing this routine to be called multiple times in a row without issue.
325 // Note: CRWSessionController currently has the responsibility to distinguish 326 // Note: CRWSessionController currently has the responsibility to distinguish
326 // between new navigations and history stack navigation, hence the inclusion 327 // between new navigations and history stack navigation, hence the inclusion
327 // of specific transiton type logic here, in order to make it reliable with 328 // of specific transiton type logic here, in order to make it reliable with
328 // real-world observed behavior. 329 // real-world observed behavior.
329 // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere 330 // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere
330 // in the web layer so that this hack can be removed. 331 // in the web layer so that this hack can be removed.
331 // Remove the workaround code from -presentSafeBrowsingWarningForResource:. 332 // Remove the workaround code from -presentSafeBrowsingWarningForResource:.
332 CRWSessionEntry* currentEntry = self.currentEntry; 333 web::NavigationItemImpl* currentItem = self.currentItem;
333 if (currentEntry) { 334 if (currentItem) {
334 web::NavigationItem* item = [currentEntry navigationItem]; 335 BOOL hasSameURL = currentItem->GetURL() == url;
335
336 BOOL hasSameURL = item->GetURL() == url;
337 BOOL isPendingTransitionFormSubmit = 336 BOOL isPendingTransitionFormSubmit =
338 PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT); 337 PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT);
339 BOOL isCurrentTransitionFormSubmit = PageTransitionCoreTypeIs( 338 BOOL isCurrentTransitionFormSubmit = PageTransitionCoreTypeIs(
340 item->GetTransitionType(), ui::PAGE_TRANSITION_FORM_SUBMIT); 339 currentItem->GetTransitionType(), ui::PAGE_TRANSITION_FORM_SUBMIT);
341 BOOL shouldCreatePendingItem = 340 BOOL shouldCreatePendingItem =
342 !hasSameURL || 341 !hasSameURL ||
343 (isPendingTransitionFormSubmit && !isCurrentTransitionFormSubmit); 342 (isPendingTransitionFormSubmit && !isCurrentTransitionFormSubmit);
344 343
345 if (!shouldCreatePendingItem) { 344 if (!shouldCreatePendingItem) {
346 // Send the notification anyway, to preserve old behavior. It's unknown 345 // Send the notification anyway, to preserve old behavior. It's unknown
347 // whether anything currently relies on this, but since both this whole 346 // whether anything currently relies on this, but since both this whole
348 // hack and the content facade will both be going away, it's not worth 347 // hack and the content facade will both be going away, it's not worth
349 // trying to unwind. 348 // trying to unwind.
350 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 349 if (_navigationManager && _navigationManager->GetFacadeDelegate())
351 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 350 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
352 }
353 return; 351 return;
354 } 352 }
355 } 353 }
356 354
357 _pendingEntry.reset([self sessionEntryWithURL:url 355 _pendingItem = [self itemWithURL:url
358 referrer:ref 356 referrer:ref
359 transition:trans 357 transition:trans
360 initiationType:initiationType]); 358 initiationType:initiationType];
361 359
362 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 360 if (_navigationManager && _navigationManager->GetFacadeDelegate())
363 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 361 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
364 }
365 } 362 }
366 363
367 - (void)updatePendingItem:(const GURL&)url { 364 - (void)updatePendingItem:(const GURL&)url {
368 // If there is no pending entry, navigation is probably happening within the 365 // If there is no pending item, navigation is probably happening within the
369 // session history. Don't modify the entry list. 366 // session history. Don't modify the item list.
370 if (!_pendingEntry) 367 web::NavigationItemImpl* item = self.pendingItem;
368 if (!item)
371 return; 369 return;
372 370
373 web::NavigationItemImpl* item = [_pendingEntry navigationItemImpl];
374 if (url != item->GetURL()) { 371 if (url != item->GetURL()) {
375 // Assume a redirection, and discard any transient entry. 372 // Assume a redirection, and discard any transient item.
376 // TODO(stuartmorgan): Once the current safe browsing code is gone, 373 // TODO(stuartmorgan): Once the current safe browsing code is gone,
377 // consider making this a DCHECK that there's no transient entry. 374 // consider making this a DCHECK that there's no transient item.
378 [self discardTransientItem]; 375 [self discardTransientItem];
379 376
380 item->SetURL(url); 377 item->SetURL(url);
381 item->SetVirtualURL(url); 378 item->SetVirtualURL(url);
382 // Redirects (3xx response code), or client side navigation must change 379 // Redirects (3xx response code), or client side navigation must change
383 // POST requests to GETs. 380 // POST requests to GETs.
384 item->SetPostData(nil); 381 item->SetPostData(nil);
385 item->ResetHttpRequestHeaders(); 382 item->ResetHttpRequestHeaders();
386 } 383 }
387 384
388 // This should probably not be sent if the URLs matched, but that's what was 385 // This should probably not be sent if the URLs matched, but that's what was
389 // done before, so preserve behavior in case something relies on it. 386 // done before, so preserve behavior in case something relies on it.
390 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 387 if (_navigationManager && _navigationManager->GetFacadeDelegate())
391 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 388 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
392 }
393 } 389 }
394 390
395 - (void)clearForwardItems { 391 - (void)clearForwardItems {
396 DCHECK_EQ(_pendingItemIndex, -1); 392 DCHECK_EQ(self.pendingItemIndex, -1);
397 [self discardTransientItem]; 393 [self discardTransientItem];
398 394
399 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1; 395 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1;
400 DCHECK(forwardItemStartIndex >= 0); 396 DCHECK(forwardItemStartIndex >= 0);
401 397
402 if (forwardItemStartIndex >= static_cast<NSInteger>([_entries count])) 398 size_t itemCount = self.items.size();
399 if (forwardItemStartIndex >= static_cast<NSInteger>(itemCount))
403 return; 400 return;
404 401
405 NSRange remove = NSMakeRange(forwardItemStartIndex,
406 [_entries count] - forwardItemStartIndex);
407 // Store removed items in temporary NSArray so they can be deallocated after
408 // their facades.
409 base::scoped_nsobject<NSArray> removedItems(
410 [_entries subarrayWithRange:remove]);
411 [_entries removeObjectsInRange:remove];
412 if (_previousNavigationIndex >= forwardItemStartIndex) 402 if (_previousNavigationIndex >= forwardItemStartIndex)
413 _previousNavigationIndex = -1; 403 _previousNavigationIndex = -1;
404
405 // Remove the NavigationItems and notify the NavigationManater
406 _items.erase(_items.begin() + forwardItemStartIndex, _items.end());
414 if (_navigationManager) { 407 if (_navigationManager) {
415 _navigationManager->OnNavigationItemsPruned(remove.length); 408 _navigationManager->OnNavigationItemsPruned(itemCount -
409 forwardItemStartIndex);
416 } 410 }
417 } 411 }
418 412
419 - (void)commitPendingItem { 413 - (void)commitPendingItem {
420 if (_pendingEntry) { 414 if (self.pendingItem) {
421 NSInteger newNavigationIndex = _pendingItemIndex; 415 // Once an item is committed it's not renderer-initiated any more. (Matches
422 if (_pendingItemIndex == -1) { 416 // the implementation in NavigationController.)
417 self.pendingItem->ResetForCommit();
418
419 NSInteger newNavigationIndex = self.pendingItemIndex;
420 if (newNavigationIndex == -1) {
423 [self clearForwardItems]; 421 [self clearForwardItems];
424 // Add the new entry at the end. 422 // Add the new item at the end.
425 [_entries addObject:_pendingEntry]; 423 _items.push_back(std::move(_pendingItem));
426 newNavigationIndex = [_entries count] - 1; 424 newNavigationIndex = self.items.size() - 1;
427 } 425 }
428 _previousNavigationIndex = _currentNavigationIndex; 426 _previousNavigationIndex = _currentNavigationIndex;
429 self.currentNavigationIndex = newNavigationIndex; 427 self.currentNavigationIndex = newNavigationIndex;
430 // Once an entry is committed it's not renderer-initiated any more. (Matches 428 self.pendingItemIndex = -1;
431 // the implementation in NavigationController.) 429 DCHECK(!_pendingItem);
432 [_pendingEntry navigationItemImpl]->ResetForCommit();
433 _pendingEntry.reset();
434 _pendingItemIndex = -1;
435 } 430 }
436 431
437 CRWSessionEntry* currentEntry = self.currentEntry; 432 web::NavigationItem* item = self.currentItem;
438 web::NavigationItem* item = currentEntry.navigationItem;
439 // Update the navigation timestamp now that it's actually happened. 433 // Update the navigation timestamp now that it's actually happened.
440 if (item) 434 if (item)
441 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now())); 435 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now()));
442 436
443 if (_navigationManager && item) 437 if (_navigationManager && item)
444 _navigationManager->OnNavigationItemCommitted(); 438 _navigationManager->OnNavigationItemCommitted();
445 DCHECK_EQ(_pendingItemIndex, -1); 439 DCHECK_EQ(self.pendingItemIndex, -1);
446 } 440 }
447 441
448 - (void)addTransientItemWithURL:(const GURL&)URL { 442 - (void)addTransientItemWithURL:(const GURL&)URL {
449 _transientEntry.reset([self 443 _transientItem =
450 sessionEntryWithURL:URL 444 [self itemWithURL:URL
451 referrer:web::Referrer() 445 referrer:web::Referrer()
452 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT 446 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
453 initiationType:web::NavigationInitiationType::USER_INITIATED]); 447 initiationType:web::NavigationInitiationType::USER_INITIATED];
454 448 _transientItem->SetTimestamp(
455 web::NavigationItem* navigationItem = [_transientEntry navigationItem];
456 DCHECK(navigationItem);
457 navigationItem->SetTimestamp(
458 _timeSmoother.GetSmoothedTime(base::Time::Now())); 449 _timeSmoother.GetSmoothedTime(base::Time::Now()));
459 } 450 }
460 451
461 - (void)pushNewItemWithURL:(const GURL&)URL 452 - (void)pushNewItemWithURL:(const GURL&)URL
462 stateObject:(NSString*)stateObject 453 stateObject:(NSString*)stateObject
463 transition:(ui::PageTransition)transition { 454 transition:(ui::PageTransition)transition {
464 DCHECK(![self pendingEntry]); 455 DCHECK(!self.pendingItem);
465 DCHECK([self currentEntry]); 456 DCHECK(self.currentItem);
466 457
467 web::NavigationItem* lastCommittedItem = 458 web::NavigationItem* lastCommittedItem = self.lastCommittedItem;
468 self.lastCommittedEntry.navigationItem;
469 CHECK(web::history_state_util::IsHistoryStateChangeValid( 459 CHECK(web::history_state_util::IsHistoryStateChangeValid(
470 lastCommittedItem->GetURL(), URL)); 460 lastCommittedItem->GetURL(), URL));
471 461
472 web::Referrer referrer(lastCommittedItem->GetURL(), 462 web::Referrer referrer(lastCommittedItem->GetURL(),
473 web::ReferrerPolicyDefault); 463 web::ReferrerPolicyDefault);
474 base::scoped_nsobject<CRWSessionEntry> pushedEntry([self 464 std::unique_ptr<web::NavigationItemImpl> pushedItem =
475 sessionEntryWithURL:URL 465 [self itemWithURL:URL
476 referrer:referrer 466 referrer:referrer
477 transition:transition 467 transition:transition
478 initiationType:web::NavigationInitiationType::USER_INITIATED]); 468 initiationType:web::NavigationInitiationType::USER_INITIATED];
479
480 web::NavigationItemImpl* pushedItem = [pushedEntry navigationItemImpl];
481 pushedItem->SetUserAgentType(lastCommittedItem->GetUserAgentType()); 469 pushedItem->SetUserAgentType(lastCommittedItem->GetUserAgentType());
482 pushedItem->SetSerializedStateObject(stateObject); 470 pushedItem->SetSerializedStateObject(stateObject);
483 pushedItem->SetIsCreatedFromPushState(true); 471 pushedItem->SetIsCreatedFromPushState(true);
484 pushedItem->GetSSL() = lastCommittedItem->GetSSL(); 472 pushedItem->GetSSL() = lastCommittedItem->GetSSL();
485 pushedItem->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now())); 473 pushedItem->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now()));
486 474
487 [self clearForwardItems]; 475 [self clearForwardItems];
488 // Add the new entry at the end. 476 // Add the new item at the end.
489 [_entries addObject:pushedEntry]; 477 _items.push_back(std::move(pushedItem));
490 _previousNavigationIndex = _currentNavigationIndex; 478 _previousNavigationIndex = _currentNavigationIndex;
491 self.currentNavigationIndex = [_entries count] - 1; 479 self.currentNavigationIndex = self.items.size() - 1;
492 480
493 if (_navigationManager) 481 if (_navigationManager)
494 _navigationManager->OnNavigationItemCommitted(); 482 _navigationManager->OnNavigationItemCommitted();
495 } 483 }
496 484
497 - (void)updateCurrentItemWithURL:(const GURL&)url 485 - (void)updateCurrentItemWithURL:(const GURL&)url
498 stateObject:(NSString*)stateObject { 486 stateObject:(NSString*)stateObject {
499 DCHECK(!_transientEntry); 487 DCHECK(!self.transientItem);
500 CRWSessionEntry* currentEntry = self.currentEntry; 488 web::NavigationItemImpl* currentItem = self.currentItem;
501 web::NavigationItemImpl* currentItem = self.currentEntry.navigationItemImpl;
502 currentItem->SetURL(url); 489 currentItem->SetURL(url);
503 currentItem->SetSerializedStateObject(stateObject); 490 currentItem->SetSerializedStateObject(stateObject);
504 currentItem->SetHasStateBeenReplaced(true); 491 currentItem->SetHasStateBeenReplaced(true);
505 currentItem->SetPostData(nil); 492 currentItem->SetPostData(nil);
506 currentEntry.navigationItem->SetURL(url); 493 // If the change is to a committed item, notify interested parties.
507 // If the change is to a committed entry, notify interested parties. 494 if (currentItem != self.pendingItem && _navigationManager)
508 if (currentEntry != self.pendingEntry && _navigationManager)
509 _navigationManager->OnNavigationItemChanged(); 495 _navigationManager->OnNavigationItemChanged();
510 } 496 }
511 497
512 - (void)discardNonCommittedItems { 498 - (void)discardNonCommittedItems {
513 [self discardTransientItem]; 499 [self discardTransientItem];
514 _pendingEntry.reset(); 500 _pendingItem.reset();
515 _pendingItemIndex = -1; 501 self.pendingItemIndex = -1;
516 } 502 }
517 503
518 - (void)discardTransientItem { 504 - (void)discardTransientItem {
519 // Keep the entry alive temporarily. There are flows that get the current 505 _transientItem.reset();
520 // entry, do some navigation operation, and then try to use that old current
521 // entry; since navigations clear the transient entry, these flows might
522 // crash. (This should be removable once more session management is handled
523 // within this class and/or NavigationManager).
524 _transientEntry.reset();
525 } 506 }
526 507
527 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession { 508 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession {
528 DCHECK(sourceSession); 509 DCHECK(sourceSession);
529 // The other session may not have any entries, in which case there is nothing 510
530 // to insert. The other session's currentNavigationEntry will be bogus 511 // The other session may not have any items, in which case there is nothing
531 // in such cases, so ignore it and return early. 512 // to insert. The other session's currentItem will be bogus in such cases, so
532 NSArray* sourceEntries = sourceSession.entries; 513 // ignore it and return early.
533 if (!sourceEntries.count) 514 web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items;
515 if (sourceItems.empty())
534 return; 516 return;
535 517
536 // Cycle through the entries from the other session and insert them before any 518 // Cycle through the items from the other session and insert them before any
537 // entries from this session. Do not copy anything that comes after the other 519 // items from this session. Do not copy anything that comes after the other
538 // session's current entry. 520 // session's current item.
539 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex; 521 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex;
540 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) { 522 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) {
541 [_entries insertObject:sourceEntries[i] atIndex:i]; 523 std::unique_ptr<web::NavigationItemImpl> sourceItemCopy =
524 base::MakeUnique<web::NavigationItemImpl>(*sourceItems[i]);
525 _items.insert(_items.begin() + i, std::move(sourceItemCopy));
542 } 526 }
543 527
528 // Update state to reflect inserted NavigationItems.
544 _previousNavigationIndex = -1; 529 _previousNavigationIndex = -1;
545 _currentNavigationIndex += lastIndexToCopy + 1; 530 _currentNavigationIndex += lastIndexToCopy + 1;
546 if (_pendingItemIndex != -1) 531 if (self.pendingItemIndex != -1)
547 _pendingItemIndex += lastIndexToCopy + 1; 532 self.pendingItemIndex += lastIndexToCopy + 1;
548 533
549 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), _entries.count); 534 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex),
550 DCHECK(_pendingItemIndex == -1 || _pendingEntry); 535 self.items.size());
536 DCHECK(self.pendingItemIndex == -1 || self.pendingItem);
551 } 537 }
552 538
553 - (void)goToItemAtIndex:(NSInteger)index { 539 - (void)goToItemAtIndex:(NSInteger)index {
554 if (index < 0 || static_cast<NSUInteger>(index) >= _entries.count) 540 if (index < 0 || static_cast<NSUInteger>(index) >= self.items.size())
555 return; 541 return;
556 542
557 if (index < _currentNavigationIndex) { 543 if (index < _currentNavigationIndex) {
558 // Going back. 544 // Going back.
559 [self discardNonCommittedItems]; 545 [self discardNonCommittedItems];
560 } else if (_currentNavigationIndex < index) { 546 } else if (_currentNavigationIndex < index) {
561 // Going forward. 547 // Going forward.
562 [self discardTransientItem]; 548 [self discardTransientItem];
563 } else { 549 } else {
564 // |delta| is 0, no need to change current navigation index. 550 // |delta| is 0, no need to change current navigation index.
565 return; 551 return;
566 } 552 }
567 553
568 _previousNavigationIndex = _currentNavigationIndex; 554 _previousNavigationIndex = _currentNavigationIndex;
569 _currentNavigationIndex = index; 555 _currentNavigationIndex = index;
570 } 556 }
571 557
572 - (void)removeItemAtIndex:(NSInteger)index { 558 - (void)removeItemAtIndex:(NSInteger)index {
573 DCHECK(index < static_cast<NSInteger>([_entries count])); 559 DCHECK(index < static_cast<NSInteger>(self.items.size()));
574 DCHECK(index != _currentNavigationIndex); 560 DCHECK(index != _currentNavigationIndex);
575 DCHECK(index >= 0); 561 DCHECK(index >= 0);
576 562
577 [self discardNonCommittedItems]; 563 [self discardNonCommittedItems];
578 564
579 [_entries removeObjectAtIndex:index]; 565 _items.erase(_items.begin() + index);
580 if (_currentNavigationIndex > index) 566 if (_currentNavigationIndex > index)
581 _currentNavigationIndex--; 567 _currentNavigationIndex--;
582 if (_previousNavigationIndex >= index) 568 if (_previousNavigationIndex >= index)
583 _previousNavigationIndex--; 569 _previousNavigationIndex--;
584 } 570 }
585 571
586 - (NSArray*)backwardEntries {
587 NSMutableArray* entries = [NSMutableArray array];
588 for (NSInteger index = _currentNavigationIndex; index > 0; --index) {
589 if (![self isRedirectTransitionForItemAtIndex:index])
590 [entries addObject:_entries[index - 1]];
591 }
592 return entries;
593 }
594
595 - (NSArray*)forwardEntries {
596 NSMutableArray* entries = [NSMutableArray array];
597 NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
598 while (lastNonRedirectedIndex < [_entries count]) {
599 CRWSessionEntry* entry = [_entries objectAtIndex:lastNonRedirectedIndex];
600 if (!ui::PageTransitionIsRedirect(
601 entry.navigationItem->GetTransitionType())) {
602 [entries addObject:entry];
603 }
604 ++lastNonRedirectedIndex;
605 }
606 return entries;
607 }
608
609 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem 572 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem
610 andItem:(web::NavigationItem*)secondItem { 573 andItem:(web::NavigationItem*)secondItem {
611 if (!firstItem || !secondItem || firstItem == secondItem) 574 if (!firstItem || !secondItem || firstItem == secondItem)
612 return NO; 575 return NO;
613 NSUInteger firstIndex = [self indexOfItem:firstItem]; 576 NSUInteger firstIndex = [self indexOfItem:firstItem];
614 NSUInteger secondIndex = [self indexOfItem:secondItem]; 577 NSUInteger secondIndex = [self indexOfItem:secondItem];
615 if (firstIndex == NSNotFound || secondIndex == NSNotFound) 578 if (firstIndex == NSNotFound || secondIndex == NSNotFound)
616 return NO; 579 return NO;
617 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex; 580 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex;
618 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex; 581 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
619 582
620 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) { 583 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) {
621 web::NavigationItemImpl* item = [_entries[i] navigationItemImpl]; 584 web::NavigationItemImpl* item = self.items[i].get();
622 // Every entry in the sequence has to be created from a hash change or 585 // Every item in the sequence has to be created from a hash change or
623 // pushState() call. 586 // pushState() call.
624 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange()) 587 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange())
625 return NO; 588 return NO;
626 // Every entry in the sequence has to have a URL that could have been 589 // Every item in the sequence has to have a URL that could have been
627 // created from a pushState() call. 590 // created from a pushState() call.
628 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(), 591 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(),
629 item->GetURL())) 592 item->GetURL()))
630 return NO; 593 return NO;
631 } 594 }
632 return YES; 595 return YES;
633 } 596 }
634 597
635 - (CRWSessionEntry*)lastUserEntry {
636 if (![_entries count])
637 return nil;
638
639 NSInteger index = _currentNavigationIndex;
640 // This will return the first session entry if all other entries are
641 // redirects, regardless of the transition state of the first entry.
642 while (index > 0 && [self isRedirectTransitionForItemAtIndex:index]) {
643 --index;
644 }
645 return [_entries objectAtIndex:index];
646 }
647
648 - (NSInteger)indexOfItem:(const web::NavigationItem*)item { 598 - (NSInteger)indexOfItem:(const web::NavigationItem*)item {
649 for (NSUInteger index = 0; index < self.entries.count; ++index) { 599 DCHECK(item);
650 if ([self.entries[index] navigationItem] == item) 600 for (size_t index = 0; index < self.items.size(); ++index) {
651 return static_cast<NSInteger>(index); 601 if (self.items[index].get() == item)
602 return index;
652 } 603 }
653 return NSNotFound; 604 return NSNotFound;
654 } 605 }
655 606
656 - (web::NavigationItemImpl*)itemAtIndex:(NSInteger)index { 607 - (web::NavigationItemImpl*)itemAtIndex:(NSInteger)index {
657 if (index < 0 || self.entries.count <= static_cast<NSUInteger>(index)) 608 if (index < 0 || self.items.size() <= static_cast<NSUInteger>(index))
658 return nullptr; 609 return nullptr;
659 return static_cast<web::NavigationItemImpl*>( 610 return self.items[index].get();
660 [self.entries[index] navigationItem]);
661 } 611 }
662 612
663 #pragma mark - 613 #pragma mark -
664 #pragma mark Private methods 614 #pragma mark Private methods
665 615
666 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url 616 - (std::unique_ptr<web::NavigationItemImpl>)
667 referrer:(const web::Referrer&)referrer 617 itemWithURL:(const GURL&)url
668 transition:(ui::PageTransition)transition 618 referrer:(const web::Referrer&)referrer
669 initiationType: 619 transition:(ui::PageTransition)transition
670 (web::NavigationInitiationType)initiationType { 620 initiationType:(web::NavigationInitiationType)initiationType {
671 GURL loaded_url(url); 621 GURL loaded_url(url);
672 BOOL urlWasRewritten = NO; 622 BOOL urlWasRewritten = NO;
673 if (_navigationManager) { 623 if (_navigationManager) {
674 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>> 624 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>>
675 transientRewriters = _navigationManager->GetTransientURLRewriters(); 625 transientRewriters = _navigationManager->GetTransientURLRewriters();
676 if (transientRewriters) { 626 if (transientRewriters) {
677 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters( 627 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters(
678 &loaded_url, _browserState, *transientRewriters.get()); 628 &loaded_url, _browserState, *transientRewriters.get());
679 } 629 }
680 } 630 }
681 if (!urlWasRewritten) { 631 if (!urlWasRewritten) {
682 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary( 632 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary(
683 &loaded_url, _browserState); 633 &loaded_url, _browserState);
684 } 634 }
685 635
686 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); 636 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl());
687 item->SetOriginalRequestURL(loaded_url); 637 item->SetOriginalRequestURL(loaded_url);
688 item->SetURL(loaded_url); 638 item->SetURL(loaded_url);
689 item->SetReferrer(referrer); 639 item->SetReferrer(referrer);
690 item->SetTransitionType(transition); 640 item->SetTransitionType(transition);
691 item->SetNavigationInitiationType(initiationType); 641 item->SetNavigationInitiationType(initiationType);
692 if (web::GetWebClient()->IsAppSpecificURL(loaded_url)) 642 if (web::GetWebClient()->IsAppSpecificURL(loaded_url))
693 item->SetUserAgentType(web::UserAgentType::NONE); 643 item->SetUserAgentType(web::UserAgentType::NONE);
694 return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]; 644 return item;
695 } 645 }
696 646
697 - (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index { 647 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index {
698 ui::PageTransition transition = 648 DCHECK_LT(index, self.items.size());
699 [_entries[index] navigationItem]->GetTransitionType(); 649 ui::PageTransition transition = self.items[index]->GetTransitionType();
700 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO; 650 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO;
701 } 651 }
702 652
703 - (web::NavigationItemList)itemListForEntryList:(NSArray*)entries {
704 web::NavigationItemList list(entries.count);
705 for (size_t index = 0; index < entries.count; ++index)
706 list[index] = [entries[index] navigationItem];
707 return list;
708 }
709
710 @end 653 @end
OLDNEW
« no previous file with comments | « ios/web/navigation/crw_session_controller.h ('k') | ios/web/navigation/crw_session_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698