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_internal_creation_util.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 #import "ios/web/public/browsing_data_partition.h"
15 #include "ios/web/public/web_client.h"
16 #import "ios/web/public/web_view_creation_util.h"
17 #include "ios/web/ui_web_view_util.h"
18 #import "ios/web/weak_nsobject_counter.h"
19 #import "ios/web/web_state/ui/crw_static_file_web_view.h"
20 #import "ios/web/web_state/ui/crw_ui_simple_web_view_controller.h"
21 #import "ios/web/web_state/ui/crw_wk_simple_web_view_controller.h"
22 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
25 #import "ios/web/web_state/ui/crw_debug_web_view.h"
31 // Returns the counter of all the active WKWebViews.
32 web::WeakNSObjectCounter& GetActiveWKWebViewCounter() {
33 static web::WeakNSObjectCounter active_wk_web_view_counter;
34 return active_wk_web_view_counter;
36 // Decides if WKWebView can be created.
37 BOOL gAllowWKWebViewCreation = NO;
40 @interface WKWebView (CRWAdditions)
43 @implementation WKWebView (CRWAdditions)
46 id (^allocator)(Class klass, NSZone* zone) = ^id(Class klass, NSZone* zone) {
47 if (gAllowWKWebViewCreation) {
48 return NSAllocateObject(klass, 0, zone);
50 // You have hit this because you are trying to create a WKWebView directly.
51 // Please use one of the web::CreateWKWKWebView methods that vend a
56 web::AddAllocWithZoneMethod([WKWebView class], allocator);
61 #endif // !defined(NDEBUG)
65 UIWebView* CreateWebView(CGRect frame,
66 NSString* request_group_id,
67 BOOL use_desktop_user_agent) {
68 web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
69 use_desktop_user_agent);
70 return web::CreateWebView(frame);
73 UIWebView* CreateWebView(CGRect frame) {
74 DCHECK(web::GetWebClient());
75 web::GetWebClient()->PreWebViewCreation();
77 UIWebView* result = nil;
79 result = [[UIWebView alloc] initWithFrame:frame];
81 // TODO(eugenebut): create constant for @"LogJavascript" (crbug.com/391807).
82 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LogJavascript"])
83 result = [[CRWDebugWebView alloc] initWithFrame:frame];
85 result = [[UIWebView alloc] initWithFrame:frame];
86 #endif // defined(NDEBUG)
88 // Disable data detector types. Safari does the same.
89 [result setDataDetectorTypes:UIDataDetectorTypeNone];
90 [result setScalesPageToFit:YES];
92 // By default UIWebView uses a very sluggish scroll speed. Set it to a more
94 result.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
96 web::GetWebClient()->PostWebViewCreation(result);
101 WKWebView* CreateWKWebView(CGRect frame,
102 WKWebViewConfiguration* configuration,
103 BrowserState* browser_state,
104 NSString* request_group_id,
105 BOOL use_desktop_user_agent) {
106 web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
107 use_desktop_user_agent);
108 return CreateWKWebView(frame, configuration, browser_state);
111 WKWebView* CreateWKWebView(CGRect frame,
112 WKWebViewConfiguration* configuration,
113 BrowserState* browser_state) {
114 DCHECK(browser_state);
115 DCHECK(configuration);
116 DCHECK(web::BrowsingDataPartition::IsSynchronized());
117 WKWebViewConfigurationProvider& config_provider =
118 WKWebViewConfigurationProvider::FromBrowserState(browser_state);
119 DCHECK_EQ([config_provider.GetWebViewConfiguration() processPool],
120 [configuration processPool]);
122 DCHECK(web::GetWebClient());
123 web::GetWebClient()->PreWebViewCreation();
125 gAllowWKWebViewCreation = YES;
129 [[WKWebView alloc] initWithFrame:frame configuration:configuration];
131 GetActiveWKWebViewCounter().Insert(result);
132 gAllowWKWebViewCreation = NO;
135 // TODO(stuartmorgan): Figure out how to make this work; two different client
136 // methods for the two web view types?
137 // web::GetWebClient()->PostWebViewCreation(result);
142 NSUInteger GetActiveWKWebViewsCount() {
144 // This should not be used in release builds.
148 return GetActiveWKWebViewCounter().Size();
152 id<CRWSimpleWebViewController> CreateSimpleWebViewController(
154 BrowserState* browser_state,
155 WebViewType web_view_type) {
156 DCHECK(web::BrowsingDataPartition::IsSynchronized());
158 // Transparently return the correct subclass.
159 if (web_view_type == WK_WEB_VIEW_TYPE) {
160 base::scoped_nsobject<WKWebView> web_view(
161 web::CreateWKWebView(frame, browser_state));
162 return [[CRWWKSimpleWebViewController alloc] initWithWKWebView:web_view];
164 base::scoped_nsobject<UIWebView> web_view(web::CreateWebView(frame));
165 return [[CRWUISimpleWebViewController alloc] initWithUIWebView:web_view];
168 id<CRWSimpleWebViewController> CreateStaticFileSimpleWebViewController(
170 BrowserState* browser_state,
171 WebViewType web_view_type) {
172 DCHECK(web::BrowsingDataPartition::IsSynchronized());
174 // Transparently return the correct subclass.
175 if (web_view_type == WK_WEB_VIEW_TYPE) {
176 // TOOD(shreyasv): Create a new util function vending a WKWebView, wrap that
177 // now return the UIWebView version. crbug.com/403634.
179 base::scoped_nsobject<UIWebView> staticFileWebView(
180 CreateStaticFileWebView(frame, browser_state));
181 return [[CRWUISimpleWebViewController alloc]
182 initWithUIWebView:staticFileWebView];
185 UIWebView* CreateStaticFileWebView(CGRect frame, BrowserState* browser_state) {
186 DCHECK(web::GetWebClient());
187 web::GetWebClient()->PreWebViewCreation();
190 [[CRWStaticFileWebView alloc] initWithFrame:frame
191 browserState:browser_state];
193 web::GetWebClient()->PostWebViewCreation(result);
197 UIWebView* CreateStaticFileWebView() {
198 return CreateStaticFileWebView(CGRectZero, nullptr);