Commit 66de93d3 authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

[iOS] Move the fullscreen frame change to the fullscreen mediator

This CL changes the way the frame of the WebView is changed, moving the
implementation to the FullscreenMediator.

Bug: 836730
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: Idc8b339ea61d4024268549789f18ec10c64f0d54
Reviewed-on: https://chromium-review.googlesource.com/1194226
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarKurt Horimoto <kkhorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587601}
parent 4bb6d652
......@@ -378,6 +378,9 @@ const flags_ui::FeatureEntry kFeatureEntries[] = {
flag_descriptions::kSyncSupportSecondaryAccountDescription,
flags_ui::kOsIos,
FEATURE_VALUE_TYPE(switches::kSyncSupportSecondaryAccount)},
{"out-of-web-fullscreen", flag_descriptions::kOutOfWebFullscreenName,
flag_descriptions::kOutOfWebFullscreenDescription, flags_ui::kOsIos,
FEATURE_VALUE_TYPE(web::features::kOutOfWebFullscreen)},
};
// Add all switches from experimental flags to |command_line|.
......
......@@ -204,6 +204,11 @@ const char kOmniboxUIElideSuggestionUrlAfterHostDescription[] =
"Elides the path, query, and ref of suggested URLs in the omnibox "
"dropdown.";
const char kOutOfWebFullscreenName[] = "Fullscreen implementation out of web";
const char kOutOfWebFullscreenDescription[] =
"Use the fullscreen implementation living outside of web. Disable the one "
"in web.";
const char kPasswordExportName[] = "Password Export";
const char kPasswordExportDescription[] =
"Enables password exporting functionality in password settings.";
......
......@@ -166,6 +166,11 @@ extern const char kNewPasswordFormParsingDescription[];
extern const char kOmniboxUIElideSuggestionUrlAfterHostName[];
extern const char kOmniboxUIElideSuggestionUrlAfterHostDescription[];
// Title and description for the flag to control the out of web implementation
// of fullscreen.
extern const char kOutOfWebFullscreenName[];
extern const char kOutOfWebFullscreenDescription[];
// Title and description for the flag to enable the ability to export passwords
// from the password settings.
extern const char kPasswordExportName[];
......
......@@ -79,6 +79,8 @@ source_set("internal") {
"fullscreen_web_state_observer.mm",
"fullscreen_web_view_proxy_observer.h",
"fullscreen_web_view_proxy_observer.mm",
"fullscreen_web_view_resizer.h",
"fullscreen_web_view_resizer.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
......@@ -127,6 +129,7 @@ source_set("unit_tests") {
"fullscreen_ui_updater_unittest.mm",
"fullscreen_web_state_list_observer_unittest.mm",
"fullscreen_web_state_observer_unittest.mm",
"fullscreen_web_view_resizer_unittest.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
......@@ -145,6 +148,7 @@ source_set("unit_tests") {
"//ios/web",
"//ios/web/public",
"//ios/web/public/test/fakes",
"//testing/gmock",
"//testing/gtest",
"//third_party/ocmock",
]
......
......@@ -6,6 +6,7 @@
#include "base/logging.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/web/public/features.h"
#import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
#import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
......@@ -17,10 +18,14 @@ void MoveContentBelowHeader(id<CRWWebViewProxy> proxy, FullscreenModel* model) {
DCHECK(proxy);
DCHECK(model);
CGFloat topPadding = model->progress() * model->GetExpandedToolbarHeight();
CGFloat bottomPadding = model->progress() * model->GetBottomToolbarHeight();
proxy.scrollViewProxy.contentOffset = CGPointMake(0, -topPadding);
UIEdgeInsets contentInset = proxy.contentInset;
contentInset.top = topPadding;
contentInset.bottom = bottomPadding;
proxy.contentInset = contentInset;
if (!base::FeatureList::IsEnabled(web::features::kOutOfWebFullscreen)) {
// With the fullscreen implementation living outside of web, this is no
// longer needed.
CGFloat bottomPadding = model->progress() * model->GetBottomToolbarHeight();
UIEdgeInsets contentInset = proxy.contentInset;
contentInset.top = topPadding;
contentInset.bottom = bottomPadding;
proxy.contentInset = contentInset;
}
}
......@@ -18,8 +18,13 @@ class FullscreenControllerObserver;
@class FullscreenResetAnimator;
@class FullscreenScrollEndAnimator;
@class FullscreenScrollToTopAnimator;
@class FullscreenWebViewResizer;
@class ToolbarRevealAnimator;
namespace web {
class WebState;
}
// A helper object that listens to FullscreenModel changes and forwards this
// information to FullscreenControllerObservers.
class FullscreenMediator : public FullscreenModelObserver {
......@@ -35,6 +40,9 @@ class FullscreenMediator : public FullscreenModelObserver {
observers_.RemoveObserver(observer);
}
// Sets the WebState which view is to be resized.
void SetWebState(web::WebState* webState);
// Instructs the mediator that a scroll-to-top animation has been triggered.
void ScrollToTop();
......@@ -77,6 +85,10 @@ class FullscreenMediator : public FullscreenModelObserver {
// changes.
base::ObserverList<FullscreenControllerObserver>::Unchecked observers_;
// Fullscreen resizer, used to resize the WebView based on the fullscreen
// progress.
FullscreenWebViewResizer* resizer_ = nil;
DISALLOW_COPY_AND_ASSIGN(FullscreenMediator);
};
......
......@@ -9,6 +9,7 @@
#import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.h"
#include "ios/chrome/browser/ui/ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -17,7 +18,9 @@
FullscreenMediator::FullscreenMediator(FullscreenController* controller,
FullscreenModel* model)
: controller_(controller), model_(model) {
: controller_(controller),
model_(model),
resizer_([[FullscreenWebViewResizer alloc] initWithModel:model]) {
DCHECK(controller_);
DCHECK(model_);
model_->AddObserver(this);
......@@ -29,6 +32,10 @@ FullscreenMediator::~FullscreenMediator() {
DCHECK(!model_);
}
void FullscreenMediator::SetWebState(web::WebState* webState) {
resizer_.webState = webState;
}
void FullscreenMediator::ScrollToTop() {
FullscreenAnimatorStyle scrollToTopStyle =
FullscreenAnimatorStyle::EXIT_FULLSCREEN;
......@@ -80,6 +87,8 @@ void FullscreenMediator::Disconnect() {
for (auto& observer : observers_) {
observer.FullscreenControllerWillShutDown(controller_);
}
resizer_.webState = nullptr;
resizer_ = nil;
[animator_ stopAnimation:YES];
animator_ = nil;
model_->RemoveObserver(this);
......@@ -94,6 +103,8 @@ void FullscreenMediator::FullscreenModelProgressUpdated(
for (auto& observer : observers_) {
observer.FullscreenProgressUpdated(controller_, model_->progress());
}
[resizer_ updateForFullscreenProgress:model->progress()];
}
void FullscreenMediator::FullscreenModelEnabledStateChanged(
......@@ -137,6 +148,8 @@ void FullscreenMediator::FullscreenModelWasReset(FullscreenModel* model) {
for (auto& observer : observers_) {
observer.FullscreenProgressUpdated(controller_, model_->progress());
}
[resizer_ updateForFullscreenProgress:model_->progress()];
}
void FullscreenMediator::SetUpAnimator(FullscreenAnimatorStyle style) {
......@@ -152,6 +165,7 @@ void FullscreenMediator::SetUpAnimator(FullscreenAnimatorStyle style) {
return;
model_->AnimationEndedWithProgress(
[weakAnimator progressForAnimatingPosition:finalPosition]);
[resizer_ updateForFullscreenProgress:animator_.finalProgress];
animator_ = nil;
}];
}
......
......@@ -47,6 +47,8 @@ class FullscreenWebStateObserver : public web::WebStateObserver {
FullscreenController* controller_;
// The model passed on construction.
FullscreenModel* model_;
// The mediator passed on construction.
FullscreenMediator* mediator_ = nullptr;
// Observer for |web_state_|'s scroll view proxy.
__strong FullscreenWebViewProxyObserver* web_view_proxy_observer_;
// The disabler for invalid SSL states.
......
......@@ -6,6 +6,7 @@
#include "base/logging.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.h"
#import "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h"
......@@ -53,6 +54,7 @@ FullscreenWebStateObserver::FullscreenWebStateObserver(
FullscreenMediator* mediator)
: controller_(controller),
model_(model),
mediator_(mediator),
web_view_proxy_observer_([[FullscreenWebViewProxyObserver alloc]
initWithModel:model_
mediator:mediator]) {
......@@ -73,6 +75,7 @@ void FullscreenWebStateObserver::SetWebState(web::WebState* web_state) {
// The toolbar should be visible whenever the current tab changes.
model_->ResetForNavigation();
}
mediator_->SetWebState(web_state);
// Update the model according to the new WebState.
SetIsLoading(web_state_ ? web_state->IsLoading() : false);
SetDisableFullscreenForSSL(ShouldDisableFullscreenForWebStateSSL(web_state_));
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_WEB_VIEW_RESIZER_H_
#define IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_WEB_VIEW_RESIZER_H_
#import <UIKit/UIKit.h>
class FullscreenModel;
namespace web {
class WebState;
}
// Resizer for the fullscreen view. This object is taking care of resizing the
// WebView associated with a WebState to have it compatible with the fullscreen
// feature.
@interface FullscreenWebViewResizer : NSObject
// Initializes the object with the fullscreen |model|, used to get the
// information about the state of fullscreen.
- (instancetype)initWithModel:(FullscreenModel*)model NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// WebState currently displayed.
@property(nonatomic, assign) web::WebState* webState;
// Updates the WebView of the current webState to adjust it to the current
// fullscreen |progress|. |progress| should be between 0 and 1, 0 meaning that
// the application is in fullscreen, 1 that it is out of fullscreen.
- (void)updateForFullscreenProgress:(CGFloat)progress;
@end
#endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_WEB_VIEW_RESIZER_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#import "ios/web/public/features.h"
#import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
#import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
#import "ios/web/public/web_state/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface FullscreenWebViewResizer ()
// The fullscreen model, used to get the information about the state of
// fullscreen.
@property(nonatomic, assign) FullscreenModel* model;
@end
@implementation FullscreenWebViewResizer
@synthesize model = _model;
@synthesize webState = _webState;
- (instancetype)initWithModel:(FullscreenModel*)model {
// This can only be instantiated when the feature is enabled.
if (!base::FeatureList::IsEnabled(web::features::kOutOfWebFullscreen))
return nil;
self = [super init];
if (self) {
_model = model;
}
return self;
}
- (void)dealloc {
if (_webState && _webState->GetView())
[_webState->GetView() removeObserver:self forKeyPath:@"frame"];
}
#pragma mark - Properties
- (void)setWebState:(web::WebState*)webState {
if (_webState == webState)
return;
if (_webState && _webState->GetView())
[_webState->GetView() removeObserver:self forKeyPath:@"frame"];
_webState = webState;
if (webState)
[self observeWebStateViewFrame:webState];
}
#pragma mark - Public
- (void)updateForFullscreenProgress:(CGFloat)progress {
if (!self.webState || !self.webState->GetView().superview)
return;
UIView* webView = self.webState->GetView();
UIEdgeInsets newInsets =
UIEdgeInsetsMake(self.model->GetCollapsedToolbarHeight() +
progress * (self.model->GetExpandedToolbarHeight() -
self.model->GetCollapsedToolbarHeight()),
0, progress * self.model->GetBottomToolbarHeight(), 0);
CGRect newFrame = UIEdgeInsetsInsetRect(webView.superview.bounds, newInsets);
// Make sure the frame has changed to avoid a loop as the frame property is
// actually monitored by this object.
if (std::fabs(newFrame.origin.x - webView.frame.origin.x) < 0.01 &&
std::fabs(newFrame.origin.y - webView.frame.origin.y) < 0.01 &&
std::fabs(newFrame.size.width - webView.frame.size.width) < 0.01 &&
std::fabs(newFrame.size.height - webView.frame.size.height) < 0.01)
return;
webView.frame = newFrame;
}
#pragma mark - Private
// Observes the frame property of the view of the |webState| using KVO.
- (void)observeWebStateViewFrame:(web::WebState*)webState {
if (!webState->GetView())
return;
[webState->GetView() addObserver:self
forKeyPath:@"frame"
options:NSKeyValueObservingOptionInitial
context:nil];
}
// Callback for the KVO.
- (void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
if (![keyPath isEqualToString:@"frame"] || object != _webState->GetView())
return;
[self updateForFullscreenProgress:self.model->progress()];
}
@end
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.h"
#include "base/test/scoped_feature_list.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#include "ios/web/public/features.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const CGFloat kTopToolbarExpandedHeight = 50;
const CGFloat kTopToolbarCollapsedHeight = 20;
const CGFloat kBottomToolbarHeight = 40;
const CGFloat kViewWidth = 300;
const CGFloat kViewHeight = 700;
} // namespace
class FullscreenWebViewResizerTest : public PlatformTest {
public:
FullscreenWebViewResizerTest() {
// Make sure the features is enabled.
_features.InitAndEnableFeature(web::features::kOutOfWebFullscreen);
// FullscreenModel setup.
_model.SetExpandedToolbarHeight(kTopToolbarExpandedHeight);
_model.SetCollapsedToolbarHeight(kTopToolbarCollapsedHeight);
_model.SetBottomToolbarHeight(kBottomToolbarHeight);
_model.SetScrollViewHeight(700);
_model.SetContentHeight(1000);
_model.SetScrollViewIsScrolling(true);
_model.SetYContentOffset(10);
// WebState view setup.
CGRect superviewFrame = CGRectMake(0, 0, kViewWidth, kViewHeight);
_webStateSuperview = [[UIView alloc] initWithFrame:superviewFrame];
_webStateView = [[UIView alloc] initWithFrame:CGRectZero];
[_webStateSuperview addSubview:_webStateView];
// WebState setup.
_webState.SetView(_webStateView);
}
protected:
base::test::ScopedFeatureList _features;
FullscreenModel _model;
UIView* _webStateSuperview;
UIView* _webStateView;
web::TestWebState _webState;
};
// Tests that updating the resizer works as expected.
TEST_F(FullscreenWebViewResizerTest, UpdateWebState) {
// Test.
ASSERT_EQ(1, _model.progress());
FullscreenWebViewResizer* resizer =
[[FullscreenWebViewResizer alloc] initWithModel:&_model];
resizer.webState = &_webState;
// The frame should be updated when setting the WebState.
CGRect fullInsetFrame = CGRectMake(
0, kTopToolbarExpandedHeight, kViewWidth,
kViewHeight - kTopToolbarExpandedHeight - kBottomToolbarHeight);
EXPECT_TRUE(CGRectEqualToRect(fullInsetFrame, _webStateView.frame));
// Scroll the view then update the resizer.
_model.SetYContentOffset(50);
ASSERT_EQ(0, _model.progress());
[resizer updateForFullscreenProgress:0];
CGRect smallInsetFrame = CGRectMake(0, kTopToolbarCollapsedHeight, kViewWidth,
kViewHeight - kTopToolbarCollapsedHeight);
EXPECT_TRUE(CGRectEqualToRect(smallInsetFrame, _webStateView.frame));
}
// Tests that nothing happen if there is no superview for the web state view.
TEST_F(FullscreenWebViewResizerTest, WebStateNoSuperview) {
// WebState view setup.
CGRect webViewFrame = CGRectMake(0, 0, kViewWidth, kViewHeight);
UIView* webStateView = [[UIView alloc] initWithFrame:webViewFrame];
// WebState setup.
web::TestWebState webState;
webState.SetView(webStateView);
// Test.
FullscreenWebViewResizer* resizer =
[[FullscreenWebViewResizer alloc] initWithModel:&_model];
resizer.webState = &webState;
EXPECT_TRUE(CGRectEqualToRect(webViewFrame, webStateView.frame));
[resizer updateForFullscreenProgress:1];
EXPECT_TRUE(CGRectEqualToRect(webViewFrame, webStateView.frame));
}
// Tests that nothing happen (no crash) if there is no web state.
TEST_F(FullscreenWebViewResizerTest, NoWebState) {
// Test.
FullscreenWebViewResizer* resizer =
[[FullscreenWebViewResizer alloc] initWithModel:&_model];
[resizer updateForFullscreenProgress:1];
}
......@@ -29,5 +29,8 @@ const base::Feature kCrashOnUnexpectedURLChange{
const base::Feature kBrowserContainerFullscreen{
"BrowserContainerFullscreen", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kOutOfWebFullscreen{"OutOfWebFullscreen",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace web
......@@ -35,6 +35,9 @@ extern const base::Feature kCrashOnUnexpectedURLChange;
// Used to make BrowserContainerViewController fullscreen.
extern const base::Feature kBrowserContainerFullscreen;
// Used to use the fullscreen implementation out of web.
extern const base::Feature kOutOfWebFullscreen;
} // namespace features
} // namespace web
......
......@@ -9,6 +9,7 @@
#include <limits>
#include "base/logging.h"
#import "ios/web/public/features.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -81,10 +82,12 @@ const CGFloat kBackgroundRGBComponents[] = {0.75f, 0.74f, 0.76f};
- (void)layoutSubviews {
[super layoutSubviews];
CGRect frame = self.bounds;
frame = UIEdgeInsetsInsetRect(frame, _contentInset);
frame = CGRectOffset(frame, _contentOffset.x, _contentOffset.y);
self.webView.frame = frame;
if (!base::FeatureList::IsEnabled(web::features::kOutOfWebFullscreen)) {
CGRect frame = self.bounds;
frame = UIEdgeInsetsInsetRect(frame, _contentInset);
frame = CGRectOffset(frame, _contentOffset.x, _contentOffset.y);
self.webView.frame = frame;
}
}
- (BOOL)isViewAlive {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment