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

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

Issue 2957163002: [Navigation Experiment] Add WKBasedNavigationManagerImpl. (Closed)
Patch Set: Created 3 years, 5 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 2017 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/wk_based_navigation_manager_impl.h"
6
Eugene But (OOO till 7-30) 2017/06/27 22:02:00 FYI: I did not look at this file, which I guess is
danyao 2017/06/28 22:11:04 Thanks. I've stripped down this file to just a ske
7 #include <memory>
8
9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h"
11 #import "ios/web/navigation/navigation_item_impl.h"
12 #import "ios/web/navigation/navigation_manager_delegate.h"
13 #import "ios/web/navigation/web_view_navigation_proxy.h"
14 #include "ios/web/public/load_committed_details.h"
15 #import "ios/web/public/navigation_item.h"
16 #import "ios/web/public/web_client.h"
17 #import "net/base/mac/url_conversions.h"
18
19 #if !defined(__has_feature) || !__has_feature(objc_arc)
20 #error "This file requires ARC support."
21 #endif
22
23 @class CRWSessionController;
24
25 namespace {
26
27 // Checks whether or not two URL are an in-page navigation (differing only
28 // in the fragment).
29 bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) {
30 if (existing_url == new_url || !new_url.has_ref())
31 return false;
32
33 return existing_url.EqualsIgnoringRef(new_url);
34 }
35
36 web::WebViewNavigationProxy* GetWebViewOrDie(
37 web::NavigationManagerDelegate* delegate) {
38 DCHECK(delegate);
39 web::WebViewNavigationProxy* proxy = delegate->GetWebViewNavigationProxy();
40 DCHECK(proxy);
41 return proxy;
42 }
43
44 } // namespace
45
46 namespace web {
47
48 WKBasedNavigationManagerImpl::WKBasedNavigationManagerImpl()
49 : delegate_(nullptr), browser_state_(nullptr) {}
50
51 WKBasedNavigationManagerImpl::~WKBasedNavigationManagerImpl() {}
52
53 void WKBasedNavigationManagerImpl::SetDelegate(
54 NavigationManagerDelegate* delegate) {
55 delegate_ = delegate;
56 }
57
58 void WKBasedNavigationManagerImpl::SetBrowserState(
59 BrowserState* browser_state) {
60 browser_state_ = browser_state;
61 }
62
63 void WKBasedNavigationManagerImpl::SetSessionController(
64 CRWSessionController* session_controller) {}
65
66 void WKBasedNavigationManagerImpl::InitializeSession() {}
67
68 void WKBasedNavigationManagerImpl::ReplaceSessionHistory(
69 std::vector<std::unique_ptr<NavigationItem>> items,
70 int current_index) {
71 DLOG(WARNING) << "ReplaceSessionHistory needs to be implemented.";
72 }
73
74 void WKBasedNavigationManagerImpl::OnNavigationItemsPruned(
75 size_t pruned_item_count) {
76 delegate_->OnNavigationItemsPruned(pruned_item_count);
77 }
78
79 void WKBasedNavigationManagerImpl::OnNavigationItemChanged() {
80 delegate_->OnNavigationItemChanged();
81 }
82
83 void WKBasedNavigationManagerImpl::OnNavigationItemCommitted() {
84 LoadCommittedDetails details;
85 details.item = GetLastCommittedItem();
86 DCHECK(details.item);
87 details.previous_item_index = GetPreviousItemIndex();
88 if (details.previous_item_index >= 0) {
89 NavigationItem* previous_item = GetItemAtIndex(details.previous_item_index);
90 DCHECK(previous_item);
91 details.previous_url = previous_item->GetURL();
92 details.is_in_page =
93 AreURLsInPageNavigation(details.previous_url, details.item->GetURL());
94 } else {
95 details.previous_url = GURL();
96 details.is_in_page = NO;
97 }
98
99 delegate_->OnNavigationItemCommitted(details);
100 }
101
102 CRWSessionController* WKBasedNavigationManagerImpl::GetSessionController()
103 const {
104 return nullptr;
105 }
106
107 void WKBasedNavigationManagerImpl::AddTransientItem(const GURL& url) {
108 DLOG(WARNING) << "AddTransientItem needs to be implemented.";
109 }
110
111 void WKBasedNavigationManagerImpl::AddPendingItem(
112 const GURL& url,
113 const web::Referrer& referrer,
114 ui::PageTransition navigation_type,
115 NavigationInitiationType initiation_type,
116 UserAgentOverrideOption user_agent_override_option) {
117 // This is a start of a new navigation. Discard all uncommitted items.
118 DiscardNonCommittedItems();
119
120 // TODO(danyao):
121 // - share code with CRWSessionController |itemWithURL|
122 // - decide if shouldCreatePendingItemWithURL check applies: basically
123 // WKBasedNavigationManager no longer has the responsibility to distinguish
124 // between history navigation vs. new navigation. So perhaps we can always
125 // create a pending item.
126 GURL loaded_url(url);
127 bool urlWasRewritten = false;
128 if (transient_url_rewriters_) {
129 urlWasRewritten = BrowserURLRewriter::RewriteURLWithWriters(
130 &loaded_url, GetBrowserState(), *transient_url_rewriters_);
131 }
132
133 if (!urlWasRewritten) {
134 BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary(&loaded_url,
135 GetBrowserState());
136 }
137
138 if (initiation_type == NavigationInitiationType::RENDERER_INITIATED &&
139 loaded_url != url && GetWebClient()->IsAppSpecificURL(loaded_url)) {
140 bool lastCommittedURLIsAppSpecific =
141 GetLastCommittedItem() &&
142 GetWebClient()->IsAppSpecificURL(GetLastCommittedItem()->GetURL());
143
144 if (!lastCommittedURLIsAppSpecific) {
145 // The URL should not be changed to app-specific URL if the load was
146 // renderer-initiated requested by non app-specific URL. Pages with
147 // app-specific URLs have elevated privileges and should not be allowed
148 // to open app-specific URLs.
149 loaded_url = url;
150 }
151 }
152
153 pending_item_ = base::MakeUnique<NavigationItemImpl>();
154 pending_item_->SetOriginalRequestURL(loaded_url);
155 pending_item_->SetURL(loaded_url);
156 pending_item_->SetReferrer(referrer);
157 pending_item_->SetTransitionType(navigation_type);
158 pending_item_->SetNavigationInitiationType(initiation_type);
159 if (GetWebClient()->IsAppSpecificURL(loaded_url)) {
160 pending_item_->SetUserAgentType(UserAgentType::NONE);
161 }
162 }
163
164 void WKBasedNavigationManagerImpl::CommitPendingItem() {
165 // Add pending item to the end of the list. Make sure that
166 // committed_navigation_items_ are in sync with WKWebView.
167 int last_committed_index = GetLastCommittedItemIndex();
168 DCHECK(last_committed_index >= -1);
169 size_t commit_index = last_committed_index + 1;
170 if (commit_index == committed_navigation_items_.size()) {
171 committed_navigation_items_.push_back(std::move(pending_item_));
172 } else {
173 committed_navigation_items_[commit_index] = std::move(pending_item_);
174 committed_navigation_items_.resize(commit_index + 1);
175 }
176
177 SyncNavigationItems();
178
179 // Commiting a pending item invalidates both transient item and pending item.
180 DiscardNonCommittedItems();
181 }
182
183 int WKBasedNavigationManagerImpl::GetIndexForOffset(int offset) const {
184 // Use cases:
185 // - CRWWebController: determines which entry goDelta should land on
186
187 // TODO(danyao): take transient item into account
188 return GetLastCommittedItemIndex() + offset;
189 }
190
191 BrowserState* WKBasedNavigationManagerImpl::GetBrowserState() const {
192 return browser_state_;
193 }
194
195 WebState* WKBasedNavigationManagerImpl::GetWebState() const {
196 return delegate_->GetWebState();
197 }
198
199 NavigationItem* WKBasedNavigationManagerImpl::GetVisibleItem() const {
200 // Transient item if one exists
201 // Pending item for new (non-history), browser-initiated navigation
202 if (transient_item_.get()) {
203 return transient_item_.get();
204 }
205
206 // TODO(danyao): check pending item
207 return GetLastCommittedItem();
208 }
209
210 NavigationItem* WKBasedNavigationManagerImpl::GetLastCommittedItem() const {
211 SyncNavigationItems();
212 int last_committed_index = GetLastCommittedItemIndex();
213 if (last_committed_index == -1) {
214 return nullptr;
215 }
216 return GetItemAtIndex(static_cast<size_t>(last_committed_index));
217 }
218
219 NavigationItem* WKBasedNavigationManagerImpl::GetPendingItem() const {
220 return pending_item_.get();
221 }
222
223 NavigationItem* WKBasedNavigationManagerImpl::GetTransientItem() const {
224 return transient_item_.get();
225 }
226
227 void WKBasedNavigationManagerImpl::DiscardNonCommittedItems() {
228 // WKWebView should handle this.
229 pending_item_.reset();
230 transient_item_.reset();
231 }
232
233 void WKBasedNavigationManagerImpl::LoadURLWithParams(
234 const NavigationManager::WebLoadParams&) {
235 DLOG(WARNING) << "LoadURLWithParams needs to be implemented.";
236 }
237
238 // TODO(danyao): move this to NavigationManagerImpl to reduce duplication
239 // between legacy and wk-based
240 void WKBasedNavigationManagerImpl::AddTransientURLRewriter(
241 BrowserURLRewriter::URLRewriter rewriter) {
242 DCHECK(rewriter);
243 if (!transient_url_rewriters_) {
244 transient_url_rewriters_.reset(
245 new std::vector<BrowserURLRewriter::URLRewriter>());
246 }
247 transient_url_rewriters_->push_back(rewriter);
248 }
249
250 int WKBasedNavigationManagerImpl::GetItemCount() const {
251 WebViewNavigationProxy* proxy = delegate_->GetWebViewNavigationProxy();
252 if (proxy) {
253 NSUInteger count_current_page = proxy->GetCurrentItem() ? 1 : 0;
254 return (int)(proxy->GetBackList().count + count_current_page +
255 proxy->GetForwardList().count);
256 }
257
258 // If WebView has not been created, it's fair to say navigation has 0 item.
259 return 0;
260 }
261
262 NavigationItem* WKBasedNavigationManagerImpl::GetItemAtIndex(
263 size_t index) const {
264 // TODO(danyao): figure out how transient item fits in. Also this may result
265 // in dangling pointer if SyncNavigationItems are called after this.
266 return GetNavigationItemImplAtIndex(index);
267 }
268
269 int WKBasedNavigationManagerImpl::GetIndexOfItem(
270 const NavigationItem* item) const {
271 DLOG(WARNING) << "GetIndexOfItem needs to be implemented.";
272 return -1;
273 }
274
275 int WKBasedNavigationManagerImpl::GetPendingItemIndex() const {
276 // TODO(danyao): can we define pending item as only new navigation in main
277 // frame?
278 return -1;
279 }
280
281 int WKBasedNavigationManagerImpl::GetLastCommittedItemIndex() const {
282 WebViewNavigationProxy* proxy = delegate_->GetWebViewNavigationProxy();
283
284 // If web view is empty (i.e. currentItem = nil, backList = []), return -1
285 // If web view is not empty, return the index of the current item.
286 if (proxy && proxy->GetCurrentItem()) {
287 return static_cast<int>(proxy->GetBackList().count);
288 }
289 return -1;
290 }
291
292 bool WKBasedNavigationManagerImpl::RemoveItemAtIndex(int index) {
293 DLOG(WARNING) << "RemoveItemAtIndex needs to be implemented.";
294 return true;
295 }
296
297 bool WKBasedNavigationManagerImpl::CanGoBack() const {
298 WebViewNavigationProxy* proxy = delegate_->GetWebViewNavigationProxy();
299 return proxy && proxy->CanGoBack();
300 ;
301 }
302
303 bool WKBasedNavigationManagerImpl::CanGoForward() const {
304 WebViewNavigationProxy* proxy = delegate_->GetWebViewNavigationProxy();
305 return proxy && proxy->CanGoForward();
306 ;
307 }
308
309 bool WKBasedNavigationManagerImpl::CanGoToOffset(int offset) const {
310 int index = GetIndexForOffset(offset);
311 return index >= 0 && index < GetItemCount();
312 }
313
314 void WKBasedNavigationManagerImpl::GoBack() {
315 // TODO(danyao): deal with the returned WKNavigation.
316 GetWebViewOrDie(delegate_)->GoBack();
317 }
318
319 void WKBasedNavigationManagerImpl::GoForward() {
320 // TODO(danyao): deal with the returned WKNavigation.
321 GetWebViewOrDie(delegate_)->GoForward();
322 }
323
324 void WKBasedNavigationManagerImpl::GoToIndex(int index) {
325 DLOG(WARNING) << "GoToIndex needs to be implemented.";
326 }
327
328 void WKBasedNavigationManagerImpl::Reload(ReloadType reload_type,
329 bool check_for_reposts) {
330 DLOG(WARNING) << "Reload needs to be implemented.";
331 }
332
333 NavigationItemList WKBasedNavigationManagerImpl::GetBackwardItems() const {
334 SyncNavigationItems();
335 int last_committed_index = GetLastCommittedItemIndex();
336 if (last_committed_index == -1) {
337 return NavigationItemList();
338 } else {
339 // TODO(danyao): this can potentially lead to dangling pointers if
340 // SyncNavigationItems() is called while the caller still has access to this
341 // object.
342 NavigationItemList back_items(last_committed_index);
343 for (size_t index = 0; index < static_cast<size_t>(last_committed_index);
344 index++) {
345 back_items[index] = GetItemAtIndex(index);
346 }
347 return back_items;
348 }
349 }
350
351 NavigationItemList WKBasedNavigationManagerImpl::GetForwardItems() const {
352 SyncNavigationItems();
353 int last_committed_index = GetLastCommittedItemIndex();
354 DCHECK(last_committed_index >= -1);
355
356 NavigationItemList forward_items;
357 for (size_t index = last_committed_index + 1;
358 index < committed_navigation_items_.size(); index++) {
359 forward_items.push_back(GetItemAtIndex(index));
360 }
361
362 return forward_items;
363 }
364
365 void WKBasedNavigationManagerImpl::CopyStateFromAndPrune(
366 const NavigationManager* source) {
367 DLOG(WARNING) << "CopyStateFromAndPrune needs to be implemented.";
368 }
369
370 bool WKBasedNavigationManagerImpl::CanPruneAllButLastCommittedItem() const {
371 DLOG(WARNING) << "CanPruneAllButLastCommittedItem needs to be implemented.";
372 return true;
373 }
374
375 void WKBasedNavigationManagerImpl::RemoveTransientURLRewriters() {
376 transient_url_rewriters_.reset();
377 }
378
379 std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
380 WKBasedNavigationManagerImpl::GetTransientURLRewriters() {
381 return std::move(transient_url_rewriters_);
382 };
383
384 // NavigationManagerImpl methods used by SessionStorageBuilder.
385 NavigationItemImpl* WKBasedNavigationManagerImpl::GetNavigationItemImplAtIndex(
386 size_t index) const {
387 if (index < committed_navigation_items_.size()) {
388 return committed_navigation_items_[index].get();
389 }
390 return nullptr;
391 }
392
393 int WKBasedNavigationManagerImpl::GetPreviousItemIndex() const {
394 // TODO(danyao): try not to support this method
395 return GetIndexForOffset(-1);
396 }
397
398 bool isEquivalent(const NavigationItemImpl* navigation_item,
399 const WKBackForwardListItem* wk_item) {
400 DCHECK(navigation_item);
401 DCHECK(wk_item);
402
403 return navigation_item->GetURL() == net::GURLWithNSURL(wk_item.URL);
404 }
405
406 const WKBackForwardListItem* GetItemAtAbsoluteIndex(
407 size_t index,
408 const WebViewNavigationProxy* proxy) {
409 size_t back_list_size = static_cast<size_t>(proxy->GetBackList().count);
410 if (index == back_list_size) {
411 return proxy->GetCurrentItem();
412 } else if (index < back_list_size) {
413 return proxy->GetItemAtOffset(index - back_list_size);
414 } else {
415 return proxy->GetItemAtOffset(index - back_list_size - 1);
416 }
417 }
418
419 // Backfill NavigationItemImpls for navigations that happened in the rendere
420 // that did not notify the embedder. Usually these are navigation that results
421 // from scripts or iframe navigation.
422 // TODO(danyao): share code with CRWSessionController |itemWithURL|
423 std::unique_ptr<NavigationItemImpl> NavigationItemFromWKItem(
424 const WKBackForwardListItem* wk_item,
425 const WKBackForwardListItem* prev_wk_item) {
426 auto item = base::MakeUnique<NavigationItemImpl>();
427 GURL url = net::GURLWithNSURL(wk_item.URL);
428 item->SetOriginalRequestURL(url);
429 item->SetURL(url);
430
431 if (prev_wk_item) {
432 item->SetReferrer(Referrer(net::GURLWithNSURL(prev_wk_item.URL),
433 ReferrerPolicy::ReferrerPolicyDefault));
434 }
435
436 // Only renderer-initiated navigation items will end up here because if the
437 // navigation was user-initiated, the item would have been created via
438 // AddPendingItem.
439 item->SetNavigationInitiationType(
440 web::NavigationInitiationType::RENDERER_INITIATED);
441 if (web::GetWebClient()->IsAppSpecificURL(url)) {
442 item->SetUserAgentType(web::UserAgentType::NONE);
443 }
444
445 // Since this is a renderer-initiated navigation, our best guess is that it's
446 // a link transition.
447 item->SetTransitionType(ui::PageTransition::PAGE_TRANSITION_LINK);
448
449 return item;
450 }
451
452 // TODO(danyao): remove const qualifier
453 // Maintains navigation_items_ invariants:
454 // 1) committed_navigation_items_.size() == GetItemCount() == backList.count +
455 // forwardList.count + currentItem ? 1 : 0
456 //
457 bool WKBasedNavigationManagerImpl::SyncNavigationItems() const {
458 WebViewNavigationProxy* proxy = delegate_->GetWebViewNavigationProxy();
459 if (!proxy) {
460 bool is_changed = !committed_navigation_items_.empty();
461 committed_navigation_items_.clear();
462 return is_changed;
463 }
464
465 size_t wk_history_length = proxy->GetBackList().count +
466 (proxy->GetCurrentItem() ? 1 : 0) +
467 proxy->GetForwardList().count;
468 size_t num_equivalent_items =
469 std::min(committed_navigation_items_.size(), wk_history_length);
470
471 for (size_t index = 0;
472 index < committed_navigation_items_.size() && index < wk_history_length;
473 index++) {
474 if (!isEquivalent(committed_navigation_items_[index].get(),
475 GetItemAtAbsoluteIndex(index, proxy))) {
476 num_equivalent_items = index;
477 break;
478 }
479 }
480
481 if (num_equivalent_items == committed_navigation_items_.size() &&
482 num_equivalent_items == wk_history_length) {
483 return false;
484 }
485
486 // Now we need to rebuild everything beyond this point
487 committed_navigation_items_.resize(wk_history_length);
488 const WKBackForwardListItem* prev_wk_item = nullptr;
489 for (size_t index = num_equivalent_items; index < wk_history_length;
490 index++) {
491 const WKBackForwardListItem* wk_item = GetItemAtAbsoluteIndex(index, proxy);
492 committed_navigation_items_[index] =
493 NavigationItemFromWKItem(wk_item, prev_wk_item);
494 prev_wk_item = wk_item;
495 }
496
497 return true;
498 }
499
500 } // namespace web
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698