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/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.h"
6
7#include "base/check_op.h"
8#include "base/ios/ios_util.h"
9#import "ios/chrome/browser/ui/fullscreen/fullscreen_content_adjustment_util.h"
10#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
11#import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h"
12#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
13#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.h"
14#import "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h"
15#include "ios/chrome/browser/ui/util/ui_util.h"
16#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
17#import "ios/public/provider/chrome/browser/ui/fullscreen_provider.h"
18#include "ios/web/common/url_util.h"
19#import "ios/web/public/navigation/navigation_context.h"
20#import "ios/web/public/navigation/navigation_item.h"
21#import "ios/web/public/navigation/navigation_manager.h"
22#include "ios/web/public/security/ssl_status.h"
23#import "ios/web/public/ui/crw_web_view_proxy.h"
24#import "ios/web/public/ui/page_display_state.h"
25#import "ios/web/public/web_state.h"
26
27#if !defined(__has_feature) || !__has_feature(objc_arc)
28#error "This file requires ARC support."
29#endif
30
31FullscreenWebStateObserver::FullscreenWebStateObserver(
32    FullscreenController* controller,
33    FullscreenModel* model,
34    FullscreenMediator* mediator)
35    : controller_(controller),
36      model_(model),
37      mediator_(mediator),
38      web_view_proxy_observer_([[FullscreenWebViewProxyObserver alloc]
39          initWithModel:model_
40               mediator:mediator]) {
41  DCHECK(controller_);
42  DCHECK(model_);
43}
44
45FullscreenWebStateObserver::~FullscreenWebStateObserver() = default;
46
47void FullscreenWebStateObserver::SetWebState(web::WebState* web_state) {
48  if (web_state_ == web_state)
49    return;
50  if (web_state_)
51    web_state_->RemoveObserver(this);
52  web_state_ = web_state;
53  if (web_state_) {
54    web_state_->AddObserver(this);
55    // The toolbar should be visible whenever the current tab changes.
56    model_->ResetForNavigation();
57  }
58  mediator_->SetWebState(web_state);
59  // Update the scroll view replacement handler's proxy.
60  web_view_proxy_observer_.proxy =
61      web_state_ ? web_state_->GetWebViewProxy() : nil;
62}
63
64void FullscreenWebStateObserver::WasShown(web::WebState* web_state) {
65  // Show the toolbars when a WebState is shown.
66  model_->ResetForNavigation();
67}
68
69void FullscreenWebStateObserver::DidFinishNavigation(
70    web::WebState* web_state,
71    web::NavigationContext* navigation_context) {
72  const GURL& navigation_url = navigation_context->GetUrl();
73  bool url_changed = web::GURLByRemovingRefFromGURL(navigation_url) !=
74                     web::GURLByRemovingRefFromGURL(last_navigation_url_);
75  last_navigation_url_ = navigation_url;
76
77  // Due to limitations in WKWebView's rendering, different MIME types must be
78  // inset using different techniques:
79  // - PDFs need to be inset using the scroll view's |contentInset| property or
80  //   the floating page indicator is laid out incorrectly.
81  // - For normal pages, using |contentInset| breaks the layout of fixed-
82  //   position DOM elements, so top padding must be accomplished by updating
83  //   the WKWebView's frame.
84  bool is_pdf = web_state->GetContentsMimeType() == "application/pdf";
85  id<CRWWebViewProxy> web_view_proxy = web_state->GetWebViewProxy();
86  web_view_proxy.shouldUseViewContentInset = is_pdf;
87
88  model_->SetResizesScrollView(!is_pdf && !ios::GetChromeBrowserProvider()
89                                               ->GetFullscreenProvider()
90                                               ->IsInitialized());
91
92  // Only reset the model for document-changing navigations or same-document
93  // navigations that update the visible URL.
94  if (!navigation_context->IsSameDocument() || url_changed)
95    model_->ResetForNavigation();
96}
97
98void FullscreenWebStateObserver::DidStartLoading(web::WebState* web_state) {
99  // This is done to show the toolbar when navigating to a page that is
100  // considered as being in the SameDocument by the NavigationContext, so the
101  // toolbar isn't shown in the DidFinishNavigation. For example this is
102  // needed to load AMP pages from Google Search Result Page.
103  controller_->ExitFullscreen();
104}
105
106void FullscreenWebStateObserver::WebStateDestroyed(web::WebState* web_state) {
107  DCHECK_EQ(web_state, web_state_);
108  SetWebState(nullptr);
109}
110