| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/web/navigation/crw_session_controller.h" | 5 #import "ios/web/navigation/crw_session_controller.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 - (void)discardTransientEntry; | 125 - (void)discardTransientEntry; |
| 126 // Create a new autoreleased session entry. | 126 // Create a new autoreleased session entry. |
| 127 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url | 127 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url |
| 128 referrer:(const web::Referrer&)referrer | 128 referrer:(const web::Referrer&)referrer |
| 129 transition:(ui::PageTransition)transition | 129 transition:(ui::PageTransition)transition |
| 130 useDesktopUserAgent:(BOOL)useDesktopUserAgent | 130 useDesktopUserAgent:(BOOL)useDesktopUserAgent |
| 131 rendererInitiated:(BOOL)rendererInitiated; | 131 rendererInitiated:(BOOL)rendererInitiated; |
| 132 // Return the PageTransition for the underlying navigationItem at |index| in | 132 // Return the PageTransition for the underlying navigationItem at |index| in |
| 133 // |entries_| | 133 // |entries_| |
| 134 - (ui::PageTransition)transitionForIndex:(NSUInteger)index; | 134 - (ui::PageTransition)transitionForIndex:(NSUInteger)index; |
| 135 // Returns YES if the PageTransition for the underlying navigationItem at | |
| 136 // |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK. | |
| 137 - (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index; | |
| 138 @end | 135 @end |
| 139 | 136 |
| 140 @implementation CRWSessionController | 137 @implementation CRWSessionController |
| 141 | 138 |
| 142 @synthesize tabId = _tabId; | 139 @synthesize tabId = _tabId; |
| 143 @synthesize currentNavigationIndex = _currentNavigationIndex; | 140 @synthesize currentNavigationIndex = _currentNavigationIndex; |
| 144 @synthesize previousNavigationIndex = _previousNavigationIndex; | 141 @synthesize previousNavigationIndex = _previousNavigationIndex; |
| 145 @synthesize entries = _entries; | 142 @synthesize entries = _entries; |
| 146 @synthesize windowName = _windowName; | 143 @synthesize windowName = _windowName; |
| 147 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp; | 144 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp; |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 } | 605 } |
| 609 } | 606 } |
| 610 DCHECK_LT((NSUInteger)_currentNavigationIndex, [_entries count]); | 607 DCHECK_LT((NSUInteger)_currentNavigationIndex, [_entries count]); |
| 611 } | 608 } |
| 612 | 609 |
| 613 - (ui::PageTransition)transitionForIndex:(NSUInteger)index { | 610 - (ui::PageTransition)transitionForIndex:(NSUInteger)index { |
| 614 return [[_entries objectAtIndex:index] navigationItem]->GetTransitionType(); | 611 return [[_entries objectAtIndex:index] navigationItem]->GetTransitionType(); |
| 615 } | 612 } |
| 616 | 613 |
| 617 - (BOOL)canGoBack { | 614 - (BOOL)canGoBack { |
| 618 return [self canGoDelta:-1]; | 615 if ([_entries count] == 0) |
| 616 return NO; |
| 617 |
| 618 // A transient entry behaves from a user perspective in most ways like a |
| 619 // committed entry, so allow going back from a transient entry since this |
| 620 // object already has at least one committed entry. |
| 621 if (_transientEntry) |
| 622 return YES; |
| 623 |
| 624 NSInteger lastNonRedirectedIndex = _currentNavigationIndex; |
| 625 while (lastNonRedirectedIndex >= 0 && |
| 626 ui::PageTransitionIsRedirect( |
| 627 [self transitionForIndex:lastNonRedirectedIndex])) { |
| 628 --lastNonRedirectedIndex; |
| 629 } |
| 630 |
| 631 return lastNonRedirectedIndex > 0; |
| 619 } | 632 } |
| 620 | 633 |
| 621 - (BOOL)canGoForward { | 634 - (BOOL)canGoForward { |
| 622 return [self canGoDelta:1]; | 635 // In case there are pending entries return no since when the entry will be |
| 623 } | 636 // committed the history will be cleared from that point forward. |
| 624 | 637 if (_pendingEntry) |
| 625 - (BOOL)canGoDelta:(int)delta { | 638 return NO; |
| 626 NSInteger index = [self indexOfEntryForDelta:delta]; | 639 // If the current index is less than the last element, there are entries to |
| 627 return 0 <= index && static_cast<NSUInteger>(index) < _entries.count; | 640 // go forward to. |
| 641 const NSInteger count = [_entries count]; |
| 642 return count && _currentNavigationIndex < (count - 1); |
| 628 } | 643 } |
| 629 | 644 |
| 630 - (void)goBack { | 645 - (void)goBack { |
| 631 [self goDelta:-1]; | 646 if (![self canGoBack]) |
| 647 return; |
| 648 |
| 649 BOOL hadTransientEntry = _transientEntry != nil; |
| 650 |
| 651 [self discardNonCommittedEntries]; |
| 652 |
| 653 // Going back from a transient entry doesn't require anything beyond |
| 654 // discarding the pending entry. |
| 655 if (hadTransientEntry) |
| 656 return; |
| 657 |
| 658 base::RecordAction(UserMetricsAction("Back")); |
| 659 _previousNavigationIndex = _currentNavigationIndex; |
| 660 // To stop the user getting 'stuck' on redirecting pages they weren't even |
| 661 // aware existed, it is necessary to pass over pages that would immediately |
| 662 // result in a redirect (the entry *before* the redirected page). |
| 663 while (_currentNavigationIndex && |
| 664 [self transitionForIndex:_currentNavigationIndex] & |
| 665 ui::PAGE_TRANSITION_IS_REDIRECT_MASK) { |
| 666 --_currentNavigationIndex; |
| 667 } |
| 668 |
| 669 if (_currentNavigationIndex) |
| 670 --_currentNavigationIndex; |
| 632 } | 671 } |
| 633 | 672 |
| 634 - (void)goForward { | 673 - (void)goForward { |
| 635 [self goDelta:1]; | 674 [self discardTransientEntry]; |
| 675 |
| 676 base::RecordAction(UserMetricsAction("Forward")); |
| 677 if (_currentNavigationIndex + 1 < static_cast<NSInteger>([_entries count])) { |
| 678 _previousNavigationIndex = _currentNavigationIndex; |
| 679 ++_currentNavigationIndex; |
| 680 } |
| 681 // To reduce the chance of a redirect kicking in (truncating the history |
| 682 // stack) we skip over any pages that might do this; we detect this by |
| 683 // looking for when the *next* page had rediection transition type (was |
| 684 // auto redirected to). |
| 685 while (_currentNavigationIndex + 1 < |
| 686 (static_cast<NSInteger>([_entries count])) && |
| 687 ([self transitionForIndex:_currentNavigationIndex + 1] & |
| 688 ui::PAGE_TRANSITION_IS_REDIRECT_MASK)) { |
| 689 ++_currentNavigationIndex; |
| 690 } |
| 636 } | 691 } |
| 637 | 692 |
| 638 - (void)goDelta:(int)delta { | 693 - (void)goDelta:(int)delta { |
| 639 if (delta == 0 || ![self canGoDelta:delta]) | 694 // Store the navigation index at the start of this function, as |-goForward| |
| 640 return; | 695 // and |-goBack| will incrementally reset |_previousNavigationIndex| each time |
| 641 | 696 // they are called. |
| 642 NSInteger oldNavigationIndex = self.currentNavigationIndex; | 697 NSInteger previousNavigationIndex = self.currentNavigationIndex; |
| 643 NSInteger newNavigationIndex = [self indexOfEntryForDelta:delta]; | |
| 644 | |
| 645 if (delta < 0) { | 698 if (delta < 0) { |
| 646 [self discardNonCommittedEntries]; | 699 while ([self canGoBack] && delta < 0) { |
| 647 for (int i = delta; i < 0; i++) { | 700 [self goBack]; |
| 648 base::RecordAction(UserMetricsAction("Back")); | 701 ++delta; |
| 649 } | 702 } |
| 650 } else if (delta > 0) { | 703 } else { |
| 651 [self discardTransientEntry]; | 704 while ([self canGoForward] && delta > 0) { |
| 652 for (int i = 0; i < delta; i++) { | 705 [self goForward]; |
| 653 base::RecordAction(UserMetricsAction("Forward")); | 706 --delta; |
| 654 } | 707 } |
| 655 } | 708 } |
| 656 | 709 _previousNavigationIndex = previousNavigationIndex; |
| 657 _currentNavigationIndex = newNavigationIndex; | |
| 658 _previousNavigationIndex = oldNavigationIndex; | |
| 659 } | 710 } |
| 660 | 711 |
| 661 - (void)goToEntry:(CRWSessionEntry*)entry { | 712 - (void)goToEntry:(CRWSessionEntry*)entry { |
| 662 DCHECK(entry); | 713 DCHECK(entry); |
| 663 | 714 |
| 664 [self discardTransientEntry]; | 715 [self discardTransientEntry]; |
| 665 | 716 |
| 666 // Check that |entries_| still contains |entry|. |entry| could have been | 717 // Check that |entries_| still contains |entry|. |entry| could have been |
| 667 // removed by -clearForwardEntries. | 718 // removed by -clearForwardEntries. |
| 668 if ([_entries containsObject:entry]) { | 719 if ([_entries containsObject:entry]) { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 return [_entries objectAtIndex:index]; | 837 return [_entries objectAtIndex:index]; |
| 787 } | 838 } |
| 788 | 839 |
| 789 - (void)useDesktopUserAgentForNextPendingEntry { | 840 - (void)useDesktopUserAgentForNextPendingEntry { |
| 790 if (_pendingEntry) | 841 if (_pendingEntry) |
| 791 [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true); | 842 [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true); |
| 792 else | 843 else |
| 793 _useDesktopUserAgentForNextPendingEntry = YES; | 844 _useDesktopUserAgentForNextPendingEntry = YES; |
| 794 } | 845 } |
| 795 | 846 |
| 796 - (NSInteger)indexOfEntryForDelta:(int)delta { | |
| 797 NSInteger result = _currentNavigationIndex; | |
| 798 if (delta < 0) { | |
| 799 if (_transientEntry) { | |
| 800 // Going back from transient entry is a matter of discarding it and there | |
| 801 // is no need to move navigation index back. | |
| 802 delta++; | |
| 803 } | |
| 804 | |
| 805 while (delta < 0) { | |
| 806 // To stop the user getting 'stuck' on redirecting pages they weren't | |
| 807 // even aware existed, it is necessary to pass over pages that would | |
| 808 // immediately result in a redirect (the entry *before* the redirected | |
| 809 // page). | |
| 810 while (result > 0 && [self isRedirectTransitionForEntryAtIndex:result]) { | |
| 811 --result; | |
| 812 } | |
| 813 --result; | |
| 814 ++delta; | |
| 815 } | |
| 816 } else if (delta > 0) { | |
| 817 NSInteger count = static_cast<NSInteger>([_entries count]); | |
| 818 if (_pendingEntry) { | |
| 819 // Chrome for iOS does not allow forward navigation if there is another | |
| 820 // pending navigation in progress. Returning invalid index indicates that | |
| 821 // forward navigation will not be allowed (and |NSNotFound| works for | |
| 822 // that). This is different from other platforms which allow forward | |
| 823 // navigation if pending entry exist. | |
| 824 // TODO(crbug.com/661858): Remove this once back-forward navigation uses | |
| 825 // pending index. | |
| 826 return NSNotFound; | |
| 827 } | |
| 828 | |
| 829 while (delta > 0) { | |
| 830 ++result; | |
| 831 --delta; | |
| 832 // As with going back, skip over redirects. | |
| 833 while (result + 1 < count && | |
| 834 [self isRedirectTransitionForEntryAtIndex:result + 1]) { | |
| 835 ++result; | |
| 836 } | |
| 837 } | |
| 838 } | |
| 839 | |
| 840 return result; | |
| 841 } | |
| 842 | |
| 843 #pragma mark - | 847 #pragma mark - |
| 844 #pragma mark Private methods | 848 #pragma mark Private methods |
| 845 | 849 |
| 846 - (NSString*)uniqueID { | 850 - (NSString*)uniqueID { |
| 847 CFUUIDRef uuidRef = CFUUIDCreate(NULL); | 851 CFUUIDRef uuidRef = CFUUIDCreate(NULL); |
| 848 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); | 852 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); |
| 849 CFRelease(uuidRef); | 853 CFRelease(uuidRef); |
| 850 | 854 |
| 851 NSString* uuid = | 855 NSString* uuid = |
| 852 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>( | 856 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>( |
| (...skipping 22 matching lines...) Expand all Loading... |
| 875 } | 879 } |
| 876 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); | 880 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); |
| 877 item->SetURL(loaded_url); | 881 item->SetURL(loaded_url); |
| 878 item->SetReferrer(referrer); | 882 item->SetReferrer(referrer); |
| 879 item->SetTransitionType(transition); | 883 item->SetTransitionType(transition); |
| 880 item->SetIsOverridingUserAgent(useDesktopUserAgent); | 884 item->SetIsOverridingUserAgent(useDesktopUserAgent); |
| 881 item->set_is_renderer_initiated(rendererInitiated); | 885 item->set_is_renderer_initiated(rendererInitiated); |
| 882 return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]; | 886 return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]; |
| 883 } | 887 } |
| 884 | 888 |
| 885 - (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index { | |
| 886 return [self transitionForIndex:index] & ui::PAGE_TRANSITION_IS_REDIRECT_MASK; | |
| 887 } | |
| 888 | |
| 889 @end | 889 @end |
| OLD | NEW |