Begin work on supporting reply blocks in _WKRemoteObjectRegistry
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 31 Oct 2015 00:12:28 +0000 (00:12 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 31 Oct 2015 00:12:28 +0000 (00:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150739

Reviewed by Tim Horton.

Source/WebKit2:

* Platform/spi/Cocoa/BlockSPI.h:
Add SPI header.

* Shared/API/Cocoa/RemoteObjectInvocation.h:
(WebKit::RemoteObjectInvocation::ReplyInfo::ReplyInfo):
(WebKit::RemoteObjectInvocation::replyInfo):
* Shared/API/Cocoa/RemoteObjectInvocation.mm:
(WebKit::RemoteObjectInvocation::RemoteObjectInvocation):
(WebKit::RemoteObjectInvocation::encode):
(WebKit::RemoteObjectInvocation::decode):
Add an optional ReplyInfo struct to RemoteObjectInvocation.

* Shared/API/Cocoa/_WKRemoteObjectRegistry.mm:
(generateReplyIdentifier):
Helper function to generate a reply identifier.

(-[_WKRemoteObjectRegistry _sendInvocation:interface:]):
Do some block parameter validation.

* WebKit2.xcodeproj/project.pbxproj:

Tools:

Add a test. We only test the encoding right now.

* TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h:
* TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.mm:
(TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistryPlugIn.mm:
(-[RemoteObjectRegistryPlugIn sayHello:completionHandler:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191831 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/Platform/spi/Cocoa/BlockSPI.h [new file with mode: 0644]
Source/WebKit2/Shared/API/Cocoa/RemoteObjectInvocation.h
Source/WebKit2/Shared/API/Cocoa/RemoteObjectInvocation.mm
Source/WebKit2/Shared/API/Cocoa/_WKRemoteObjectRegistry.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.mm
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistryPlugIn.mm

index 2224a46..482670a 100644 (file)
@@ -1,3 +1,31 @@
+2015-10-30  Anders Carlsson  <andersca@apple.com>
+
+        Begin work on supporting reply blocks in _WKRemoteObjectRegistry
+        https://bugs.webkit.org/show_bug.cgi?id=150739
+
+        Reviewed by Tim Horton.
+
+        * Platform/spi/Cocoa/BlockSPI.h:
+        Add SPI header.
+
+        * Shared/API/Cocoa/RemoteObjectInvocation.h:
+        (WebKit::RemoteObjectInvocation::ReplyInfo::ReplyInfo):
+        (WebKit::RemoteObjectInvocation::replyInfo):
+        * Shared/API/Cocoa/RemoteObjectInvocation.mm:
+        (WebKit::RemoteObjectInvocation::RemoteObjectInvocation):
+        (WebKit::RemoteObjectInvocation::encode):
+        (WebKit::RemoteObjectInvocation::decode):
+        Add an optional ReplyInfo struct to RemoteObjectInvocation.
+
+        * Shared/API/Cocoa/_WKRemoteObjectRegistry.mm:
+        (generateReplyIdentifier):
+        Helper function to generate a reply identifier.
+
+        (-[_WKRemoteObjectRegistry _sendInvocation:interface:]):
+        Do some block parameter validation.
+
+        * WebKit2.xcodeproj/project.pbxproj:
+
 2015-10-30  Beth Dakin  <bdakin@apple.com>
 
         Link preview doesn't work on XHTML pages with Content-Type header as 
diff --git a/Source/WebKit2/Platform/spi/Cocoa/BlockSPI.h b/Source/WebKit2/Platform/spi/Cocoa/BlockSPI.h
new file mode 100644 (file)
index 0000000..dd255da
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if USE(APPLE_INTERNAL_SDK)
+
+#import <Block_private.h>
+
+#else
+
+#import <Block.h>
+
+BLOCK_EXPORT const char* _Block_signature(void*);
+
+#endif
index 123a610..f1e07f7 100644 (file)
@@ -38,11 +38,22 @@ namespace WebKit {
 
 class RemoteObjectInvocation {
 public:
+    struct ReplyInfo {
+        ReplyInfo(uint64_t replyID, String&& blockSignature)
+            : replyID(replyID)
+            , blockSignature(WTF::move(blockSignature))
+        {
+        }
+
+        const uint64_t replyID;
+        const String blockSignature;
+    };
     RemoteObjectInvocation();
-    RemoteObjectInvocation(const String& interfaceIdentifier, RefPtr<API::Dictionary>&& encodedInvocation);
+    RemoteObjectInvocation(const String& interfaceIdentifier, RefPtr<API::Dictionary>&& encodedInvocation, std::unique_ptr<ReplyInfo>&&);
 
     const String& interfaceIdentifier() const { return m_interfaceIdentifier; }
     const API::Dictionary* encodedInvocation() const { return m_encodedInvocation.get(); }
+    const ReplyInfo* replyInfo() const { return m_replyInfo.get(); }
 
     void encode(IPC::ArgumentEncoder&) const;
     static bool decode(IPC::ArgumentDecoder&, RemoteObjectInvocation&);
@@ -50,6 +61,7 @@ public:
 private:
     String m_interfaceIdentifier;
     RefPtr<API::Dictionary> m_encodedInvocation;
+    std::unique_ptr<ReplyInfo> m_replyInfo;
 };
 
 }
index 2c4a528..b5911a3 100644 (file)
@@ -35,9 +35,10 @@ RemoteObjectInvocation::RemoteObjectInvocation()
 {
 }
 
-RemoteObjectInvocation::RemoteObjectInvocation(const String& interfaceIdentifier, RefPtr<API::Dictionary>&& encodedInvocation)
+RemoteObjectInvocation::RemoteObjectInvocation(const String& interfaceIdentifier, RefPtr<API::Dictionary>&& encodedInvocation, std::unique_ptr<ReplyInfo>&& replyInfo)
     : m_interfaceIdentifier(interfaceIdentifier)
     , m_encodedInvocation(WTF::move(encodedInvocation))
+    , m_replyInfo(WTF::move(replyInfo))
 {
 }
 
@@ -45,6 +46,11 @@ void RemoteObjectInvocation::encode(IPC::ArgumentEncoder& encoder) const
 {
     encoder << m_interfaceIdentifier;
     UserData::encode(encoder, m_encodedInvocation.get());
+    if (m_replyInfo) {
+        encoder << true;
+        encoder << m_replyInfo->replyID;
+        encoder << m_replyInfo->blockSignature;
+    }
 }
 
 bool RemoteObjectInvocation::decode(IPC::ArgumentDecoder& decoder, RemoteObjectInvocation& result)
@@ -61,6 +67,22 @@ bool RemoteObjectInvocation::decode(IPC::ArgumentDecoder& decoder, RemoteObjectI
 
     result.m_encodedInvocation = static_cast<API::Dictionary*>(encodedInvocation.get());
 
+    bool hasReplyInfo;
+    if (!decoder.decode(hasReplyInfo))
+        return false;
+
+    if (hasReplyInfo) {
+        uint64_t replyID;
+        if (!decoder.decode(replyID))
+            return false;
+
+        String blockSignature;
+        if (!decoder.decode(blockSignature))
+            return false;
+
+        result.m_replyInfo = std::make_unique<ReplyInfo>(replyID, WTF::move(blockSignature));
+    }
+
     return true;
 }
 
index 34e8ff0..1f974df 100644 (file)
@@ -29,6 +29,7 @@
 #if WK_API_ENABLED
 
 #import "APIDictionary.h"
+#import "BlockSPI.h"
 #import "Connection.h"
 #import "RemoteObjectInvocation.h"
 #import "RemoteObjectRegistry.h"
@@ -94,15 +95,52 @@ using namespace WebKit;
     _remoteObjectRegistry = nullptr;
 }
 
+static uint64_t generateReplyIdentifier()
+{
+    static uint64_t identifier;
+
+    return ++identifier;
+}
+
 - (void)_sendInvocation:(NSInvocation *)invocation interface:(_WKRemoteObjectInterface *)interface
 {
-    auto encoder = adoptNS([[WKRemoteObjectEncoder alloc] init]);
+    std::unique_ptr<RemoteObjectInvocation::ReplyInfo> replyInfo;
+
+    NSMethodSignature *methodSignature = invocation.methodSignature;
+    for (NSUInteger i = 0, count = methodSignature.numberOfArguments; i < count; ++i) {
+        const char *type = [methodSignature getArgumentTypeAtIndex:i];
+
+        if (strcmp(type, "@?"))
+            continue;
+
+        if (replyInfo)
+            [NSException raise:NSInvalidArgumentException format:@"Only one reply block is allowed per message send. (%s)", sel_getName(invocation.selector)];
+
+        id block = nullptr;
+        [invocation getArgument:&block atIndex:i];
+        if (!block)
+            [NSException raise:NSInvalidArgumentException format:@"A NULL reply block was passed into a message. (%s)", sel_getName(invocation.selector)];
+
+        const char* replyBlockSignature = _Block_signature(block);
+
+        if (strcmp([NSMethodSignature signatureWithObjCTypes:replyBlockSignature].methodReturnType, "v"))
+            [NSException raise:NSInvalidArgumentException format:@"Return value of block argument must be 'void'. (%s)", sel_getName(invocation.selector)];
+
+        replyInfo = std::make_unique<RemoteObjectInvocation::ReplyInfo>(generateReplyIdentifier(), replyBlockSignature);
+
+        // Replace the block object so we won't try to encode it.
+        id null = nullptr;
+        [invocation setArgument:&null atIndex:i];
+    }
+
+    RetainPtr<WKRemoteObjectEncoder> encoder = adoptNS([[WKRemoteObjectEncoder alloc] init]);
+
     [encoder encodeObject:invocation forKey:invocationKey];
 
     if (!_remoteObjectRegistry)
         return;
 
-    _remoteObjectRegistry->sendInvocation(RemoteObjectInvocation(interface.identifier, [encoder rootObjectDictionary]));
+    _remoteObjectRegistry->sendInvocation(RemoteObjectInvocation(interface.identifier, [encoder rootObjectDictionary], WTF::move(replyInfo)));
 }
 
 - (WebKit::RemoteObjectRegistry&)remoteObjectRegistry
index 0aaa6f6..afc7525 100644 (file)
                1A5704F81BE01FF400874AF1 /* _WKContextMenuElementInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A5704F61BE01FF400874AF1 /* _WKContextMenuElementInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1A5704FB1BE1751100874AF1 /* RemoteObjectInvocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A5704F91BE1751100874AF1 /* RemoteObjectInvocation.mm */; };
                1A5704FC1BE1751100874AF1 /* RemoteObjectInvocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A5704FA1BE1751100874AF1 /* RemoteObjectInvocation.h */; };
+               1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A5705101BE410E500874AF1 /* BlockSPI.h */; };
                1A57109E1ABA0027002FABBE /* WKWebsiteDataStoreRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A57109C1ABA0027002FABBE /* WKWebsiteDataStoreRef.cpp */; };
                1A57109F1ABA0027002FABBE /* WKWebsiteDataStoreRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A57109D1ABA0027002FABBE /* WKWebsiteDataStoreRef.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1A5B1C501898606F004FCF9B /* WKNavigation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A5B1C4E1898606F004FCF9B /* WKNavigation.mm */; };
                1A5704F61BE01FF400874AF1 /* _WKContextMenuElementInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKContextMenuElementInfo.h; sourceTree = "<group>"; };
                1A5704F91BE1751100874AF1 /* RemoteObjectInvocation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RemoteObjectInvocation.mm; sourceTree = "<group>"; };
                1A5704FA1BE1751100874AF1 /* RemoteObjectInvocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteObjectInvocation.h; sourceTree = "<group>"; };
+               1A5705101BE410E500874AF1 /* BlockSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockSPI.h; sourceTree = "<group>"; };
                1A57109C1ABA0027002FABBE /* WKWebsiteDataStoreRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKWebsiteDataStoreRef.cpp; sourceTree = "<group>"; };
                1A57109D1ABA0027002FABBE /* WKWebsiteDataStoreRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebsiteDataStoreRef.h; sourceTree = "<group>"; };
                1A5B1C4E1898606F004FCF9B /* WKNavigation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKNavigation.mm; sourceTree = "<group>"; };
                3754D5411B3A2998003A4C7F /* Cocoa */ = {
                        isa = PBXGroup;
                        children = (
+                               1A5705101BE410E500874AF1 /* BlockSPI.h */,
                                3754D5441B3A29FD003A4C7F /* NSInvocationSPI.h */,
                        );
                        path = Cocoa;
                                BC204EE311C83E98008F3375 /* InjectedBundle.h in Headers */,
                                935EEBA2127761D0003322B8 /* InjectedBundleBackForwardList.h in Headers */,
                                935EEBA4127761D6003322B8 /* InjectedBundleBackForwardListItem.h in Headers */,
+                               1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */,
                                BCEE7DC5128B645D009827DA /* InjectedBundleClient.h in Headers */,
                                7CBB811D1AA0F8B1006B1942 /* InjectedBundleFileHandle.h in Headers */,
                                BC498618124D10E200D834E1 /* InjectedBundleHitTestResult.h in Headers */,
index c25b4a0..3fe6d4e 100644 (file)
@@ -1,3 +1,18 @@
+2015-10-30  Anders Carlsson  <andersca@apple.com>
+
+        Begin work on supporting reply blocks in _WKRemoteObjectRegistry
+        https://bugs.webkit.org/show_bug.cgi?id=150739
+
+        Reviewed by Tim Horton.
+
+        Add a test. We only test the encoding right now.
+
+        * TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.mm:
+        (TEST):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistryPlugIn.mm:
+        (-[RemoteObjectRegistryPlugIn sayHello:completionHandler:]):
+
 2015-10-30  Lucas Forschler  <lforschler@apple.com>
 
         Add CMAke builder to build.webkit.org
index 12ff539..53e110c 100644 (file)
@@ -30,6 +30,7 @@
 @protocol RemoteObjectProtocol <NSObject>
 
 - (void)sayHello:(NSString *)hello;
+- (void)sayHello:(NSString *)hello completionHandler:(void (^)(NSString *))completionHandler;
 
 @end
 
index 5e86fa5..f6d7ff4 100644 (file)
@@ -58,8 +58,11 @@ TEST(WebKit2, RemoteObjectRegistry)
             EXPECT_WK_STREQ(result, @"Hello, World!");
             isDone = true;
         }];
-
         TestWebKitAPI::Util::run(&isDone);
+
+        [object sayHello:@"Hello Again!" completionHandler:^(NSString *) {
+            // FIXME: Check the string here.
+        }];
     }
 }
 
index 8d85f03..e758094 100644 (file)
     [jsContext setObject:helloString forKeyedSubscript:@"helloString"];
 }
 
+- (void)sayHello:(NSString *)hello completionHandler:(void (^)(NSString *))completionHandler
+{
+    // FIXME: Actually call this.
+    // completionHandler([NSString stringWithFormat:@"Your string was '%@'", hello]);
+}
+
 @end
 
 #endif // WK_API_ENABLED