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

Unified Diff: ios/web/navigation/crw_session_controller.mm

Issue 2672723003: Converted CRWSessionController to use NavigationItems. (Closed)
Patch Set: test fixes, self review Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: ios/web/navigation/crw_session_controller.mm
diff --git a/ios/web/navigation/crw_session_controller.mm b/ios/web/navigation/crw_session_controller.mm
index bc03108a4936197276c2be68fbb8f7273fa23784..3f1a8ab64b3ee34a755cd491618bd284758d20df 100644
--- a/ios/web/navigation/crw_session_controller.mm
+++ b/ios/web/navigation/crw_session_controller.mm
@@ -7,8 +7,8 @@
#include <stddef.h>
#include <algorithm>
+#include <map>
#include <utility>
-#include <vector>
#include "base/format_macros.h"
#include "base/logging.h"
@@ -32,6 +32,10 @@
#error "This file requires ARC support."
#endif
+typedef std::map<web::NavigationItemImpl*,
+ base::scoped_nsobject<CRWSessionEntry>>
+ SessionEntryMap;
+
@interface CRWSessionController () {
// Weak pointer back to the owning NavigationManager. This is to facilitate
// the incremental merging of the two classes.
@@ -49,21 +53,6 @@ @interface CRWSessionController () {
// Identifies the index of the previous navigation in the CRWSessionEntry
// array.
NSInteger _previousNavigationIndex;
- // Ordered array of |CRWSessionEntry| objects, one for each site in session
- // history. End of the list is the most recent load.
- NSMutableArray* _entries;
-
- // An entry we haven't gotten a response for yet. This will be discarded
- // when we navigate again. It's used only so we know what the currently
- // displayed tab is. It backs the property of the same name and should only
- // be set through its setter.
- base::scoped_nsobject<CRWSessionEntry> _pendingEntry;
-
- // The transient entry, if any. A transient entry is discarded on any
- // navigation, and is used for representing interstitials that need to be
- // represented in the session. It backs the property of the same name and
- // should only be set through its setter.
- base::scoped_nsobject<CRWSessionEntry> _transientEntry;
// The window name associated with the session.
NSString* _windowName;
@@ -76,15 +65,22 @@ @interface CRWSessionController () {
NSTimeInterval _lastVisitedTimestamp;
// If |YES|, override |currentEntry.useDesktopUserAgent| and create the
- // pending entry using the desktop user agent.
- BOOL _useDesktopUserAgentForNextPendingEntry;
+ // pending item using the desktop user agent.
+ BOOL _useDesktopUserAgentForNextPendingItem;
// The browser state associated with this CRWSessionController;
web::BrowserState* _browserState; // weak
- // Time smoother for navigation entry timestamps; see comment in
+ // Time smoother for navigation item timestamps; see comment in
// navigation_controller_impl.h
web::TimeSmoother _timeSmoother;
+
+ // Backing objects for properties of the same name.
+ web::ScopedNavigationItemImplList _items;
+ NSMutableArray* _entries;
+ std::unique_ptr<web::NavigationItemImpl> _pendingItem;
+ std::unique_ptr<web::NavigationItemImpl> _transientItem;
+ SessionEntryMap _sessionEntryMap;
}
// Redefine as readwrite.
@@ -105,20 +101,32 @@ @interface CRWSessionController () {
@property(nonatomic, readwrite, assign) NSInteger openerNavigationIndex;
@property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex;
+// The map associating NavigationItemImpls with CRWSessionEntries. This is a
+// temporary fix, and will be removed once clients of this class have been
+// updated to use NavigationItems rather than CRWSessionEntries.
+@property(nonatomic, readonly) SessionEntryMap& sessionEntryMap;
+
- (NSString*)uniqueID;
-// Removes all entries after currentNavigationIndex_.
-- (void)clearForwardEntries;
-// Discards the transient entry, if any.
-- (void)discardTransientEntry;
-// Create a new autoreleased session entry.
-- (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url
- referrer:(const web::Referrer&)referrer
- transition:(ui::PageTransition)transition
- useDesktopUserAgent:(BOOL)useDesktopUserAgent
- rendererInitiated:(BOOL)rendererInitiated;
+// Removes all items after currentNavigationIndex_.
+- (void)clearForwardItems;
+// Discards the transient item, if any.
+- (void)discardTransientItem;
+// Creates a NavigationItemImpl with the specified properties.
+- (std::unique_ptr<web::NavigationItemImpl>)
+ itemWithURL:(const GURL&)url
+ referrer:(const web::Referrer&)referrer
+ transition:(ui::PageTransition)transition
+useDesktopUserAgent:(BOOL)useDesktopUserAgent
+ rendererInitiated:(BOOL)rendererInitiated;
// Returns YES if the PageTransition for the underlying navigationItem at
-// |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
-- (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index;
+// |index| in |items| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
+- (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index;
+// Returns the CRWSessionEntry corresponding with |item|.
+- (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item;
+// Returns an autoreleased NSArray containing CRWSessionEntries corresponding
+// with the NavigationItems in |itemList|.
+- (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList;
+
@end
@implementation CRWSessionController
@@ -126,7 +134,7 @@ @implementation CRWSessionController
@synthesize tabId = _tabId;
@synthesize currentNavigationIndex = _currentNavigationIndex;
@synthesize previousNavigationIndex = _previousNavigationIndex;
-@synthesize pendingEntryIndex = _pendingEntryIndex;
+@synthesize pendingItemIndex = _pendingItemIndex;
@synthesize entries = _entries;
@synthesize windowName = _windowName;
@synthesize lastVisitedTimestamp = _lastVisitedTimestamp;
@@ -152,15 +160,14 @@ - (id)initWithWindowName:(NSString*)windowName
_lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
_currentNavigationIndex = -1;
_previousNavigationIndex = -1;
- _pendingEntryIndex = -1;
+ _pendingItemIndex = -1;
_sessionCertificatePolicyManager =
[[CRWSessionCertificatePolicyManager alloc] init];
}
return self;
}
-- (id)initWithNavigationItems:
- (std::vector<std::unique_ptr<web::NavigationItem>>)items
+- (id)initWithNavigationItems:(web::ScopedNavigationItemList)items
currentIndex:(NSUInteger)currentIndex
browserState:(web::BrowserState*)browserState {
self = [super init];
@@ -168,24 +175,17 @@ - (id)initWithNavigationItems:
_tabId = [[self uniqueID] copy];
_openerId = nil;
_browserState = browserState;
-
- // Create entries array from list of navigations.
+ _items = web::CreateScopedNavigationItemImplList(std::move(items));
_entries = [[NSMutableArray alloc] initWithCapacity:items.size()];
-
- for (auto& item : items) {
- base::scoped_nsobject<CRWSessionEntry> entry(
- [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]);
- [_entries addObject:entry];
- }
+ for (auto& item : _items)
+ [_entries addObject:[self entryForItem:item.get()]];
self.currentNavigationIndex = currentIndex;
- // Prior to M34, 0 was used as "no index" instead of -1; adjust for that.
- if (![_entries count])
+ if (_items.empty())
self.currentNavigationIndex = -1;
- if (_currentNavigationIndex >= static_cast<NSInteger>(items.size())) {
- self.currentNavigationIndex = static_cast<NSInteger>(items.size()) - 1;
- }
+ _currentNavigationIndex = std::min(
+ _currentNavigationIndex, static_cast<NSInteger>(_items.size() - 1));
_previousNavigationIndex = -1;
- _pendingEntryIndex = -1;
+ _pendingItemIndex = -1;
_lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
_sessionCertificatePolicyManager =
[[CRWSessionCertificatePolicyManager alloc] init];
@@ -193,23 +193,7 @@ - (id)initWithNavigationItems:
return self;
}
-- (id)copyWithZone:(NSZone*)zone {
- CRWSessionController* copy = [[[self class] alloc] init];
- copy->_tabId = [_tabId copy];
- copy->_openerId = [_openerId copy];
- copy->_openedByDOM = _openedByDOM;
- copy->_openerNavigationIndex = _openerNavigationIndex;
- copy.windowName = self.windowName;
- copy->_currentNavigationIndex = _currentNavigationIndex;
- copy->_previousNavigationIndex = _previousNavigationIndex;
- copy->_pendingEntryIndex = _pendingEntryIndex;
- copy->_lastVisitedTimestamp = _lastVisitedTimestamp;
- copy->_entries =
- [[NSMutableArray alloc] initWithArray:_entries copyItems:YES];
- copy->_sessionCertificatePolicyManager =
- [_sessionCertificatePolicyManager copy];
- return copy;
-}
+#pragma mark - Accessors
- (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
if (_currentNavigationIndex != currentNavigationIndex) {
@@ -219,95 +203,209 @@ - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
}
}
-- (void)setPendingEntryIndex:(NSInteger)index {
- DCHECK_GE(index, -1);
- DCHECK_LT(index, static_cast<NSInteger>(_entries.count));
- _pendingEntryIndex = index;
- CRWSessionEntry* entry = index != -1 ? _entries[index] : nil;
- _pendingEntry.reset(entry);
- DCHECK(_pendingEntryIndex == -1 || _pendingEntry);
+- (void)setPendingItemIndex:(NSInteger)pendingItemIndex {
+ DCHECK_GE(pendingItemIndex, -1);
+ DCHECK_LT(pendingItemIndex, static_cast<NSInteger>(self.items.size()));
+ _pendingItemIndex = pendingItemIndex;
+ DCHECK(_pendingItemIndex == -1 || self.pendingItem);
}
-- (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager {
- _navigationManager = navigationManager;
- if (_navigationManager) {
- // _browserState will be nullptr if CRWSessionController has been
- // initialized with -initWithCoder: method. Take _browserState from
- // NavigationManagerImpl if that's the case.
- if (!_browserState) {
- _browserState = _navigationManager->GetBrowserState();
- }
- DCHECK_EQ(_browserState, _navigationManager->GetBrowserState());
+- (const web::ScopedNavigationItemImplList&)items {
+ return _items;
+}
+
+- (web::NavigationItemImpl*)currentItem {
+ if (self.transientItem)
+ return self.transientItem;
+ if (self.pendingItem)
+ return self.pendingItem;
+ return self.lastCommittedItem;
+}
+
+- (web::NavigationItemImpl*)visibleItem {
+ if (self.transientItem)
+ return self.transientItem;
+ // Only return the |pendingItem| for new (non-history), browser-initiated
+ // navigations in order to prevent URL spoof attacks.
+ web::NavigationItemImpl* pendingItem = self.pendingItem;
+ bool safeToShowPending = pendingItem &&
+ !pendingItem->is_renderer_initiated() &&
+ _pendingItemIndex == -1;
+ if (safeToShowPending)
+ return pendingItem;
+ return self.lastCommittedItem;
+}
+
+- (web::NavigationItemImpl*)pendingItem {
+ if (self.pendingItemIndex == -1)
+ return _pendingItem.get();
+ return self.items[self.pendingItemIndex].get();
+}
+
+- (web::NavigationItemImpl*)transientItem {
+ return _transientItem.get();
+}
+
+- (web::NavigationItemImpl*)lastCommittedItem {
+ NSInteger index = self.currentNavigationIndex;
+ return index == -1 ? nullptr : self.items[index].get();
+}
+
+- (web::NavigationItemImpl*)previousItem {
+ NSInteger index = self.previousNavigationIndex;
+ return index == -1 || self.items.empty() ? nullptr : self.items[index].get();
+}
+
+- (web::NavigationItemImpl*)lastUserItem {
+ if (self.items.empty())
+ return nil;
+
+ NSInteger index = self.currentNavigationIndex;
+ // This will return the first NavigationItem if all other items are
+ // redirects, regardless of the transition state of the first item.
+ while (index > 0 && [self isRedirectTransitionForItemAtIndex:index])
+ --index;
+
+ return self.items[index].get();
+}
+
+- (web::NavigationItemList)backwardItems {
+ web::NavigationItemList items;
+ for (size_t index = _currentNavigationIndex; index > 0; --index) {
+ if (![self isRedirectTransitionForItemAtIndex:index])
+ items.push_back(self.items[index - 1].get());
}
+ return items;
}
-- (NSString*)description {
- return [NSString
- stringWithFormat:
- @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS
- @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS
- @"\n%@\npending: %@\ntransient: %@\n",
- _tabId, self.windowName, _lastVisitedTimestamp,
- _currentNavigationIndex, _previousNavigationIndex, _pendingEntryIndex,
- _entries, _pendingEntry.get(), _transientEntry.get()];
+- (web::NavigationItemList)forwardItems {
+ web::NavigationItemList items;
+ NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
+ while (lastNonRedirectedIndex < self.items.size()) {
+ web::NavigationItem* item = self.items[lastNonRedirectedIndex].get();
+ if (!ui::PageTransitionIsRedirect(item->GetTransitionType()))
+ items.push_back(item);
+ ++lastNonRedirectedIndex;
+ }
+ return items;
}
-// Returns the current entry in the session list, or the pending entry if there
-// is a navigation in progress.
+- (SessionEntryMap&)sessionEntryMap {
+ return _sessionEntryMap;
+}
+
+// DEPRECATED
- (CRWSessionEntry*)currentEntry {
- if (_transientEntry)
- return _transientEntry.get();
- if (_pendingEntry)
- return _pendingEntry.get();
- return [self lastCommittedEntry];
+ return [self entryForItem:self.currentItem];
}
-// See NavigationController::GetVisibleEntry for the motivation for this
-// distinction.
+// DEPRECATED
- (CRWSessionEntry*)visibleEntry {
- if (_transientEntry)
- return _transientEntry.get();
- // Only return the pending_entry for new (non-history), browser-initiated
- // navigations in order to prevent URL spoof attacks.
- web::NavigationItemImpl* pendingItem = [_pendingEntry navigationItemImpl];
- bool safeToShowPending = pendingItem &&
- !pendingItem->is_renderer_initiated() &&
- _pendingEntryIndex == -1;
- if (safeToShowPending) {
- return _pendingEntry.get();
- }
- return [self lastCommittedEntry];
+ return [self entryForItem:self.visibleItem];
}
+// DEPRECATED
- (CRWSessionEntry*)pendingEntry {
- return _pendingEntry.get();
+ return [self entryForItem:self.pendingItem];
}
+// DEPRECATED
- (CRWSessionEntry*)transientEntry {
- return _transientEntry.get();
+ return [self entryForItem:self.transientItem];
}
+// DEPRECATED
- (CRWSessionEntry*)lastCommittedEntry {
- if (_currentNavigationIndex == -1)
- return nil;
- return [_entries objectAtIndex:_currentNavigationIndex];
+ return [self entryForItem:self.lastCommittedItem];
}
-// Returns the previous entry in the session list, or nil if there isn't any.
+// DEPRECATED
- (CRWSessionEntry*)previousEntry {
- if ((_previousNavigationIndex < 0) || (![_entries count]))
- return nil;
- return [_entries objectAtIndex:_previousNavigationIndex];
+ return [self entryForItem:self.previousItem];
+}
+
+// DEPRECATED
+- (CRWSessionEntry*)lastUserEntry {
+ return [self entryForItem:self.lastUserItem];
}
-- (void)addPendingEntry:(const GURL&)url
- referrer:(const web::Referrer&)ref
- transition:(ui::PageTransition)trans
- rendererInitiated:(BOOL)rendererInitiated {
- [self discardTransientEntry];
- _pendingEntryIndex = -1;
+// DEPRECATED
+- (NSArray*)backwardEntries {
+ return [self entryListForItemList:self.backwardItems];
+}
+
+// DEPRECATED
+- (NSArray*)forwardEntries {
+ return [self entryListForItemList:self.forwardItems];
+}
- // Don't create a new entry if it's already the same as the current entry,
+#pragma mark - NSObject
+
+- (NSString*)description {
+ return [NSString
+ stringWithFormat:
+ @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS
+ @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS
+ @"\n%@\npending: %@\ntransient: %@\n",
+ _tabId, self.windowName, _lastVisitedTimestamp,
+ _currentNavigationIndex, _previousNavigationIndex, _pendingItemIndex,
+ _entries, self.pendingEntry, self.transientEntry];
+}
+
+#pragma mark - NSCopying
+
+- (id)copyWithZone:(NSZone*)zone {
+ CRWSessionController* copy = [[[self class] alloc] init];
+ copy->_tabId = [_tabId copy];
+ copy->_openerId = [_openerId copy];
+ copy->_openedByDOM = _openedByDOM;
+ copy->_openerNavigationIndex = _openerNavigationIndex;
+ copy.windowName = self.windowName;
+ copy->_currentNavigationIndex = _currentNavigationIndex;
+ copy->_previousNavigationIndex = _previousNavigationIndex;
+ copy->_pendingItemIndex = _pendingItemIndex;
+ copy->_lastVisitedTimestamp = _lastVisitedTimestamp;
+ copy->_sessionCertificatePolicyManager =
+ [_sessionCertificatePolicyManager copy];
+ copy->_entries = [NSMutableArray array];
+ for (size_t index = 0; index < self.items.size(); ++index) {
+ std::unique_ptr<web::NavigationItemImpl> itemCopy(
+ new web::NavigationItemImpl(*self.items[index].get()));
+ copy->_items.push_back(std::move(itemCopy));
+ [copy->_entries addObject:[copy entryForItem:copy.items.back().get()]];
+ }
+ return copy;
+}
+
+#pragma mark - Public
+
+- (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager {
+ _navigationManager = navigationManager;
+ if (_navigationManager) {
+ // _browserState will be nullptr if CRWSessionController has been
+ // initialized with -initWithCoder: method. Take _browserState from
+ // NavigationManagerImpl if that's the case.
+ if (!_browserState) {
+ _browserState = _navigationManager->GetBrowserState();
+ }
+ DCHECK_EQ(_browserState, _navigationManager->GetBrowserState());
+ }
+}
+
+- (void)setBrowserState:(web::BrowserState*)browserState {
+ _browserState = browserState;
+ DCHECK(!_navigationManager ||
+ _navigationManager->GetBrowserState() == _browserState);
+}
+
+- (void)addPendingItem:(const GURL&)url
+ referrer:(const web::Referrer&)ref
+ transition:(ui::PageTransition)trans
+ rendererInitiated:(BOOL)rendererInitiated {
+ [self discardTransientItem];
+ self.pendingItemIndex = -1;
+
+ // Don't create a new item if it's already the same as the current item,
// allowing this routine to be called multiple times in a row without issue.
// Note: CRWSessionController currently has the responsibility to distinguish
// between new navigations and history stack navigation, hence the inclusion
@@ -316,52 +414,46 @@ - (void)addPendingEntry:(const GURL&)url
// TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere
// in the web layer so that this hack can be removed.
// Remove the workaround code from -presentSafeBrowsingWarningForResource:.
- CRWSessionEntry* currentEntry = self.currentEntry;
- if (currentEntry) {
- web::NavigationItem* item = [currentEntry navigationItem];
- if (item->GetURL() == url &&
- (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
- PageTransitionCoreTypeIs(item->GetTransitionType(),
- ui::PAGE_TRANSITION_FORM_SUBMIT))) {
- // Send the notification anyway, to preserve old behavior. It's unknown
- // whether anything currently relies on this, but since both this whole
- // hack and the content facade will both be going away, it's not worth
- // trying to unwind.
- if (_navigationManager && _navigationManager->GetFacadeDelegate()) {
- _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
- }
- return;
- }
+ web::NavigationItemImpl* currentItem = self.currentItem;
+ if (currentItem && currentItem->GetURL() == url &&
+ (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
+ PageTransitionCoreTypeIs(currentItem->GetTransitionType(),
+ ui::PAGE_TRANSITION_FORM_SUBMIT))) {
+ // Send the notification anyway, to preserve old behavior. It's unknown
+ // whether anything currently relies on this, but since both this whole
+ // hack and the content facade will both be going away, it's not worth
+ // trying to unwind.
+ if (_navigationManager && _navigationManager->GetFacadeDelegate())
+ _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
+ return;
}
BOOL useDesktopUserAgent =
- _useDesktopUserAgentForNextPendingEntry ||
- (self.currentEntry.navigationItem &&
- self.currentEntry.navigationItem->IsOverridingUserAgent());
- _useDesktopUserAgentForNextPendingEntry = NO;
- _pendingEntry.reset([self sessionEntryWithURL:url
- referrer:ref
- transition:trans
- useDesktopUserAgent:useDesktopUserAgent
- rendererInitiated:rendererInitiated]);
-
- if (_navigationManager && _navigationManager->GetFacadeDelegate()) {
+ _useDesktopUserAgentForNextPendingItem ||
+ (currentItem && currentItem->IsOverridingUserAgent());
+ _useDesktopUserAgentForNextPendingItem = NO;
+ _pendingItem = [self itemWithURL:url
+ referrer:ref
+ transition:trans
+ useDesktopUserAgent:useDesktopUserAgent
+ rendererInitiated:rendererInitiated];
+
+ if (_navigationManager && _navigationManager->GetFacadeDelegate())
_navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
- }
}
-- (void)updatePendingEntry:(const GURL&)url {
- // If there is no pending entry, navigation is probably happening within the
- // session history. Don't modify the entry list.
- if (!_pendingEntry)
+- (void)updatePendingItem:(const GURL&)url {
+ // If there is no pending item, navigation is probably happening within the
+ // session history. Don't modify the item list.
+ web::NavigationItemImpl* item = self.pendingItem;
+ if (!item)
return;
- web::NavigationItemImpl* item = [_pendingEntry navigationItemImpl];
if (url != item->GetURL()) {
- // Assume a redirection, and discard any transient entry.
+ // Assume a redirection, and discard any transient item.
// TODO(stuartmorgan): Once the current safe browsing code is gone,
- // consider making this a DCHECK that there's no transient entry.
- [self discardTransientEntry];
+ // consider making this a DCHECK that there's no transient item.
+ [self discardTransientItem];
item->SetURL(url);
item->SetVirtualURL(url);
@@ -373,183 +465,193 @@ - (void)updatePendingEntry:(const GURL&)url {
// This should probably not be sent if the URLs matched, but that's what was
// done before, so preserve behavior in case something relies on it.
- if (_navigationManager && _navigationManager->GetFacadeDelegate()) {
+ if (_navigationManager && _navigationManager->GetFacadeDelegate())
_navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
- }
}
-- (void)clearForwardEntries {
- DCHECK_EQ(_pendingEntryIndex, -1);
- [self discardTransientEntry];
+- (void)clearForwardItems {
+ DCHECK_EQ(self.pendingItemIndex, -1);
+ [self discardTransientItem];
- NSInteger forwardEntryStartIndex = _currentNavigationIndex + 1;
- DCHECK(forwardEntryStartIndex >= 0);
+ NSInteger forwardItemStartIndex = _currentNavigationIndex + 1;
+ DCHECK(forwardItemStartIndex >= 0);
- if (forwardEntryStartIndex >= static_cast<NSInteger>([_entries count]))
+ size_t itemCount = self.items.size();
+ if (forwardItemStartIndex >= static_cast<NSInteger>(itemCount))
return;
- NSRange remove = NSMakeRange(forwardEntryStartIndex,
- [_entries count] - forwardEntryStartIndex);
- // Store removed items in temporary NSArray so they can be deallocated after
- // their facades.
- base::scoped_nsobject<NSArray> removedItems(
+ // Remove the CRWSessionEntries from the map.
+ for (size_t index = forwardItemStartIndex; index < itemCount; ++index)
+ self.sessionEntryMap.erase(self.items[index].get());
+
+ // Remove the forward CRWSessionEntries in |_entries|, storing them in a
+ // temporary array so they're deallocated after their facades.
+ // TODO(crbug.com/583744): Remove facade code.
+ NSRange remove = NSMakeRange(forwardItemStartIndex,
+ [_entries count] - forwardItemStartIndex);
+ base::scoped_nsobject<NSArray> removedEntries(
[_entries subarrayWithRange:remove]);
[_entries removeObjectsInRange:remove];
- if (_previousNavigationIndex >= forwardEntryStartIndex)
+ if (_previousNavigationIndex >= forwardItemStartIndex)
_previousNavigationIndex = -1;
- if (_navigationManager) {
+ if (_navigationManager)
_navigationManager->OnNavigationItemsPruned(remove.length);
- }
+
+ // Remove the NavigationItems.
+ _items.erase(_items.begin() + forwardItemStartIndex, _items.end());
}
-- (void)commitPendingEntry {
- if (_pendingEntry) {
- NSInteger newNavigationIndex = _pendingEntryIndex;
- if (_pendingEntryIndex == -1) {
- [self clearForwardEntries];
- // Add the new entry at the end.
- [_entries addObject:_pendingEntry];
- newNavigationIndex = [_entries count] - 1;
+- (void)commitPendingItem {
+ if (self.pendingItem) {
+ // Once an item is committed it's not renderer-initiated any more. (Matches
+ // the implementation in NavigationController.)
+ self.pendingItem->ResetForCommit();
+
+ NSInteger newNavigationIndex = self.pendingItemIndex;
+ if (newNavigationIndex == -1) {
+ [self clearForwardItems];
+ // Add the new item at the end.
+ _items.push_back(std::move(_pendingItem));
+ [_entries addObject:[self entryForItem:self.items.back().get()]];
+ newNavigationIndex = self.items.size() - 1;
}
_previousNavigationIndex = _currentNavigationIndex;
self.currentNavigationIndex = newNavigationIndex;
- // Once an entry is committed it's not renderer-initiated any more. (Matches
- // the implementation in NavigationController.)
- [_pendingEntry navigationItemImpl]->ResetForCommit();
- _pendingEntry.reset();
- _pendingEntryIndex = -1;
+ self.pendingItemIndex = -1;
}
- CRWSessionEntry* currentEntry = self.currentEntry;
- web::NavigationItem* item = currentEntry.navigationItem;
+ web::NavigationItem* item = self.currentItem;
// Update the navigation timestamp now that it's actually happened.
if (item)
item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now()));
if (_navigationManager && item)
_navigationManager->OnNavigationItemCommitted();
- DCHECK_EQ(_pendingEntryIndex, -1);
+ DCHECK_EQ(self.pendingItemIndex, -1);
}
-- (void)addTransientEntryWithURL:(const GURL&)URL {
- _transientEntry.reset([self
- sessionEntryWithURL:URL
- referrer:web::Referrer()
- transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
- useDesktopUserAgent:NO
- rendererInitiated:NO]);
-
- web::NavigationItem* navigationItem = [_transientEntry navigationItem];
- DCHECK(navigationItem);
- navigationItem->SetTimestamp(
+- (void)addTransientItemWithURL:(const GURL&)URL {
+ _transientItem = [self itemWithURL:URL
+ referrer:web::Referrer()
+ transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
+ useDesktopUserAgent:NO
+ rendererInitiated:NO];
+ _transientItem->SetTimestamp(
_timeSmoother.GetSmoothedTime(base::Time::Now()));
}
-- (void)pushNewEntryWithURL:(const GURL&)URL
- stateObject:(NSString*)stateObject
- transition:(ui::PageTransition)transition {
- DCHECK(![self pendingEntry]);
- DCHECK([self currentEntry]);
- web::NavigationItem* item = [self currentEntry].navigationItem;
+- (void)pushNewItemWithURL:(const GURL&)URL
+ stateObject:(NSString*)stateObject
+ transition:(ui::PageTransition)transition {
+ DCHECK(!self.pendingItem);
+ web::NavigationItem* item = self.currentItem;
+ DCHECK(item);
CHECK(
web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL));
web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault);
- bool overrideUserAgent =
- self.currentEntry.navigationItem->IsOverridingUserAgent();
- base::scoped_nsobject<CRWSessionEntry> pushedEntry([self
- sessionEntryWithURL:URL
- referrer:referrer
- transition:transition
- useDesktopUserAgent:overrideUserAgent
- rendererInitiated:NO]);
- web::NavigationItemImpl* pushedItem = [pushedEntry navigationItemImpl];
+ bool overrideUserAgent = self.currentItem->IsOverridingUserAgent();
+ std::unique_ptr<web::NavigationItemImpl> pushedItem =
+ [self itemWithURL:URL
+ referrer:referrer
+ transition:transition
+ useDesktopUserAgent:overrideUserAgent
+ rendererInitiated:NO];
pushedItem->SetSerializedStateObject(stateObject);
pushedItem->SetIsCreatedFromPushState(true);
- web::SSLStatus& sslStatus = [self currentEntry].navigationItem->GetSSL();
- pushedEntry.get().navigationItem->GetSSL() = sslStatus;
+ web::SSLStatus& sslStatus = self.currentItem->GetSSL();
+ pushedItem->GetSSL() = sslStatus;
- [self clearForwardEntries];
- // Add the new entry at the end.
- [_entries addObject:pushedEntry];
+ [self clearForwardItems];
+ // Add the new item at the end.
+ _items.push_back(std::move(pushedItem));
+ [_entries addObject:[self entryForItem:self.items.back().get()]];
_previousNavigationIndex = _currentNavigationIndex;
- self.currentNavigationIndex = [_entries count] - 1;
+ self.currentNavigationIndex = self.items.size() - 1;
if (_navigationManager)
_navigationManager->OnNavigationItemCommitted();
}
-- (void)updateCurrentEntryWithURL:(const GURL&)url
- stateObject:(NSString*)stateObject {
- DCHECK(!_transientEntry);
- CRWSessionEntry* currentEntry = self.currentEntry;
- web::NavigationItemImpl* currentItem = self.currentEntry.navigationItemImpl;
+- (void)updateCurrentItemWithURL:(const GURL&)url
+ stateObject:(NSString*)stateObject {
+ DCHECK(!self.transientItem);
+ web::NavigationItemImpl* currentItem = self.currentItem;
currentItem->SetURL(url);
currentItem->SetSerializedStateObject(stateObject);
currentItem->SetHasStateBeenReplaced(true);
currentItem->SetPostData(nil);
- currentEntry.navigationItem->SetURL(url);
- // If the change is to a committed entry, notify interested parties.
- if (currentEntry != self.pendingEntry && _navigationManager)
+ // If the change is to a committed item, notify interested parties.
+ if (currentItem != self.pendingItem && _navigationManager)
_navigationManager->OnNavigationItemChanged();
}
-- (void)discardNonCommittedEntries {
- [self discardTransientEntry];
- _pendingEntry.reset();
- _pendingEntryIndex = -1;
-}
-
-- (void)discardTransientEntry {
- // Keep the entry alive temporarily. There are flows that get the current
- // entry, do some navigation operation, and then try to use that old current
- // entry; since navigations clear the transient entry, these flows might
- // crash. (This should be removable once more session management is handled
- // within this class and/or NavigationManager).
- _transientEntry.reset();
+- (void)discardNonCommittedItems {
+ [self discardTransientItem];
+ self.sessionEntryMap.erase(self.pendingItem);
+ _pendingItem.reset();
+ self.pendingItemIndex = -1;
}
-- (BOOL)hasPendingEntry {
- return _pendingEntry != nil;
+- (void)discardTransientItem {
+ self.sessionEntryMap.erase(self.transientItem);
+ _transientItem.reset();
}
- (void)insertStateFromSessionController:(CRWSessionController*)sourceSession {
DCHECK(sourceSession);
self.windowName = sourceSession.windowName;
- // The other session may not have any entries, in which case there is nothing
- // to insert. The other session's currentNavigationEntry will be bogus
+ // The other session may not have any items, in which case there is nothing
+ // to insert. The other session's currentItem will be bogus
// in such cases, so ignore it and return early.
- NSArray* sourceEntries = sourceSession.entries;
- if (!sourceEntries.count)
+ web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items;
+ if (sourceItems.empty())
return;
- // Cycle through the entries from the other session and insert them before any
- // entries from this session. Do not copy anything that comes after the other
- // session's current entry.
+ // Cycle through the items from the other session and insert them before any
+ // items from this session. Do not copy anything that comes after the other
+ // session's current item.
NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex;
for (NSInteger i = 0; i <= lastIndexToCopy; ++i) {
- [_entries insertObject:sourceEntries[i] atIndex:i];
+ web::NavigationItemImpl* itemToInsert = sourceItems[i].get();
+ CRWSessionEntry* insertedEntry = [sourceSession entryForItem:itemToInsert];
+ _items.insert(_items.begin() + i, std::move(sourceItems[i]));
+ [_entries insertObject:insertedEntry atIndex:i];
+ self.sessionEntryMap[itemToInsert].reset(insertedEntry);
}
+ // Update state to reflect inserted NavigationItems.
_previousNavigationIndex = -1;
_currentNavigationIndex += lastIndexToCopy + 1;
- if (_pendingEntryIndex != -1)
- _pendingEntryIndex += lastIndexToCopy + 1;
-
- DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), _entries.count);
- DCHECK(_pendingEntryIndex == -1 || _pendingEntry);
-}
-
-- (void)goToEntryAtIndex:(NSInteger)index {
- if (index < 0 || static_cast<NSUInteger>(index) >= _entries.count)
+ if (self.pendingItemIndex != -1)
+ self.pendingItemIndex += lastIndexToCopy + 1;
+
+ // Update |sourceSession|'s state to reflect the ownership of its
+ // NavigationItems.
+ sourceSession->_items.clear();
+ [sourceSession->_entries removeAllObjects];
+ sourceSession->_pendingItem.reset();
+ sourceSession->_transientItem.reset();
+ sourceSession->_sessionEntryMap.clear();
+ sourceSession->_currentNavigationIndex = -1;
+ sourceSession->_previousNavigationIndex = -1;
+ sourceSession->_pendingItemIndex = -1;
+
+ DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex),
+ self.items.size());
+ DCHECK(self.pendingItemIndex == -1 || self.pendingItem);
+}
+
+- (void)goToItemAtIndex:(NSInteger)index {
+ if (index < 0 || static_cast<NSUInteger>(index) >= self.items.size())
return;
if (index < _currentNavigationIndex) {
// Going back.
- [self discardNonCommittedEntries];
+ [self discardNonCommittedItems];
} else if (_currentNavigationIndex < index) {
// Going forward.
- [self discardTransientEntry];
+ [self discardTransientItem];
} else {
// |delta| is 0, no need to change current navigation index.
return;
@@ -559,87 +661,62 @@ - (void)goToEntryAtIndex:(NSInteger)index {
_currentNavigationIndex = index;
}
-- (void)removeEntryAtIndex:(NSInteger)index {
- DCHECK(index < static_cast<NSInteger>([_entries count]));
+- (void)removeItemAtIndex:(NSInteger)index {
+ DCHECK(index < static_cast<NSInteger>(self.items.size()));
DCHECK(index != _currentNavigationIndex);
DCHECK(index >= 0);
- [self discardNonCommittedEntries];
+ [self discardNonCommittedItems];
[_entries removeObjectAtIndex:index];
+ self.sessionEntryMap.erase(self.items[index].get());
+ _items.erase(_items.begin() + index);
if (_currentNavigationIndex > index)
_currentNavigationIndex--;
if (_previousNavigationIndex >= index)
_previousNavigationIndex--;
}
-- (NSArray*)backwardEntries {
- NSMutableArray* entries = [NSMutableArray array];
- for (NSInteger index = _currentNavigationIndex; index > 0; --index) {
- if (![self isRedirectTransitionForEntryAtIndex:index])
- [entries addObject:_entries[index - 1]];
- }
- return entries;
-}
-
-- (NSArray*)forwardEntries {
- NSMutableArray* entries = [NSMutableArray array];
- NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
- while (lastNonRedirectedIndex < [_entries count]) {
- CRWSessionEntry* entry = [_entries objectAtIndex:lastNonRedirectedIndex];
- if (!ui::PageTransitionIsRedirect(
- entry.navigationItem->GetTransitionType())) {
- [entries addObject:entry];
- }
- ++lastNonRedirectedIndex;
- }
- return entries;
-}
-
-- (BOOL)isSameDocumentNavigationBetweenEntry:(CRWSessionEntry*)firstEntry
- andEntry:(CRWSessionEntry*)secondEntry {
- if (!firstEntry || !secondEntry || firstEntry == secondEntry)
+- (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem
+ andItem:(web::NavigationItem*)secondItem {
+ if (!firstItem || !secondItem || firstItem == secondItem)
return NO;
- NSUInteger firstIndex = [_entries indexOfObject:firstEntry];
- NSUInteger secondIndex = [_entries indexOfObject:secondEntry];
+ NSUInteger firstIndex = [self indexOfItem:firstItem];
+ NSUInteger secondIndex = [self indexOfItem:secondItem];
if (firstIndex == NSNotFound || secondIndex == NSNotFound)
return NO;
NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex;
NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
for (NSUInteger i = startIndex + 1; i <= endIndex; i++) {
- web::NavigationItemImpl* item = [_entries[i] navigationItemImpl];
- // Every entry in the sequence has to be created from a hash change or
+ web::NavigationItemImpl* item = self.items[i].get();
+ // Every item in the sequence has to be created from a hash change or
// pushState() call.
if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange())
return NO;
- // Every entry in the sequence has to have a URL that could have been
+ // Every item in the sequence has to have a URL that could have been
// created from a pushState() call.
- if (!web::history_state_util::IsHistoryStateChangeValid(
- firstEntry.navigationItem->GetURL(), item->GetURL()))
+ if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(),
+ item->GetURL()))
return NO;
}
return YES;
}
-- (CRWSessionEntry*)lastUserEntry {
- if (![_entries count])
- return nil;
-
- NSInteger index = _currentNavigationIndex;
- // This will return the first session entry if all other entries are
- // redirects, regardless of the transition state of the first entry.
- while (index > 0 && [self isRedirectTransitionForEntryAtIndex:index]) {
- --index;
- }
- return [_entries objectAtIndex:index];
+- (void)useDesktopUserAgentForNextPendingItem {
+ if (self.pendingItem)
+ self.pendingItem->SetIsOverridingUserAgent(true);
+ else
+ _useDesktopUserAgentForNextPendingItem = YES;
}
-- (void)useDesktopUserAgentForNextPendingEntry {
- if (_pendingEntry)
- [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true);
- else
- _useDesktopUserAgentForNextPendingEntry = YES;
+- (NSInteger)indexOfItem:(web::NavigationItem*)item {
+ DCHECK(item);
+ for (size_t index = 0; index < self.items.size(); ++index) {
+ if (self.items[index].get() == item)
+ return index;
+ }
+ return NSNotFound;
}
#pragma mark -
@@ -656,11 +733,12 @@ - (NSString*)uniqueID {
return uuid;
}
-- (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url
- referrer:(const web::Referrer&)referrer
- transition:(ui::PageTransition)transition
- useDesktopUserAgent:(BOOL)useDesktopUserAgent
- rendererInitiated:(BOOL)rendererInitiated {
+- (std::unique_ptr<web::NavigationItemImpl>)
+ itemWithURL:(const GURL&)url
+ referrer:(const web::Referrer&)referrer
+ transition:(ui::PageTransition)transition
+useDesktopUserAgent:(BOOL)useDesktopUserAgent
+ rendererInitiated:(BOOL)rendererInitiated {
GURL loaded_url(url);
BOOL urlWasRewritten = NO;
if (_navigationManager) {
@@ -682,13 +760,38 @@ - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url
item->SetTransitionType(transition);
item->SetIsOverridingUserAgent(useDesktopUserAgent);
item->set_is_renderer_initiated(rendererInitiated);
- return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)];
+ return item;
}
-- (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index {
- ui::PageTransition transition =
- [_entries[index] navigationItem]->GetTransitionType();
+- (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index {
+ DCHECK_LT(index, self.items.size());
+ ui::PageTransition transition = self.items[index]->GetTransitionType();
return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO;
}
+- (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item {
+ if (!item)
+ return nil;
+ // CRWSessionEntries vended by a CRWSessionController should always correspond
+ // with a NavigationItem that is owned by that CRWSessionController.
+ DCHECK([self indexOfItem:item] != NSNotFound || item == _pendingItem.get() ||
+ item == _transientItem.get());
+ base::scoped_nsobject<CRWSessionEntry>& entry = self.sessionEntryMap[item];
+ if (!entry)
+ entry.reset([[CRWSessionEntry alloc] initWithNavigationItem:item]);
+ DCHECK(entry);
+ return entry;
+}
+
+- (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList {
+ NSMutableArray* entryList =
+ [[NSMutableArray alloc] initWithCapacity:itemList.size()];
+ for (web::NavigationItem* item : itemList) {
+ CRWSessionEntry* entry =
+ [self entryForItem:static_cast<web::NavigationItemImpl*>(item)];
+ [entryList addObject:entry];
+ }
+ return entryList;
+}
+
@end
« no previous file with comments | « ios/web/navigation/crw_session_controller.h ('k') | ios/web/navigation/crw_session_controller+private_constructors.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698