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

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

Issue 2944093002: Extract NavigationManagerImpl interface for navigation experiment. (Closed)
Patch Set: Patch for landing Created 3 years, 6 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
(Empty)
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.
4
5 #import "ios/web/navigation/navigation_manager_impl.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/logging.h"
12 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
13 #import "ios/web/navigation/crw_session_controller.h"
14 #import "ios/web/navigation/navigation_item_impl.h"
15 #import "ios/web/navigation/navigation_item_impl_list.h"
16 #import "ios/web/navigation/navigation_manager_delegate.h"
17 #include "ios/web/public/load_committed_details.h"
18 #import "ios/web/public/navigation_item.h"
19 #include "ios/web/public/reload_type.h"
20 #import "ios/web/public/web_client.h"
21 #import "ios/web/public/web_state/web_state.h"
22 #include "ui/base/page_transition_types.h"
23
24 #if !defined(__has_feature) || !__has_feature(objc_arc)
25 #error "This file requires ARC support."
26 #endif
27
28 namespace {
29
30 // Checks whether or not two URL are an in-page navigation (differing only
31 // in the fragment).
32 bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) {
33 if (existing_url == new_url || !new_url.has_ref())
34 return false;
35
36 return existing_url.EqualsIgnoringRef(new_url);
37 }
38
39 } // anonymous namespace
40
41 namespace web {
42
43 NavigationManager::WebLoadParams::WebLoadParams(const GURL& url)
44 : url(url),
45 transition_type(ui::PAGE_TRANSITION_LINK),
46 user_agent_override_option(UserAgentOverrideOption::INHERIT),
47 is_renderer_initiated(false),
48 post_data(nil) {}
49
50 NavigationManager::WebLoadParams::~WebLoadParams() {}
51
52 NavigationManager::WebLoadParams::WebLoadParams(const WebLoadParams& other)
53 : url(other.url),
54 referrer(other.referrer),
55 transition_type(other.transition_type),
56 user_agent_override_option(other.user_agent_override_option),
57 is_renderer_initiated(other.is_renderer_initiated),
58 extra_headers([other.extra_headers copy]),
59 post_data([other.post_data copy]) {}
60
61 NavigationManager::WebLoadParams& NavigationManager::WebLoadParams::operator=(
62 const WebLoadParams& other) {
63 url = other.url;
64 referrer = other.referrer;
65 is_renderer_initiated = other.is_renderer_initiated;
66 transition_type = other.transition_type;
67 user_agent_override_option = other.user_agent_override_option;
68 extra_headers.reset([other.extra_headers copy]);
69 post_data.reset([other.post_data copy]);
70
71 return *this;
72 }
73
74 NavigationManagerImpl::NavigationManagerImpl()
75 : delegate_(nullptr), browser_state_(nullptr) {}
76
77 NavigationManagerImpl::~NavigationManagerImpl() {
78 [session_controller_ setNavigationManager:nullptr];
79 }
80
81 void NavigationManagerImpl::SetDelegate(NavigationManagerDelegate* delegate) {
82 delegate_ = delegate;
83 }
84
85 void NavigationManagerImpl::SetBrowserState(BrowserState* browser_state) {
86 browser_state_ = browser_state;
87 [session_controller_ setBrowserState:browser_state];
88 }
89
90 void NavigationManagerImpl::SetSessionController(
91 CRWSessionController* session_controller) {
92 session_controller_.reset(session_controller);
93 [session_controller_ setNavigationManager:this];
94 }
95
96 void NavigationManagerImpl::InitializeSession() {
97 SetSessionController(
98 [[CRWSessionController alloc] initWithBrowserState:browser_state_]);
99 }
100
101 void NavigationManagerImpl::ReplaceSessionHistory(
102 std::vector<std::unique_ptr<web::NavigationItem>> items,
103 int lastCommittedItemIndex) {
104 SetSessionController([[CRWSessionController alloc]
105 initWithBrowserState:browser_state_
106 navigationItems:std::move(items)
107 lastCommittedItemIndex:lastCommittedItemIndex]);
108 }
109
110 void NavigationManagerImpl::OnNavigationItemsPruned(size_t pruned_item_count) {
111 delegate_->OnNavigationItemsPruned(pruned_item_count);
112 }
113
114 void NavigationManagerImpl::OnNavigationItemChanged() {
115 delegate_->OnNavigationItemChanged();
116 }
117
118 void NavigationManagerImpl::OnNavigationItemCommitted() {
119 LoadCommittedDetails details;
120 details.item = GetLastCommittedItem();
121 DCHECK(details.item);
122 details.previous_item_index = [session_controller_ previousItemIndex];
123 if (details.previous_item_index >= 0) {
124 DCHECK([session_controller_ previousItem]);
125 details.previous_url = [session_controller_ previousItem]->GetURL();
126 details.is_in_page =
127 AreURLsInPageNavigation(details.previous_url, details.item->GetURL());
128 } else {
129 details.previous_url = GURL();
130 details.is_in_page = NO;
131 }
132
133 delegate_->OnNavigationItemCommitted(details);
134 }
135
136 CRWSessionController* NavigationManagerImpl::GetSessionController() {
137 return session_controller_;
138 }
139
140 void NavigationManagerImpl::AddTransientItem(const GURL& url) {
141 [session_controller_ addTransientItemWithURL:url];
142
143 // TODO(crbug.com/676129): Transient item is only supposed to be added for
144 // pending non-app-specific loads, but pending item can be null because of the
145 // bug. The workaround should be removed once the bug is fixed.
146 NavigationItem* item = GetPendingItem();
147 if (!item)
148 item = GetLastCommittedNonAppSpecificItem();
149 DCHECK(item->GetUserAgentType() != UserAgentType::NONE);
150 GetTransientItem()->SetUserAgentType(item->GetUserAgentType());
151 }
152
153 void NavigationManagerImpl::AddPendingItem(
154 const GURL& url,
155 const web::Referrer& referrer,
156 ui::PageTransition navigation_type,
157 NavigationInitiationType initiation_type,
158 UserAgentOverrideOption user_agent_override_option) {
159 [session_controller_ addPendingItem:url
160 referrer:referrer
161 transition:navigation_type
162 initiationType:initiation_type
163 userAgentOverrideOption:user_agent_override_option];
164
165 // Set the user agent type for web URLs.
166 NavigationItem* pending_item = GetPendingItem();
167 if (!pending_item)
168 return;
169
170 // |user_agent_override_option| must be INHERIT if |pending_item|'s
171 // UserAgentType is NONE, as requesting a desktop or mobile user agent should
172 // be disabled for app-specific URLs.
173 DCHECK(pending_item->GetUserAgentType() != UserAgentType::NONE ||
174 user_agent_override_option == UserAgentOverrideOption::INHERIT);
175
176 // Newly created pending items are created with UserAgentType::NONE for native
177 // pages or UserAgentType::MOBILE for non-native pages. If the pending item's
178 // URL is non-native, check which user agent type it should be created with
179 // based on |user_agent_override_option|.
180 DCHECK_NE(UserAgentType::DESKTOP, pending_item->GetUserAgentType());
181 if (pending_item->GetUserAgentType() == UserAgentType::NONE)
182 return;
183
184 switch (user_agent_override_option) {
185 case UserAgentOverrideOption::DESKTOP:
186 pending_item->SetUserAgentType(UserAgentType::DESKTOP);
187 break;
188 case UserAgentOverrideOption::MOBILE:
189 pending_item->SetUserAgentType(UserAgentType::MOBILE);
190 break;
191 case UserAgentOverrideOption::INHERIT: {
192 // Propagate the last committed non-native item's UserAgentType if there
193 // is one, otherwise keep the default value, which is mobile.
194 NavigationItem* last_non_native_item =
195 GetLastCommittedNonAppSpecificItem();
196 DCHECK(!last_non_native_item ||
197 last_non_native_item->GetUserAgentType() != UserAgentType::NONE);
198 if (last_non_native_item) {
199 pending_item->SetUserAgentType(
200 last_non_native_item->GetUserAgentType());
201 }
202 break;
203 }
204 }
205 }
206
207 void NavigationManagerImpl::CommitPendingItem() {
208 [session_controller_ commitPendingItem];
209 }
210
211 BrowserState* NavigationManagerImpl::GetBrowserState() const {
212 return browser_state_;
213 }
214
215 WebState* NavigationManagerImpl::GetWebState() const {
216 return delegate_->GetWebState();
217 }
218
219 NavigationItem* NavigationManagerImpl::GetVisibleItem() const {
220 return [session_controller_ visibleItem];
221 }
222
223 NavigationItem* NavigationManagerImpl::GetLastCommittedItem() const {
224 return [session_controller_ lastCommittedItem];
225 }
226
227 NavigationItem* NavigationManagerImpl::GetPendingItem() const {
228 return [session_controller_ pendingItem];
229 }
230
231 NavigationItem* NavigationManagerImpl::GetTransientItem() const {
232 return [session_controller_ transientItem];
233 }
234
235 void NavigationManagerImpl::DiscardNonCommittedItems() {
236 [session_controller_ discardNonCommittedItems];
237 }
238
239 void NavigationManagerImpl::LoadURLWithParams(
240 const NavigationManager::WebLoadParams& params) {
241 delegate_->LoadURLWithParams(params);
242 }
243
244 void NavigationManagerImpl::AddTransientURLRewriter(
245 BrowserURLRewriter::URLRewriter rewriter) {
246 DCHECK(rewriter);
247 if (!transient_url_rewriters_) {
248 transient_url_rewriters_.reset(
249 new std::vector<BrowserURLRewriter::URLRewriter>());
250 }
251 transient_url_rewriters_->push_back(rewriter);
252 }
253
254 int NavigationManagerImpl::GetItemCount() const {
255 return [session_controller_ items].size();
256 }
257
258 NavigationItem* NavigationManagerImpl::GetItemAtIndex(size_t index) const {
259 return [session_controller_ itemAtIndex:index];
260 }
261
262 int NavigationManagerImpl::GetIndexOfItem(
263 const web::NavigationItem* item) const {
264 return [session_controller_ indexOfItem:item];
265 }
266
267 int NavigationManagerImpl::GetPendingItemIndex() const {
268 if (GetPendingItem()) {
269 if ([session_controller_ pendingItemIndex] != -1) {
270 return [session_controller_ pendingItemIndex];
271 }
272 // TODO(crbug.com/665189): understand why last committed item index is
273 // returned here.
274 return GetLastCommittedItemIndex();
275 }
276 return -1;
277 }
278
279 int NavigationManagerImpl::GetLastCommittedItemIndex() const {
280 if (GetItemCount() == 0)
281 return -1;
282 return [session_controller_ lastCommittedItemIndex];
283 }
284
285 bool NavigationManagerImpl::RemoveItemAtIndex(int index) {
286 if (index == GetLastCommittedItemIndex() || index == GetPendingItemIndex())
287 return false;
288
289 if (index < 0 || index >= GetItemCount())
290 return false;
291
292 [session_controller_ removeItemAtIndex:index];
293 return true;
294 }
295
296 bool NavigationManagerImpl::CanGoBack() const {
297 return CanGoToOffset(-1);
298 }
299
300 bool NavigationManagerImpl::CanGoForward() const {
301 return CanGoToOffset(1);
302 }
303
304 bool NavigationManagerImpl::CanGoToOffset(int offset) const {
305 int index = GetIndexForOffset(offset);
306 return 0 <= index && index < GetItemCount();
307 }
308
309 void NavigationManagerImpl::GoBack() {
310 delegate_->GoToIndex(GetIndexForOffset(-1));
311 }
312
313 void NavigationManagerImpl::GoForward() {
314 delegate_->GoToIndex(GetIndexForOffset(1));
315 }
316
317 void NavigationManagerImpl::GoToIndex(int index) {
318 delegate_->GoToIndex(index);
319 }
320
321 NavigationItemList NavigationManagerImpl::GetBackwardItems() const {
322 return [session_controller_ backwardItems];
323 }
324
325 NavigationItemList NavigationManagerImpl::GetForwardItems() const {
326 return [session_controller_ forwardItems];
327 }
328
329 void NavigationManagerImpl::Reload(ReloadType reload_type,
330 bool check_for_reposts) {
331 if (!GetTransientItem() && !GetPendingItem() && !GetLastCommittedItem())
332 return;
333
334 // Reload with ORIGINAL_REQUEST_URL type should reload with the original
335 // request url of the transient item, or pending item if transient doesn't
336 // exist, or last committed item if both of them don't exist. The reason is
337 // that a server side redirect may change the item's url.
338 // For example, the user visits www.chromium.org and is then redirected
339 // to m.chromium.org, when the user wants to refresh the page with a different
340 // configuration (e.g. user agent), the user would be expecting to visit
341 // www.chromium.org instead of m.chromium.org.
342 if (reload_type == web::ReloadType::ORIGINAL_REQUEST_URL) {
343 NavigationItem* reload_item = nullptr;
344 if (GetTransientItem())
345 reload_item = GetTransientItem();
346 else if (GetPendingItem())
347 reload_item = GetPendingItem();
348 else
349 reload_item = GetLastCommittedItem();
350 DCHECK(reload_item);
351
352 reload_item->SetURL(reload_item->GetOriginalRequestURL());
353 }
354
355 delegate_->Reload();
356 }
357
358 void NavigationManagerImpl::CopyStateFromAndPrune(
359 const NavigationManager* manager) {
360 DCHECK(manager);
361 CRWSessionController* other_session =
362 static_cast<const NavigationManagerImpl*>(manager)->session_controller_;
363 [session_controller_ copyStateFromSessionControllerAndPrune:other_session];
364 }
365
366 bool NavigationManagerImpl::CanPruneAllButLastCommittedItem() const {
367 return [session_controller_ canPruneAllButLastCommittedItem];
368 }
369
370 std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
371 NavigationManagerImpl::GetTransientURLRewriters() {
372 return std::move(transient_url_rewriters_);
373 }
374
375 void NavigationManagerImpl::RemoveTransientURLRewriters() {
376 transient_url_rewriters_.reset();
377 }
378
379 int NavigationManagerImpl::GetIndexForOffset(int offset) const {
380 int result = [session_controller_ pendingItemIndex] == -1
381 ? GetLastCommittedItemIndex()
382 : static_cast<int>([session_controller_ pendingItemIndex]);
383
384 if (offset < 0) {
385 if (GetTransientItem() && [session_controller_ pendingItemIndex] == -1) {
386 // Going back from transient item that added to the end navigation stack
387 // is a matter of discarding it as there is no need to move navigation
388 // index back.
389 offset++;
390 }
391
392 while (offset < 0 && result > 0) {
393 // To stop the user getting 'stuck' on redirecting pages they weren't
394 // even aware existed, it is necessary to pass over pages that would
395 // immediately result in a redirect (the item *before* the redirected
396 // page).
397 while (result > 0 && IsRedirectItemAtIndex(result)) {
398 --result;
399 }
400 --result;
401 ++offset;
402 }
403 // Result may be out of bounds, so stop trying to skip redirect items and
404 // simply add the remainder.
405 result += offset;
406 if (result > GetItemCount() /* overflow */)
407 result = INT_MIN;
408 } else if (offset > 0) {
409 while (offset > 0 && result < GetItemCount()) {
410 ++result;
411 --offset;
412 // As with going back, skip over redirects.
413 while (result + 1 < GetItemCount() && IsRedirectItemAtIndex(result + 1)) {
414 ++result;
415 }
416 }
417 // Result may be out of bounds, so stop trying to skip redirect items and
418 // simply add the remainder.
419 result += offset;
420 if (result < 0 /* overflow */)
421 result = INT_MAX;
422 }
423
424 return result;
425 }
426
427 bool NavigationManagerImpl::IsRedirectItemAtIndex(int index) const {
428 DCHECK_GE(index, 0);
429 DCHECK_LT(index, GetItemCount());
430 ui::PageTransition transition = GetItemAtIndex(index)->GetTransitionType();
431 return transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK;
432 }
433
434 NavigationItem* NavigationManagerImpl::GetLastCommittedNonAppSpecificItem()
435 const {
436 int index = GetLastCommittedItemIndex();
437 if (index == -1)
438 return nullptr;
439 WebClient* client = GetWebClient();
440 const ScopedNavigationItemImplList& items = [session_controller_ items];
441 while (index >= 0) {
442 NavigationItem* item = items[index--].get();
443 if (!client->IsAppSpecificURL(item->GetVirtualURL()))
444 return item;
445 }
446 return nullptr;
447 }
448
449 } // namespace web
OLDNEW
« no previous file with comments | « ios/web/navigation/navigation_manager_impl.h ('k') | ios/web/navigation/navigation_manager_impl_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698