| 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 d5e3801cf9c8fbdb677a8486b2a023a902322847..05f8f476bf33e2502a217d674c12dc2da33b6624 100644
|
| --- a/ios/web/navigation/crw_session_controller.mm
|
| +++ b/ios/web/navigation/crw_session_controller.mm
|
| @@ -132,9 +132,6 @@
|
| // Return the PageTransition for the underlying navigationItem at |index| in
|
| // |entries_|
|
| - (ui::PageTransition)transitionForIndex:(NSUInteger)index;
|
| -// Returns YES if the PageTransition for the underlying navigationItem at
|
| -// |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
|
| -- (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index;
|
| @end
|
|
|
| @implementation CRWSessionController
|
| @@ -615,47 +612,101 @@
|
| }
|
|
|
| - (BOOL)canGoBack {
|
| - return [self canGoDelta:-1];
|
| + if ([_entries count] == 0)
|
| + return NO;
|
| +
|
| + // A transient entry behaves from a user perspective in most ways like a
|
| + // committed entry, so allow going back from a transient entry since this
|
| + // object already has at least one committed entry.
|
| + if (_transientEntry)
|
| + return YES;
|
| +
|
| + NSInteger lastNonRedirectedIndex = _currentNavigationIndex;
|
| + while (lastNonRedirectedIndex >= 0 &&
|
| + ui::PageTransitionIsRedirect(
|
| + [self transitionForIndex:lastNonRedirectedIndex])) {
|
| + --lastNonRedirectedIndex;
|
| + }
|
| +
|
| + return lastNonRedirectedIndex > 0;
|
| }
|
|
|
| - (BOOL)canGoForward {
|
| - return [self canGoDelta:1];
|
| -}
|
| -
|
| -- (BOOL)canGoDelta:(int)delta {
|
| - NSInteger index = [self indexOfEntryForDelta:delta];
|
| - return 0 <= index && static_cast<NSUInteger>(index) < _entries.count;
|
| + // In case there are pending entries return no since when the entry will be
|
| + // committed the history will be cleared from that point forward.
|
| + if (_pendingEntry)
|
| + return NO;
|
| + // If the current index is less than the last element, there are entries to
|
| + // go forward to.
|
| + const NSInteger count = [_entries count];
|
| + return count && _currentNavigationIndex < (count - 1);
|
| }
|
|
|
| - (void)goBack {
|
| - [self goDelta:-1];
|
| + if (![self canGoBack])
|
| + return;
|
| +
|
| + BOOL hadTransientEntry = _transientEntry != nil;
|
| +
|
| + [self discardNonCommittedEntries];
|
| +
|
| + // Going back from a transient entry doesn't require anything beyond
|
| + // discarding the pending entry.
|
| + if (hadTransientEntry)
|
| + return;
|
| +
|
| + base::RecordAction(UserMetricsAction("Back"));
|
| + _previousNavigationIndex = _currentNavigationIndex;
|
| + // To stop the user getting 'stuck' on redirecting pages they weren't even
|
| + // aware existed, it is necessary to pass over pages that would immediately
|
| + // result in a redirect (the entry *before* the redirected page).
|
| + while (_currentNavigationIndex &&
|
| + [self transitionForIndex:_currentNavigationIndex] &
|
| + ui::PAGE_TRANSITION_IS_REDIRECT_MASK) {
|
| + --_currentNavigationIndex;
|
| + }
|
| +
|
| + if (_currentNavigationIndex)
|
| + --_currentNavigationIndex;
|
| }
|
|
|
| - (void)goForward {
|
| - [self goDelta:1];
|
| + [self discardTransientEntry];
|
| +
|
| + base::RecordAction(UserMetricsAction("Forward"));
|
| + if (_currentNavigationIndex + 1 < static_cast<NSInteger>([_entries count])) {
|
| + _previousNavigationIndex = _currentNavigationIndex;
|
| + ++_currentNavigationIndex;
|
| + }
|
| + // To reduce the chance of a redirect kicking in (truncating the history
|
| + // stack) we skip over any pages that might do this; we detect this by
|
| + // looking for when the *next* page had rediection transition type (was
|
| + // auto redirected to).
|
| + while (_currentNavigationIndex + 1 <
|
| + (static_cast<NSInteger>([_entries count])) &&
|
| + ([self transitionForIndex:_currentNavigationIndex + 1] &
|
| + ui::PAGE_TRANSITION_IS_REDIRECT_MASK)) {
|
| + ++_currentNavigationIndex;
|
| + }
|
| }
|
|
|
| - (void)goDelta:(int)delta {
|
| - if (delta == 0 || ![self canGoDelta:delta])
|
| - return;
|
| -
|
| - NSInteger oldNavigationIndex = self.currentNavigationIndex;
|
| - NSInteger newNavigationIndex = [self indexOfEntryForDelta:delta];
|
| -
|
| + // Store the navigation index at the start of this function, as |-goForward|
|
| + // and |-goBack| will incrementally reset |_previousNavigationIndex| each time
|
| + // they are called.
|
| + NSInteger previousNavigationIndex = self.currentNavigationIndex;
|
| if (delta < 0) {
|
| - [self discardNonCommittedEntries];
|
| - for (int i = delta; i < 0; i++) {
|
| - base::RecordAction(UserMetricsAction("Back"));
|
| - }
|
| - } else if (delta > 0) {
|
| - [self discardTransientEntry];
|
| - for (int i = 0; i < delta; i++) {
|
| - base::RecordAction(UserMetricsAction("Forward"));
|
| - }
|
| - }
|
| -
|
| - _currentNavigationIndex = newNavigationIndex;
|
| - _previousNavigationIndex = oldNavigationIndex;
|
| + while ([self canGoBack] && delta < 0) {
|
| + [self goBack];
|
| + ++delta;
|
| + }
|
| + } else {
|
| + while ([self canGoForward] && delta > 0) {
|
| + [self goForward];
|
| + --delta;
|
| + }
|
| + }
|
| + _previousNavigationIndex = previousNavigationIndex;
|
| }
|
|
|
| - (void)goToEntry:(CRWSessionEntry*)entry {
|
| @@ -791,53 +842,6 @@
|
| [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true);
|
| else
|
| _useDesktopUserAgentForNextPendingEntry = YES;
|
| -}
|
| -
|
| -- (NSInteger)indexOfEntryForDelta:(int)delta {
|
| - NSInteger result = _currentNavigationIndex;
|
| - if (delta < 0) {
|
| - if (_transientEntry) {
|
| - // Going back from transient entry is a matter of discarding it and there
|
| - // is no need to move navigation index back.
|
| - delta++;
|
| - }
|
| -
|
| - while (delta < 0) {
|
| - // To stop the user getting 'stuck' on redirecting pages they weren't
|
| - // even aware existed, it is necessary to pass over pages that would
|
| - // immediately result in a redirect (the entry *before* the redirected
|
| - // page).
|
| - while (result > 0 && [self isRedirectTransitionForEntryAtIndex:result]) {
|
| - --result;
|
| - }
|
| - --result;
|
| - ++delta;
|
| - }
|
| - } else if (delta > 0) {
|
| - NSInteger count = static_cast<NSInteger>([_entries count]);
|
| - if (_pendingEntry) {
|
| - // Chrome for iOS does not allow forward navigation if there is another
|
| - // pending navigation in progress. Returning invalid index indicates that
|
| - // forward navigation will not be allowed (and |NSNotFound| works for
|
| - // that). This is different from other platforms which allow forward
|
| - // navigation if pending entry exist.
|
| - // TODO(crbug.com/661858): Remove this once back-forward navigation uses
|
| - // pending index.
|
| - return NSNotFound;
|
| - }
|
| -
|
| - while (delta > 0) {
|
| - ++result;
|
| - --delta;
|
| - // As with going back, skip over redirects.
|
| - while (result + 1 < count &&
|
| - [self isRedirectTransitionForEntryAtIndex:result + 1]) {
|
| - ++result;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return result;
|
| }
|
|
|
| #pragma mark -
|
| @@ -882,8 +886,4 @@
|
| return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)];
|
| }
|
|
|
| -- (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index {
|
| - return [self transitionForIndex:index] & ui::PAGE_TRANSITION_IS_REDIRECT_MASK;
|
| -}
|
| -
|
| @end
|
|
|