Index: ios/web/web_state/ui/crw_wk_script_message_router.mm |
diff --git a/ios/web/web_state/ui/crw_wk_script_message_router.mm b/ios/web/web_state/ui/crw_wk_script_message_router.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..95ba4f21c9828345f5197d247c5ee2dbe8fce491 |
--- /dev/null |
+++ b/ios/web/web_state/ui/crw_wk_script_message_router.mm |
@@ -0,0 +1,113 @@ |
+// Copyright 2014 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/crw_wk_script_message_router.h" |
+ |
+#import "base/logging.h" |
+#import "base/mac/scoped_nsobject.h" |
+ |
+@interface CRWWKScriptMessageRouter ()<WKScriptMessageHandler> |
+ |
+// Removes a specific message handler. Does nothing if handler does not exist. |
+- (void)tryRemoveScriptMessageHandlerForName:(NSString*)messageName |
+ webView:(WKWebView*)webView; |
+ |
+@end |
+ |
+@implementation CRWWKScriptMessageRouter { |
+ // Two level map of registed message handlers. Keys are message names and |
+ // values are more maps (where keys are web views and values are handlers). |
+ base::scoped_nsobject<NSMutableDictionary> _handlers; |
+ // Wrapped WKUserContentController. |
+ base::scoped_nsobject<WKUserContentController> _userContentController; |
+} |
+ |
+#pragma mark - |
+#pragma mark Interface |
+ |
+- (WKUserContentController*)userContentController { |
+ return _userContentController.get(); |
+} |
+ |
+- (instancetype)init { |
+ NOTREACHED(); |
+ return nil; |
+} |
+ |
+- (instancetype)initWithUserContentController: |
+ (WKUserContentController*)userContentController { |
+ DCHECK(userContentController); |
+ if ((self = [super init])) { |
+ _handlers.reset([[NSMutableDictionary alloc] init]); |
+ _userContentController.reset([userContentController retain]); |
+ } |
+ return self; |
+} |
+ |
+- (void)setScriptMessageHandler:(void(^)(WKScriptMessage*))handler |
+ name:(NSString*)messageName |
+ webView:(WKWebView*)webView { |
+ DCHECK(handler); |
+ DCHECK(messageName); |
+ DCHECK(webView); |
+ |
+ NSMapTable* webViewToHandlerMap = [_handlers objectForKey:messageName]; |
+ if (!webViewToHandlerMap) { |
+ webViewToHandlerMap = [NSMapTable |
+ mapTableWithKeyOptions:NSPointerFunctionsStrongMemory |
+ valueOptions:NSPointerFunctionsCopyIn]; |
+ [_handlers setObject:webViewToHandlerMap forKey:messageName]; |
+ [_userContentController addScriptMessageHandler:self name:messageName]; |
+ } |
+ DCHECK(![webViewToHandlerMap objectForKey:webView]); |
+ [webViewToHandlerMap setObject:handler forKey:webView]; |
+} |
+ |
+- (void)removeScriptMessageHandlerForName:(NSString*)messageName |
+ webView:(WKWebView*)webView { |
+ DCHECK(messageName); |
+ DCHECK(webView); |
+ DCHECK([[_handlers objectForKey:messageName] objectForKey:webView]); |
+ [self tryRemoveScriptMessageHandlerForName:messageName webView:webView]; |
+} |
+ |
+- (void)removeAllScriptMessageHandlersForWebView:(WKWebView*)webView { |
+ DCHECK(webView); |
+ for (NSString* messageName in [_handlers allKeys]) { |
+ [self tryRemoveScriptMessageHandlerForName:messageName webView:webView]; |
+ } |
+} |
+ |
+#pragma mark - |
+#pragma mark WKScriptMessageHandler |
+ |
+- (void)userContentController:(WKUserContentController*)userContentController |
+ didReceiveScriptMessage:(WKScriptMessage*)message { |
+ NSMapTable* webViewToHandlerMap = [_handlers objectForKey:message.name]; |
+ DCHECK(webViewToHandlerMap); |
+ id handler = [webViewToHandlerMap objectForKey:message.webView]; |
+ if (handler) { |
+ // Web process can send messages even if web view was reset and |
+ // script message handler has been removed from the router. |
+ ((void(^)(WKScriptMessage*))handler)(message); |
+ } |
+} |
+ |
+#pragma mark - |
+#pragma mark Implementation |
+ |
+- (void)tryRemoveScriptMessageHandlerForName:(NSString*)messageName |
+ webView:(WKWebView*)webView { |
+ NSMapTable* webViewToHandlerMap = [_handlers objectForKey:messageName]; |
+ if (![webViewToHandlerMap objectForKey:webView]) |
+ return; |
+ if (webViewToHandlerMap.count == 1) { |
+ [_handlers removeObjectForKey:messageName]; |
+ [_userContentController removeScriptMessageHandlerForName:messageName]; |
+ } else { |
+ [webViewToHandlerMap removeObjectForKey:webView]; |
+ } |
+} |
+ |
+@end |