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

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

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