1// Copyright 2015 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/web_state/ui/crw_web_controller_container_view.h" 6 7#include "base/check.h" 8#include "base/notreached.h" 9#import "ios/web/common/crw_content_view.h" 10#import "ios/web/common/crw_viewport_adjustment_container.h" 11#import "ios/web/common/crw_web_view_content_view.h" 12#include "ios/web/common/features.h" 13#import "ios/web/web_state/ui/crw_web_view_proxy_impl.h" 14 15#if !defined(__has_feature) || !__has_feature(objc_arc) 16#error "This file requires ARC support." 17#endif 18 19@interface CRWWebControllerContainerView () <CRWViewportAdjustmentContainer> 20 21// Redefine properties as readwrite. 22@property(nonatomic, strong, readwrite) 23 CRWWebViewContentView* webViewContentView; 24@property(nonatomic, strong, readwrite) CRWContentView* transientContentView; 25 26// Convenience getter for the proxy object. 27@property(nonatomic, weak, readonly) CRWWebViewProxyImpl* contentViewProxy; 28 29@end 30 31@implementation CRWWebControllerContainerView 32@synthesize webViewContentView = _webViewContentView; 33@synthesize transientContentView = _transientContentView; 34@synthesize delegate = _delegate; 35 36- (instancetype)initWithDelegate: 37 (id<CRWWebControllerContainerViewDelegate>)delegate { 38 self = [super initWithFrame:CGRectZero]; 39 if (self) { 40 DCHECK(delegate); 41 _delegate = delegate; 42 self.backgroundColor = [UIColor whiteColor]; 43 self.autoresizingMask = 44 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 45 } 46 return self; 47} 48 49- (instancetype)initWithCoder:(NSCoder*)decoder { 50 NOTREACHED(); 51 return nil; 52} 53 54- (instancetype)initWithFrame:(CGRect)frame { 55 NOTREACHED(); 56 return nil; 57} 58 59- (void)dealloc { 60 self.contentViewProxy.contentView = nil; 61} 62 63#pragma mark Accessors 64 65- (UIView<CRWViewportAdjustment>*)fullscreenViewportAdjuster { 66 if (![self.webViewContentView 67 conformsToProtocol:@protocol(CRWViewportAdjustment)]) { 68 return nil; 69 } 70 return self.webViewContentView; 71} 72 73- (void)setWebViewContentView:(CRWWebViewContentView*)webViewContentView { 74 if (![_webViewContentView isEqual:webViewContentView]) { 75 [_webViewContentView removeFromSuperview]; 76 _webViewContentView = webViewContentView; 77 [_webViewContentView setFrame:self.bounds]; 78 [self addSubview:_webViewContentView]; 79 } 80} 81 82- (void)setTransientContentView:(CRWContentView*)transientContentView { 83 if (![_transientContentView isEqual:transientContentView]) { 84 [_transientContentView removeFromSuperview]; 85 _transientContentView = transientContentView; 86 } 87} 88 89- (CRWWebViewProxyImpl*)contentViewProxy { 90 return [_delegate contentViewProxyForContainerView:self]; 91} 92 93#pragma mark Layout 94 95- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { 96 [super traitCollectionDidChange:previousTraitCollection]; 97 if (previousTraitCollection.preferredContentSizeCategory != 98 self.traitCollection.preferredContentSizeCategory) { 99 // In case the preferred content size changes, the layout is dirty. 100 [self setNeedsLayout]; 101 } 102} 103 104- (void)layoutSubviews { 105 [super layoutSubviews]; 106 107 // webViewContentView layout. |-setNeedsLayout| is called in case any webview 108 // layout updates need to occur despite the bounds size staying constant. 109 self.webViewContentView.frame = self.bounds; 110 [self.webViewContentView setNeedsLayout]; 111 112 // TODO(crbug.com/570114): Move adding of the following subviews to another 113 // place. 114 // transientContentView layout. 115 if (self.transientContentView) { 116 if (!self.transientContentView.superview) 117 [self addSubview:self.transientContentView]; 118 [self bringSubviewToFront:self.transientContentView]; 119 self.transientContentView.frame = self.bounds; 120 } 121} 122 123- (BOOL)isViewAlive { 124 return self.webViewContentView || self.transientContentView; 125} 126 127- (void)willMoveToWindow:(UIWindow*)newWindow { 128 [super willMoveToWindow:newWindow]; 129 [self updateWebViewContentViewForContainerWindow:newWindow]; 130} 131 132- (void)updateWebViewContentViewForContainerWindow:(UIWindow*)containerWindow { 133 if (!base::FeatureList::IsEnabled(web::features::kKeepsRenderProcessAlive)) 134 return; 135 136 if (!self.webViewContentView) 137 return; 138 139 // If there's a containerWindow or |webViewContentView| is inactive, put it 140 // back where it belongs. 141 if (containerWindow || 142 ![_delegate shouldKeepRenderProcessAliveForContainerView:self]) { 143 if (self.webViewContentView.superview != self) { 144 [_webViewContentView setFrame:self.bounds]; 145 // Insert the content view on the back of the container view so any view 146 // that was presented on top of the content view can still appear. 147 [self insertSubview:_webViewContentView atIndex:0]; 148 } 149 return; 150 } 151 152 // There's no window and |webViewContentView| is active, stash it. 153 [_delegate containerView:self storeWebViewInWindow:self.webViewContentView]; 154} 155 156#pragma mark Content Setters 157 158- (void)resetContent { 159 self.webViewContentView = nil; 160 self.transientContentView = nil; 161 self.contentViewProxy.contentView = nil; 162} 163 164- (void)displayWebViewContentView:(CRWWebViewContentView*)webViewContentView { 165 DCHECK(webViewContentView); 166 self.webViewContentView = webViewContentView; 167 self.transientContentView = nil; 168 self.contentViewProxy.contentView = self.webViewContentView; 169 [self updateWebViewContentViewForContainerWindow:self.window]; 170 [self setNeedsLayout]; 171} 172 173- (void)displayTransientContent:(CRWContentView*)transientContentView { 174 DCHECK(transientContentView); 175 self.transientContentView = transientContentView; 176 self.contentViewProxy.contentView = self.transientContentView; 177 [self setNeedsLayout]; 178} 179 180- (void)clearTransientContentView { 181 self.transientContentView = nil; 182 self.contentViewProxy.contentView = self.webViewContentView; 183} 184 185#pragma mark UIView (printing) 186 187// Only print the web view by returning the web view printformatter. 188- (UIViewPrintFormatter*)viewPrintFormatter { 189 return [self.webViewContentView.webView viewPrintFormatter]; 190} 191 192- (void)drawRect:(CGRect)rect 193 forViewPrintFormatter:(UIViewPrintFormatter*)formatter { 194 [self.webViewContentView.webView drawRect:rect]; 195} 196 197@end 198