| Index: ios/web/web_state/ui/wk_web_view_configuration_provider.mm
|
| diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..535f8f1b0a4ebfaddba239f28bca4b29a28fc02b
|
| --- /dev/null
|
| +++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
|
| @@ -0,0 +1,113 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
|
| +
|
| +#import <Foundation/Foundation.h>
|
| +#import <WebKit/WebKit.h>
|
| +
|
| +#import "base/ios/weak_nsobject.h"
|
| +#import "base/logging.h"
|
| +#include "ios/web/public/browser_state.h"
|
| +#import "ios/web/web_state/js/page_script_util.h"
|
| +#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
|
| +
|
| +// TODO(eugenebut): swizzle [[WKWebViewConfiguration alloc] init] to make sure
|
| +// that WKWebViewConfiguration is obtained only from provider and can not be
|
| +// created by alloc/init call.
|
| +
|
| +namespace web {
|
| +
|
| +namespace {
|
| +// A key used to associate a WKWebViewConfigurationProvider with a BrowserState.
|
| +const char kWKWebViewConfigProviderKeyName[] = "wk_web_view_config_provider";
|
| +
|
| +// Returns an autoreleased instance of WKUserScript to be added to
|
| +// configuration's userContentController.
|
| +WKUserScript* GetEarlyPageScript() {
|
| + // Content of WKUserScript can be injected into the same page multiple times
|
| + // without notifying WKNavigationDelegate (e.g. after window.document.write
|
| + // JavaScript call). Injecting the script one more time will invalidate
|
| + // __gCrWeb.windowId variable and will break the ability to send messages from
|
| + // JS to the native code. Wrapping injected script into "if (!injected)" check
|
| + // prevents multiple injections into the same page.
|
| + NSString* const kSourceTemplate =
|
| + @"if (!window.__gCrWKUserScriptInjected) {"
|
| + " window.__gCrWKUserScriptInjected = true; %@"
|
| + "}";
|
| + NSString* earlyScript = GetEarlyPageScript(WK_WEB_VIEW_TYPE);
|
| + NSString* source = [NSString stringWithFormat:kSourceTemplate, earlyScript];
|
| + return [[[WKUserScript alloc]
|
| + initWithSource:source
|
| + injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
| + forMainFrameOnly:YES] autorelease];
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +WKWebViewConfigurationProvider&
|
| +WKWebViewConfigurationProvider::FromBrowserState(BrowserState* browser_state) {
|
| + DCHECK([NSThread isMainThread]);
|
| + DCHECK(browser_state);
|
| + if (!browser_state->GetUserData(kWKWebViewConfigProviderKeyName)) {
|
| + browser_state->SetUserData(kWKWebViewConfigProviderKeyName,
|
| + new WKWebViewConfigurationProvider());
|
| + }
|
| + return *(static_cast<WKWebViewConfigurationProvider*>(
|
| + browser_state->GetUserData(kWKWebViewConfigProviderKeyName)));
|
| +}
|
| +
|
| +WKWebViewConfigurationProvider::WKWebViewConfigurationProvider() {
|
| +}
|
| +
|
| +WKWebViewConfigurationProvider::~WKWebViewConfigurationProvider() {
|
| +}
|
| +
|
| +WKWebViewConfiguration*
|
| +WKWebViewConfigurationProvider::GetWebViewConfiguration() {
|
| + DCHECK([NSThread isMainThread]);
|
| + if (!configuration_) {
|
| + configuration_.reset([[WKWebViewConfiguration alloc] init]);
|
| + // setJavaScriptCanOpenWindowsAutomatically is required to support popups.
|
| + [[configuration_ preferences] setJavaScriptCanOpenWindowsAutomatically:YES];
|
| + [[configuration_ userContentController] addUserScript:GetEarlyPageScript()];
|
| + }
|
| + // Prevent callers from changing the internals of configuration.
|
| + return [[configuration_ copy] autorelease];
|
| +}
|
| +
|
| +CRWWKScriptMessageRouter*
|
| +WKWebViewConfigurationProvider::GetScriptMessageRouter() {
|
| + DCHECK([NSThread isMainThread]);
|
| + if (!router_) {
|
| + WKUserContentController* userContentController =
|
| + [GetWebViewConfiguration() userContentController];
|
| + router_.reset([[CRWWKScriptMessageRouter alloc]
|
| + initWithUserContentController:userContentController]);
|
| + }
|
| + return router_;
|
| +}
|
| +
|
| +bool WKWebViewConfigurationProvider::HasWebViewConfiguration() const {
|
| + DCHECK([NSThread isMainThread]);
|
| + return configuration_;
|
| +}
|
| +
|
| +void WKWebViewConfigurationProvider::Purge() {
|
| + DCHECK([NSThread isMainThread]);
|
| +#if !defined(NDEBUG) || !defined(DCHECK_ALWAYS_ON) // Matches DCHECK_IS_ON.
|
| + base::WeakNSObject<id> weak_configuration(configuration_);
|
| + base::WeakNSObject<id> weak_router(router_);
|
| + base::WeakNSObject<id> weak_process_pool([configuration_ processPool]);
|
| +#endif // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
| + configuration_.reset();
|
| + router_.reset();
|
| + // Make sure that no one retains configuration, router, processPool.
|
| + DCHECK(!weak_configuration);
|
| + DCHECK(!weak_router);
|
| + DCHECK(!weak_process_pool);
|
| +}
|
| +
|
| +} // namespace web
|
|
|