1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ios/web/navigation/navigation_manager_impl.h"
7 #include "base/logging.h"
8 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
9 #import "ios/web/navigation/crw_session_controller.h"
10 #import "ios/web/navigation/crw_session_entry.h"
11 #include "ios/web/navigation/navigation_item_impl.h"
12 #include "ios/web/navigation/navigation_manager_delegate.h"
13 #import "ios/web/navigation/navigation_manager_facade_delegate.h"
14 #include "ios/web/public/load_committed_details.h"
15 #include "ios/web/public/navigation_item.h"
16 #include "ios/web/public/web_state/web_state.h"
17 #include "ui/base/page_transition_types.h"
21 // Checks whether or not two URL are an in-page navigation (differing only
23 bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) {
24 if (existing_url == new_url || !new_url.has_ref())
27 url::Replacements<char> replacements;
28 replacements.ClearRef();
29 return existing_url.ReplaceComponents(replacements) ==
30 new_url.ReplaceComponents(replacements);
33 } // anonymous namespace
37 NavigationManagerImpl::NavigationManagerImpl(
38 NavigationManagerDelegate* delegate,
39 BrowserState* browser_state)
40 : delegate_(delegate),
41 browser_state_(browser_state),
42 facade_delegate_(nullptr) {
43 DCHECK(browser_state_);
46 NavigationManagerImpl::~NavigationManagerImpl() {
47 // The facade layer should be deleted before this object.
48 DCHECK(!facade_delegate_);
50 [session_controller_ setNavigationManager:nullptr];
53 CRWSessionController* NavigationManagerImpl::GetSessionController() {
54 return session_controller_;
57 void NavigationManagerImpl::SetSessionController(
58 CRWSessionController* session_controller) {
59 session_controller_.reset([session_controller retain]);
60 [session_controller_ setNavigationManager:this];
63 void NavigationManagerImpl::InitializeSession(NSString* window_name,
66 int opener_navigation_index) {
67 SetSessionController([[[CRWSessionController alloc]
68 initWithWindowName:window_name
70 openedByDOM:opened_by_dom
71 openerNavigationIndex:opener_navigation_index
72 browserState:browser_state_] autorelease]);
75 void NavigationManagerImpl::ReplaceSessionHistory(
76 ScopedVector<web::NavigationItem> items,
78 SetSessionController([[[CRWSessionController alloc]
79 initWithNavigationItems:items.Pass()
80 currentIndex:current_index
81 browserState:browser_state_] autorelease]);
84 void NavigationManagerImpl::SetFacadeDelegate(
85 NavigationManagerFacadeDelegate* facade_delegate) {
86 facade_delegate_ = facade_delegate;
89 NavigationManagerFacadeDelegate* NavigationManagerImpl::GetFacadeDelegate()
91 return facade_delegate_;
95 void NavigationManagerImpl::OnNavigationItemChanged() {
97 facade_delegate_->OnNavigationItemChanged();
100 void NavigationManagerImpl::OnNavigationItemCommitted() {
101 LoadCommittedDetails details;
102 details.item = GetLastCommittedItem();
103 DCHECK(details.item);
104 details.previous_item_index = [session_controller_ previousNavigationIndex];
105 if (details.previous_item_index >= 0) {
106 DCHECK([session_controller_ previousEntry]);
107 details.previous_url =
108 [session_controller_ previousEntry].navigationItem->GetURL();
110 AreURLsInPageNavigation(details.previous_url, details.item->GetURL());
112 details.previous_url = GURL();
113 details.is_in_page = NO;
116 delegate_->OnNavigationItemCommitted(details);
118 if (facade_delegate_) {
119 facade_delegate_->OnNavigationItemCommitted(details.previous_item_index,
124 NavigationItem* NavigationManagerImpl::GetVisibleItem() const {
125 CRWSessionEntry* entry = [session_controller_ visibleEntry];
126 return [entry navigationItem];
129 NavigationItem* NavigationManagerImpl::GetPendingItem() const {
130 return [[session_controller_ pendingEntry] navigationItem];
133 void NavigationManagerImpl::DiscardNonCommittedItems() {
134 [session_controller_ discardNonCommittedEntries];
137 NavigationItem* NavigationManagerImpl::GetTransientItem() const {
138 return [[session_controller_ transientEntry] navigationItem];
141 NavigationItem* NavigationManagerImpl::GetLastCommittedItem() const {
142 CRWSessionEntry* entry = [session_controller_ lastCommittedEntry];
143 return [entry navigationItem];
146 NavigationItem* NavigationManagerImpl::GetItemAtIndex(size_t index) const {
147 NSArray* entries = [session_controller_ entries];
148 return index < entries.count ? [entries[index] navigationItem] : nullptr;
151 int NavigationManagerImpl::GetCurrentEntryIndex() const {
152 return [session_controller_ currentNavigationIndex];
155 int NavigationManagerImpl::GetLastCommittedEntryIndex() const {
156 if (![[session_controller_ entries] count])
158 return [session_controller_ currentNavigationIndex];
161 int NavigationManagerImpl::GetEntryCount() const {
162 return [[session_controller_ entries] count];
165 bool NavigationManagerImpl::RemoveEntryAtIndex(int index) {
166 if (index == GetLastCommittedEntryIndex() ||
167 index == GetPendingEntryIndex())
170 NSUInteger idx = static_cast<NSUInteger>(index);
171 NSArray* entries = [session_controller_ entries];
172 if (idx >= entries.count)
175 [session_controller_ removeEntryAtIndex:index];
179 NavigationItem* NavigationManagerImpl::GetLastUserItem() const {
180 CRWSessionEntry* entry = [session_controller_ lastUserEntry];
181 return [entry navigationItem];
184 NavigationItem* NavigationManagerImpl::GetPreviousItem() const {
185 CRWSessionEntry* entry = [session_controller_ previousEntry];
186 return [entry navigationItem];
189 int NavigationManagerImpl::GetPendingEntryIndex() const {
190 if ([session_controller_ hasPendingEntry])
191 return GetCurrentEntryIndex();
195 void NavigationManagerImpl::AddTransientURLRewriter(
196 BrowserURLRewriter::URLRewriter rewriter) {
198 if (!transient_url_rewriters_) {
199 transient_url_rewriters_.reset(
200 new std::vector<BrowserURLRewriter::URLRewriter>());
202 transient_url_rewriters_->push_back(rewriter);
205 scoped_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
206 NavigationManagerImpl::GetTransientURLRewriters() {
207 return transient_url_rewriters_.Pass();
210 void NavigationManagerImpl::RemoveTransientURLRewriters() {
211 transient_url_rewriters_.reset();
214 void NavigationManagerImpl::LoadURL(const GURL& url,
215 const web::Referrer& referrer,
216 ui::PageTransition type) {
217 WebState::OpenURLParams params(url, referrer, CURRENT_TAB, type, NO);
218 delegate_->GetWebState()->OpenURL(params);
221 bool NavigationManagerImpl::CanGoBack() const {
222 return [session_controller_ canGoBack];
225 bool NavigationManagerImpl::CanGoForward() const {
226 return [session_controller_ canGoForward];
229 void NavigationManagerImpl::GoBack() {
231 [session_controller_ goBack];
232 // Signal the delegate to load the old page.
233 delegate_->NavigateToPendingEntry();
237 void NavigationManagerImpl::GoForward() {
238 if (CanGoForward()) {
239 [session_controller_ goForward];
240 // Signal the delegate to load the new page.
241 delegate_->NavigateToPendingEntry();
245 std::vector<NavigationItem*> NavigationManagerImpl::GetItems() {
246 std::vector<NavigationItem*> items;
248 items.resize([session_controller_ entries].count);
249 for (CRWSessionEntry* entry in [session_controller_ entries]) {
250 items[i++] = entry.navigationItem;
255 BrowserState* NavigationManagerImpl::GetBrowserState() const {
256 return browser_state_;
259 WebState* NavigationManagerImpl::GetWebState() const {
260 return delegate_->GetWebState();
263 void NavigationManagerImpl::CopyState(
264 NavigationManagerImpl* navigation_manager) {
265 SetSessionController(
266 [[navigation_manager->GetSessionController() copy] autorelease]);