Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ios / web / web_state / web_view_internal_creation_util.mm
blobc25283aa57d0c4502226042208e68de2952b6e75
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/active_state_manager.h"
14 #include "ios/web/public/browser_state.h"
15 #import "ios/web/public/browsing_data_partition.h"
16 #include "ios/web/public/web_client.h"
17 #import "ios/web/public/web_view_counter.h"
18 #import "ios/web/public/web_view_creation_util.h"
19 #include "ios/web/ui_web_view_util.h"
20 #import "ios/web/weak_nsobject_counter.h"
21 #import "ios/web/web_state/ui/crw_static_file_web_view.h"
22 #import "ios/web/web_state/ui/crw_ui_simple_web_view_controller.h"
23 #import "ios/web/web_state/ui/crw_wk_simple_web_view_controller.h"
24 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
25 #import "ios/web/web_view_counter_impl.h"
27 #if !defined(NDEBUG)
28 #import "ios/web/web_state/ui/crw_debug_web_view.h"
29 #endif
31 #if !defined(NDEBUG)
33 namespace {
34 // Returns the counter of all the active WKWebViews.
35 // DEPRECATED. Please use web::WebViewCounter instead.
36 // TODO(shreyasv): Remove this once all callers have stopped using it.
37 // crbug.com/480507
38 web::WeakNSObjectCounter& GetActiveWKWebViewCounter() {
39   static web::WeakNSObjectCounter active_wk_web_view_counter;
40   return active_wk_web_view_counter;
43 // Decides if web views can be created.
44 bool gAllowWebViewCreation = NO;
46 // Decides if web views are associated with an ActiveStateManager which is
47 // active.
48 bool gWebViewsNeedActiveStateManager = NO;
50 }  // namespace
52 @interface WKWebView (CRWAdditions)
53 @end
55 @implementation WKWebView (CRWAdditions)
57 + (void)load {
58   id (^allocator)(Class klass, NSZone* zone) = ^id(Class klass, NSZone* zone) {
59     if (web::IsWebViewAllocInitAllowed()) {
60       return NSAllocateObject(klass, 0, zone);
61     }
62     // You have hit this because you are trying to create a WKWebView directly.
63     // Please use one of the web::CreateWKWKWebView methods that vend a
64     // WKWebView instead.
65     NOTREACHED();
66     return nil;
67   };
68   web::AddAllocWithZoneMethod([WKWebView class], allocator);
71 @end
73 #endif  // !defined(NDEBUG)
75 namespace web {
77 namespace {
79 // Verifies the preconditions for creating a WKWebView. Must be called before
80 // a WKWebView is allocated. Not verifying the preconditions before creating
81 // a WKWebView will lead to undefined behavior.
82 void VerifyWKWebViewCreationPreConditions(
83     BrowserState* browser_state,
84     WKWebViewConfiguration* configuration) {
85   DCHECK(browser_state);
86   DCHECK(configuration);
87   DCHECK(web::BrowsingDataPartition::IsSynchronized());
88   WKWebViewConfigurationProvider& config_provider =
89       WKWebViewConfigurationProvider::FromBrowserState(browser_state);
90   DCHECK_EQ([config_provider.GetWebViewConfiguration() processPool],
91             [configuration processPool]);
94 // Called before a WKWebView is created.
95 void PreWKWebViewCreation(BrowserState* browser_state) {
96   DCHECK(browser_state);
97   DCHECK(GetWebClient());
98   GetWebClient()->PreWebViewCreation();
100 #if !defined(NDEBUG)
101   if (IsWebViewAllocInitAllowed() && gWebViewsNeedActiveStateManager) {
102     DCHECK(BrowserState::GetActiveStateManager(browser_state)->IsActive());
103   }
104 #endif
107 // Called after the WKWebView |web_view| is created.
108 void PostWKWebViewCreation(WKWebView* web_view, BrowserState* browser_state) {
109   DCHECK(web_view);
111 #if !defined(NDEBUG)
112   GetActiveWKWebViewCounter().Insert(web_view);
113 #endif
115   WebViewCounterImpl* web_view_counter =
116       WebViewCounterImpl::FromBrowserState(browser_state);
117   DCHECK(web_view_counter);
118   web_view_counter->InsertWKWebView(web_view);
120   // TODO(stuartmorgan): Figure out how to make this work; two different client
121   // methods for the two web view types?
122   // web::GetWebClient()->PostWebViewCreation(result);
125 }  // namespace
127 UIWebView* CreateWebView(CGRect frame,
128                          NSString* request_group_id,
129                          BOOL use_desktop_user_agent) {
130   web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
131                                              use_desktop_user_agent);
132   return web::CreateWebView(frame);
135 UIWebView* CreateWebView(CGRect frame) {
136   DCHECK(web::GetWebClient());
137   web::GetWebClient()->PreWebViewCreation();
139   UIWebView* result = nil;
140 #if defined(NDEBUG)
141   result = [[UIWebView alloc] initWithFrame:frame];
142 #else
143   // TODO(eugenebut): create constant for @"LogJavascript" (crbug.com/391807).
144   if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LogJavascript"])
145     result = [[CRWDebugWebView alloc] initWithFrame:frame];
146   else
147     result = [[UIWebView alloc] initWithFrame:frame];
148 #endif  // defined(NDEBUG)
150   // Disable data detector types. Safari does the same.
151   [result setDataDetectorTypes:UIDataDetectorTypeNone];
152   [result setScalesPageToFit:YES];
154   // By default UIWebView uses a very sluggish scroll speed. Set it to a more
155   // reasonable value.
156   result.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
158   web::GetWebClient()->PostWebViewCreation(result);
160   return result;
163 WKWebView* CreateWKWebView(CGRect frame,
164                            WKWebViewConfiguration* configuration,
165                            BrowserState* browser_state,
166                            NSString* request_group_id,
167                            BOOL use_desktop_user_agent) {
168   web::BuildAndRegisterUserAgentForUIWebView(request_group_id,
169                                              use_desktop_user_agent);
170   return CreateWKWebView(frame, configuration, browser_state);
173 WKWebView* CreateWKWebView(CGRect frame,
174                            WKWebViewConfiguration* configuration,
175                            BrowserState* browser_state) {
176   VerifyWKWebViewCreationPreConditions(browser_state, configuration);
178   PreWKWebViewCreation(browser_state);
179 #if !defined(NDEBUG)
180   bool previous_allow_web_view_creation_value = gAllowWebViewCreation;
181   gAllowWebViewCreation = true;
182 #endif
183   WKWebView* result =
184       [[WKWebView alloc] initWithFrame:frame configuration:configuration];
185 #if !defined(NDEBUG)
186   gAllowWebViewCreation = previous_allow_web_view_creation_value;
187 #endif
188   PostWKWebViewCreation(result, browser_state);
190   return result;
193 NSUInteger GetActiveWKWebViewsCount() {
194 #if defined(NDEBUG)
195   // This should not be used in release builds.
196   CHECK(0);
197   return 0;
198 #else
199   return GetActiveWKWebViewCounter().Size();
200 #endif
203 id<CRWSimpleWebViewController> CreateSimpleWebViewController(
204     CGRect frame,
205     BrowserState* browser_state,
206     WebViewType web_view_type) {
207   DCHECK(web::BrowsingDataPartition::IsSynchronized());
209   // Transparently return the correct subclass.
210   if (web_view_type == WK_WEB_VIEW_TYPE) {
211     base::scoped_nsobject<WKWebView> web_view(
212         web::CreateWKWebView(frame, browser_state));
213     return [[CRWWKSimpleWebViewController alloc] initWithWKWebView:web_view];
214   }
215   base::scoped_nsobject<UIWebView> web_view(web::CreateWebView(frame));
216   return [[CRWUISimpleWebViewController alloc] initWithUIWebView:web_view];
219 id<CRWSimpleWebViewController> CreateStaticFileSimpleWebViewController(
220     CGRect frame,
221     BrowserState* browser_state,
222     WebViewType web_view_type) {
223   DCHECK(web::BrowsingDataPartition::IsSynchronized());
225   // Transparently return the correct subclass.
226   if (web_view_type == WK_WEB_VIEW_TYPE) {
227     // TOOD(shreyasv): Create a new util function vending a WKWebView, wrap that
228     // now return the UIWebView version. crbug.com/403634.
229   }
230   base::scoped_nsobject<UIWebView> staticFileWebView(
231       CreateStaticFileWebView(frame, browser_state));
232   return [[CRWUISimpleWebViewController alloc]
233       initWithUIWebView:staticFileWebView];
236 UIWebView* CreateStaticFileWebView(CGRect frame, BrowserState* browser_state) {
237   DCHECK(web::GetWebClient());
238   web::GetWebClient()->PreWebViewCreation();
240   UIWebView* result =
241       [[CRWStaticFileWebView alloc] initWithFrame:frame
242                                      browserState:browser_state];
244   web::GetWebClient()->PostWebViewCreation(result);
245   return result;
248 UIWebView* CreateStaticFileWebView() {
249   return CreateStaticFileWebView(CGRectZero, nullptr);
252 #if !defined(NDEBUG)
253 bool IsWebViewAllocInitAllowed() {
254   static dispatch_once_t once_token = 0;
255   dispatch_once(&once_token, ^{
256     DCHECK(GetWebClient());
257     gAllowWebViewCreation = GetWebClient()->AllowWebViewAllocInit();
258     if (!gAllowWebViewCreation) {
259       gWebViewsNeedActiveStateManager =
260           GetWebClient()->WebViewsNeedActiveStateManager();
261     }
262   });
263   return gAllowWebViewCreation;
265 #endif
267 }  // namespace web