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 #include "ios/web/public/browser_state.h"
14 #include "ios/web/public/web_client.h"
15 #include "ios/web/ui_web_view_util.h"
16 #import "ios/web/weak_nsobject_counter.h"
17 #import "ios/web/web_state/ui/crw_static_file_web_view.h"
18 #import "ios/web/web_state/ui/crw_ui_simple_web_view_controller.h"
19 #import "ios/web/web_state/ui/crw_wk_simple_web_view_controller.h"
20 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
23 #import "ios/web/web_state/ui/crw_debug_web_view.h"
29 // Returns the counter of all the active WKWebViews.
30 web::WeakNSObjectCounter& GetActiveWKWebViewCounter() {
31 static web::WeakNSObjectCounter active_wk_web_view_counter;
32 return active_wk_web_view_counter;
34 // Decides if WKWebView can be created.
35 BOOL gAllowWKWebViewCreation = NO;
38 @interface WKWebView(CRWAdditions)
41 @implementation WKWebView(CRWAdditions)
44 id (^allocator)(Class klass, NSZone* zone) = ^id(Class klass, NSZone* zone) {
45 if (gAllowWKWebViewCreation) {
46 return NSAllocateObject(klass, 0, zone);
48 // You have hit this because you are trying to create a WKWebView directly.
49 // Please use one of the web::CreateWKWKWebView methods that vend a
54 web::AddAllocWithZoneMethod([WKWebView class], allocator);
59 #endif // !defined(NDEBUG)
62 // Returns a new WKWebView for displaying regular web content.
63 // Note: Callers are responsible for releasing the returned WKWebView.
64 WKWebView* CreateWKWebViewWithConfiguration(
66 WKWebViewConfiguration* configuration) {
67 DCHECK(configuration);
68 DCHECK(web::GetWebClient());
69 web::GetWebClient()->PreWebViewCreation();
71 gAllowWKWebViewCreation = YES;
75 [[WKWebView alloc] initWithFrame:frame configuration:configuration];
77 GetActiveWKWebViewCounter().Insert(result);
78 gAllowWKWebViewCreation = NO;
81 // TODO(stuartmorgan): Figure out how to make this work; two different client
82 // methods for the two web view types?
83 // web::GetWebClient()->PostWebViewCreation(result);
91 UIWebView* CreateWebView(CGRect frame,
92 NSString* request_group_id,
93 BOOL use_desktop_user_agent) {
94 web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
95 use_desktop_user_agent);
96 return web::CreateWebView(frame);
99 UIWebView* CreateWebView(CGRect frame) {
100 DCHECK(web::GetWebClient());
101 web::GetWebClient()->PreWebViewCreation();
103 UIWebView* result = nil;
105 result = [[UIWebView alloc] initWithFrame:frame];
107 // TODO(eugenebut): create constant for @"LogJavascript" (crbug.com/391807).
108 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LogJavascript"])
109 result = [[CRWDebugWebView alloc] initWithFrame:frame];
111 result = [[UIWebView alloc] initWithFrame:frame];
112 #endif // defined(NDEBUG)
114 // Disable data detector types. Safari does the same.
115 [result setDataDetectorTypes:UIDataDetectorTypeNone];
116 [result setScalesPageToFit:YES];
118 // By default UIWebView uses a very sluggish scroll speed. Set it to a more
120 result.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
122 web::GetWebClient()->PostWebViewCreation(result);
127 WKWebView* CreateWKWebView(CGRect frame,
128 WKWebViewConfiguration* configuration,
129 BrowserState* browser_state,
130 NSString* request_group_id,
131 BOOL use_desktop_user_agent) {
132 DCHECK(browser_state);
133 WKWebViewConfigurationProvider& config_provider =
134 WKWebViewConfigurationProvider::FromBrowserState(browser_state);
135 DCHECK_EQ([config_provider.GetWebViewConfiguration() processPool],
136 [configuration processPool]);
137 web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
138 use_desktop_user_agent);
139 return CreateWKWebViewWithConfiguration(frame, configuration);
142 WKWebView* CreateWKWebView(CGRect frame, BrowserState* browser_state) {
143 DCHECK(browser_state);
144 WKWebViewConfigurationProvider& config_provider =
145 WKWebViewConfigurationProvider::FromBrowserState(browser_state);
146 return CreateWKWebViewWithConfiguration(
147 frame, config_provider.GetWebViewConfiguration());
150 NSUInteger GetActiveWKWebViewsCount() {
152 // This should not be used in release builds.
156 return GetActiveWKWebViewCounter().Size();
160 id<CRWSimpleWebViewController> CreateSimpleWebViewController(
162 BrowserState* browser_state,
163 WebViewType web_view_type) {
164 // Transparently return the correct subclass.
165 if (web_view_type == WK_WEB_VIEW_TYPE) {
166 base::scoped_nsobject<WKWebView> web_view(
167 web::CreateWKWebView(frame, browser_state));
168 return [[CRWWKSimpleWebViewController alloc] initWithWKWebView:web_view];
170 base::scoped_nsobject<UIWebView> web_view(web::CreateWebView(frame));
171 return [[CRWUISimpleWebViewController alloc] initWithUIWebView:web_view];
174 id<CRWSimpleWebViewController> CreateStaticFileSimpleWebViewController(
176 BrowserState* browser_state,
177 WebViewType web_view_type) {
178 // Transparently return the correct subclass.
179 if (web_view_type == WK_WEB_VIEW_TYPE) {
180 // TOOD(shreyasv): Create a new util function vending a WKWebView, wrap that
181 // now return the UIWebView version. crbug.com/403634.
183 base::scoped_nsobject<UIWebView> staticFileWebView(
184 CreateStaticFileWebView(frame, browser_state));
185 return [[CRWUISimpleWebViewController alloc]
186 initWithUIWebView:staticFileWebView];
189 UIWebView* CreateStaticFileWebView(CGRect frame, BrowserState* browser_state) {
190 DCHECK(web::GetWebClient());
191 web::GetWebClient()->PreWebViewCreation();
194 [[CRWStaticFileWebView alloc] initWithFrame:frame
195 browserState:browser_state];
197 web::GetWebClient()->PostWebViewCreation(result);
201 UIWebView* CreateStaticFileWebView() {
202 return CreateStaticFileWebView(CGRectZero, nullptr);