1 // Copyright 2014 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.
5 #import "ios/web/web_state/web_view_creation_utils.h"
7 #import <objc/runtime.h>
8 #import <WebKit/WebKit.h>
10 #include "base/logging.h"
11 #include "base/mac/scoped_nsobject.h"
12 #import "ios/web/alloc_with_zone_interceptor.h"
13 #import "ios/web/public/browsing_data_partition.h"
14 #include "ios/web/public/browser_state.h"
15 #include "ios/web/public/web_client.h"
16 #include "ios/web/ui_web_view_util.h"
17 #import "ios/web/weak_nsobject_counter.h"
18 #import "ios/web/web_state/ui/crw_static_file_web_view.h"
19 #import "ios/web/web_state/ui/crw_ui_simple_web_view_controller.h"
20 #import "ios/web/web_state/ui/crw_wk_simple_web_view_controller.h"
21 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
24 #import "ios/web/web_state/ui/crw_debug_web_view.h"
30 // Returns the counter of all the active WKWebViews.
31 web::WeakNSObjectCounter& GetActiveWKWebViewCounter() {
32 static web::WeakNSObjectCounter active_wk_web_view_counter;
33 return active_wk_web_view_counter;
35 // Decides if WKWebView can be created.
36 BOOL gAllowWKWebViewCreation = NO;
39 @interface WKWebView(CRWAdditions)
42 @implementation WKWebView(CRWAdditions)
45 id (^allocator)(Class klass, NSZone* zone) = ^id(Class klass, NSZone* zone) {
46 if (gAllowWKWebViewCreation) {
47 return NSAllocateObject(klass, 0, zone);
49 // You have hit this because you are trying to create a WKWebView directly.
50 // Please use one of the web::CreateWKWKWebView methods that vend a
55 web::AddAllocWithZoneMethod([WKWebView class], allocator);
60 #endif // !defined(NDEBUG)
63 // Returns a new WKWebView for displaying regular web content.
64 // Note: Callers are responsible for releasing the returned WKWebView.
65 WKWebView* CreateWKWebViewWithConfiguration(
67 WKWebViewConfiguration* configuration) {
68 DCHECK(configuration);
69 DCHECK(web::GetWebClient());
70 web::GetWebClient()->PreWebViewCreation();
72 gAllowWKWebViewCreation = YES;
76 [[WKWebView alloc] initWithFrame:frame configuration:configuration];
78 GetActiveWKWebViewCounter().Insert(result);
79 gAllowWKWebViewCreation = NO;
82 // TODO(stuartmorgan): Figure out how to make this work; two different client
83 // methods for the two web view types?
84 // web::GetWebClient()->PostWebViewCreation(result);
92 UIWebView* CreateWebView(CGRect frame,
93 NSString* request_group_id,
94 BOOL use_desktop_user_agent) {
95 web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
96 use_desktop_user_agent);
97 return web::CreateWebView(frame);
100 UIWebView* CreateWebView(CGRect frame) {
101 DCHECK(web::GetWebClient());
102 web::GetWebClient()->PreWebViewCreation();
104 UIWebView* result = nil;
106 result = [[UIWebView alloc] initWithFrame:frame];
108 // TODO(eugenebut): create constant for @"LogJavascript" (crbug.com/391807).
109 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LogJavascript"])
110 result = [[CRWDebugWebView alloc] initWithFrame:frame];
112 result = [[UIWebView alloc] initWithFrame:frame];
113 #endif // defined(NDEBUG)
115 // Disable data detector types. Safari does the same.
116 [result setDataDetectorTypes:UIDataDetectorTypeNone];
117 [result setScalesPageToFit:YES];
119 // By default UIWebView uses a very sluggish scroll speed. Set it to a more
121 result.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
123 web::GetWebClient()->PostWebViewCreation(result);
128 WKWebView* CreateWKWebView(CGRect frame,
129 WKWebViewConfiguration* configuration,
130 BrowserState* browser_state,
131 NSString* request_group_id,
132 BOOL use_desktop_user_agent) {
133 DCHECK(browser_state);
134 DCHECK(web::BrowsingDataPartition::IsSynchronized());
136 WKWebViewConfigurationProvider& config_provider =
137 WKWebViewConfigurationProvider::FromBrowserState(browser_state);
138 DCHECK_EQ([config_provider.GetWebViewConfiguration() processPool],
139 [configuration processPool]);
140 web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
141 use_desktop_user_agent);
142 return CreateWKWebViewWithConfiguration(frame, configuration);
145 WKWebView* CreateWKWebView(CGRect frame, BrowserState* browser_state) {
146 DCHECK(browser_state);
147 DCHECK(web::BrowsingDataPartition::IsSynchronized());
149 WKWebViewConfigurationProvider& config_provider =
150 WKWebViewConfigurationProvider::FromBrowserState(browser_state);
151 return CreateWKWebViewWithConfiguration(
152 frame, config_provider.GetWebViewConfiguration());
155 NSUInteger GetActiveWKWebViewsCount() {
157 // This should not be used in release builds.
161 return GetActiveWKWebViewCounter().Size();
165 id<CRWSimpleWebViewController> CreateSimpleWebViewController(
167 BrowserState* browser_state,
168 WebViewType web_view_type) {
169 DCHECK(web::BrowsingDataPartition::IsSynchronized());
171 // Transparently return the correct subclass.
172 if (web_view_type == WK_WEB_VIEW_TYPE) {
173 base::scoped_nsobject<WKWebView> web_view(
174 web::CreateWKWebView(frame, browser_state));
175 return [[CRWWKSimpleWebViewController alloc] initWithWKWebView:web_view];
177 base::scoped_nsobject<UIWebView> web_view(web::CreateWebView(frame));
178 return [[CRWUISimpleWebViewController alloc] initWithUIWebView:web_view];
181 id<CRWSimpleWebViewController> CreateStaticFileSimpleWebViewController(
183 BrowserState* browser_state,
184 WebViewType web_view_type) {
185 DCHECK(web::BrowsingDataPartition::IsSynchronized());
187 // Transparently return the correct subclass.
188 if (web_view_type == WK_WEB_VIEW_TYPE) {
189 // TOOD(shreyasv): Create a new util function vending a WKWebView, wrap that
190 // now return the UIWebView version. crbug.com/403634.
192 base::scoped_nsobject<UIWebView> staticFileWebView(
193 CreateStaticFileWebView(frame, browser_state));
194 return [[CRWUISimpleWebViewController alloc]
195 initWithUIWebView:staticFileWebView];
198 UIWebView* CreateStaticFileWebView(CGRect frame, BrowserState* browser_state) {
199 DCHECK(web::GetWebClient());
200 web::GetWebClient()->PreWebViewCreation();
203 [[CRWStaticFileWebView alloc] initWithFrame:frame
204 browserState:browser_state];
206 web::GetWebClient()->PostWebViewCreation(result);
210 UIWebView* CreateStaticFileWebView() {
211 return CreateStaticFileWebView(CGRectZero, nullptr);