blob: 32aac34b93d43ffdccacce03efb885486ff80b34 [file] [log] [blame]
// Copyright 2015 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/web/public/web_state/ui/crw_web_view_content_view.h"
#import <WebKit/WebKit.h>
#include "base/logging.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Background color RGB values for the content view which is displayed when the
// |_webView| is offset from the screen due to user interaction. Displaying this
// background color is handled by UIWebView but not WKWebView, so it needs to be
// set in CRWWebViewContentView to support both. The color value matches that
// used by UIWebView.
const CGFloat kBackgroundRGBComponents[] = {0.75f, 0.74f, 0.76f};
} // namespace
@interface CRWWebViewContentView () {
// Backs up property of the same name if |_webView| is a WKWebView.
CGFloat _topContentPadding;
}
// Changes web view frame to match |self.bounds| and optionally accomodates for
// |_topContentPadding| (iff |_webView| is a WKWebView).
- (void)updateWebViewFrame;
// The web view being shown.
@property(nonatomic, strong, readwrite) UIView* webView;
// The web view's scroll view.
@property(nonatomic, strong, readwrite) UIScrollView* scrollView;
@end
@implementation CRWWebViewContentView
@synthesize shouldUseInsetForTopPadding = _shouldUseInsetForTopPadding;
@synthesize webView = _webView;
@synthesize scrollView = _scrollView;
- (instancetype)initWithWebView:(UIView*)webView
scrollView:(UIScrollView*)scrollView {
self = [super initWithFrame:CGRectZero];
if (self) {
DCHECK(webView);
DCHECK(scrollView);
DCHECK([scrollView isDescendantOfView:webView]);
_webView = webView;
_scrollView = scrollView;
}
return self;
}
- (instancetype)initForTesting {
return [super initWithFrame:CGRectZero];
}
- (instancetype)initWithCoder:(NSCoder*)decoder {
NOTREACHED();
return nil;
}
- (instancetype)initWithFrame:(CGRect)frame {
NOTREACHED();
return nil;
}
- (void)didMoveToSuperview {
[super didMoveToSuperview];
if (self.superview) {
self.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:_webView];
self.backgroundColor = [UIColor colorWithRed:kBackgroundRGBComponents[0]
green:kBackgroundRGBComponents[1]
blue:kBackgroundRGBComponents[2]
alpha:1.0];
}
}
- (BOOL)becomeFirstResponder {
return [_webView becomeFirstResponder];
}
- (void)setFrame:(CGRect)frame {
if (CGRectEqualToRect(self.frame, frame))
return;
[super setFrame:frame];
[self updateWebViewFrame];
}
- (void)setBounds:(CGRect)bounds {
if (CGRectEqualToRect(self.bounds, bounds))
return;
[super setBounds:bounds];
[self updateWebViewFrame];
}
#pragma mark Layout
- (void)layoutSubviews {
[super layoutSubviews];
[self updateWebViewFrame];
}
- (BOOL)isViewAlive {
return YES;
}
- (CGFloat)topContentPadding {
BOOL isSettingWebViewFrame = !self.shouldUseInsetForTopPadding;
return isSettingWebViewFrame ? _topContentPadding
: [_scrollView contentInset].top;
}
- (void)setTopContentPadding:(CGFloat)newTopPadding {
if (!self.shouldUseInsetForTopPadding) {
if (_topContentPadding != newTopPadding) {
// Update the content offset of the scroll view to match the padding
// that will be included in the frame.
CGFloat paddingChange = newTopPadding - _topContentPadding;
CGPoint contentOffset = [_scrollView contentOffset];
contentOffset.y += paddingChange;
[_scrollView setContentOffset:contentOffset];
_topContentPadding = newTopPadding;
// Update web view frame immediately to make |topContentPadding|
// animatable.
[self updateWebViewFrame];
// Setting WKWebView frame can mistakenly reset contentOffset. Change it
// back to the initial value if necessary.
// TODO(crbug.com/645857): Remove this workaround once WebKit bug is
// fixed.
if ([_scrollView contentOffset].y != contentOffset.y) {
[_scrollView setContentOffset:contentOffset];
}
}
} else {
UIEdgeInsets inset = [_scrollView contentInset];
inset.top = newTopPadding;
[_scrollView setContentInset:inset];
}
}
- (void)setShouldUseInsetForTopPadding:(BOOL)shouldUseInsetForTopPadding {
if (_shouldUseInsetForTopPadding != shouldUseInsetForTopPadding) {
CGFloat oldTopContentPadding = self.topContentPadding;
self.topContentPadding = 0.0f;
_shouldUseInsetForTopPadding = shouldUseInsetForTopPadding;
self.topContentPadding = oldTopContentPadding;
}
}
#pragma mark Private methods
- (void)updateWebViewFrame {
CGRect webViewFrame = self.bounds;
webViewFrame.size.height -= _topContentPadding;
webViewFrame.origin.y += _topContentPadding;
self.webView.frame = webViewFrame;
}
@end