Clean up the WKRemoteObjectEncoder code
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Nov 2013 19:24:38 +0000 (19:24 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Nov 2013 19:24:38 +0000 (19:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123811

Reviewed by Dan Bernstein.

Add a new object stream array to be used for the non-keyed encoding values
and free functions for encoding values to the object stream. Simplify object encoding
by moving the dictionary creation out into a separate function and ditching the block based methods.

* Shared/API/Cocoa/WKRemoteObjectCoder.mm:
(ensureObjectStream):
Add helper function to create an object stream.

(encodeToObjectStream):
Add overloads for encoding values into the object streams.

(encodeInvocation):
Add helper function for encoding an NSInvocation.

(encodeObject):
Call encodeInvocation if needed, otherwise just use encodeWithCoder:.

(createEncodedObject):
Helper function that sets up a dictionary, encodes the object into the dictionary and then returns the dictionary.

(-[WKRemoteObjectEncoder encodeObject:forKey:]):
Call createEncodedObject.

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

Source/WebKit2/ChangeLog
Source/WebKit2/Shared/API/Cocoa/WKRemoteObjectCoder.mm

index 0d8bde0..6e59574 100644 (file)
@@ -1,3 +1,33 @@
+2013-11-05  Anders Carlsson  <andersca@apple.com>
+
+        Clean up the WKRemoteObjectEncoder code
+        https://bugs.webkit.org/show_bug.cgi?id=123811
+
+        Reviewed by Dan Bernstein.
+
+        Add a new object stream array to be used for the non-keyed encoding values
+        and free functions for encoding values to the object stream. Simplify object encoding
+        by moving the dictionary creation out into a separate function and ditching the block based methods.
+
+        * Shared/API/Cocoa/WKRemoteObjectCoder.mm:
+        (ensureObjectStream):
+        Add helper function to create an object stream.
+
+        (encodeToObjectStream):
+        Add overloads for encoding values into the object streams.
+
+        (encodeInvocation):
+        Add helper function for encoding an NSInvocation.
+
+        (encodeObject):
+        Call encodeInvocation if needed, otherwise just use encodeWithCoder:.
+
+        (createEncodedObject):
+        Helper function that sets up a dictionary, encodes the object into the dictionary and then returns the dictionary.
+
+        (-[WKRemoteObjectEncoder encodeObject:forKey:]):
+        Call createEncodedObject.    
+
 2013-11-04  Brady Eidson  <beidson@apple.com>
 
         IDB: Split backend Cursors and Transactions into their own files
index b19519e..b81696b 100644 (file)
 
 #if WK_API_ENABLED
 
+const char* const objectStreamKey = "$objectStream";
+
 using namespace WebKit;
 
+static PassRefPtr<ImmutableDictionary> createEncodedObject(WKRemoteObjectEncoder *, id);
+
 @interface NSMethodSignature (Details)
 - (NSString *)_typeString;
 @end
 
 @implementation WKRemoteObjectEncoder {
     RefPtr<MutableDictionary> _rootDictionary;
+    MutableArray* _objectStream;
+
     MutableDictionary* _currentDictionary;
 }
 
@@ -70,110 +76,132 @@ using namespace WebKit;
     return _rootDictionary.get();
 }
 
-- (BOOL)allowsKeyedCoding
+static void ensureObjectStream(WKRemoteObjectEncoder *encoder)
 {
-    return YES;
+    if (encoder->_objectStream)
+        return;
+
+    RefPtr<MutableArray> objectStream = MutableArray::create();
+    encoder->_objectStream = objectStream.get();
+
+    encoder->_rootDictionary->set(objectStreamKey, objectStream.release());
 }
 
-- (void)encodeObject:(id)object forKey:(NSString *)key
+static void encodeToObjectStream(WKRemoteObjectEncoder *encoder, double value)
 {
-    if ([object isKindOfClass:[NSInvocation class]]) {
-        // We have to special case NSInvocation since we don't want to encode the target.
-        [self _encodeInvocation:object forKey:key];
-        return;
-    }
+    ensureObjectStream(encoder);
 
-    if (![object conformsToProtocol:@protocol(NSSecureCoding)])
-        [NSException raise:NSInvalidArgumentException format:@"%@ does not conform to NSSecureCoding", object];
+    encoder->_objectStream->append(WebDouble::create(value));
+}
 
-    [self _encodeObjectForKey:key usingBlock:^{
-        [object encodeWithCoder:self];
-    }];
+static void encodeToObjectStream(WKRemoteObjectEncoder *encoder, int value)
+{
+    ensureObjectStream(encoder);
+
+    encoder->_objectStream->append(WebUInt64::create(value));
 }
 
-static NSString *escapeKey(NSString *key)
+static void encodeToObjectStream(WKRemoteObjectEncoder *encoder, id value)
 {
-    if (key.length && [key characterAtIndex:0] == '$')
-        return [@"$" stringByAppendingString:key];
+    ensureObjectStream(encoder);
 
-    return key;
+    encoder->_objectStream->append(createEncodedObject(encoder, value));
 }
 
-- (void)_encodeInvocation:(NSInvocation *)invocation forKey:(NSString *)key
+static void encodeInvocation(WKRemoteObjectEncoder *encoder, NSInvocation *invocation)
 {
-    [self _encodeObjectForKey:key usingBlock:^{
-        NSMethodSignature *methodSignature = invocation.methodSignature;
-        [self encodeObject:methodSignature._typeString forKey:@"typeString"];
-        [self encodeObject:NSStringFromSelector(invocation.selector) forKey:@"selector"];
-
-        NSUInteger argumentCount = methodSignature.numberOfArguments;
-
-        // The invocation should always have have self and _cmd arguments.
-        ASSERT(argumentCount >= 2);
-
-        RefPtr<MutableArray> arguments = MutableArray::create();
-
-        // We ignore self and _cmd.
-        for (NSUInteger i = 2; i < argumentCount; ++i) {
-            const char* type = [methodSignature getArgumentTypeAtIndex:i];
-
-            switch (*type) {
-            // double
-            case 'i': {
-                int value;
-                [invocation getArgument:&value atIndex:i];
-
-                arguments->append(WebUInt64::create(value));
-                break;
-            }
-
-            // int
-            case 'd': {
-                double value;
-                [invocation getArgument:&value atIndex:i];
-
-                arguments->append(WebDouble::create(value));
-                break;
-            }
-
-            // Objective-C object
-            case '@': {
-                id value;
-                [invocation getArgument:&value atIndex:i];
-
-                arguments->append([self _encodedObjectUsingBlock:^{
-                    [value encodeWithCoder:self];
-                }]);
-                break;
-            }
-
-            default:
-                [NSException raise:NSInvalidArgumentException format:@"Unsupported invocation argument type '%s'", type];
-            }
+    NSMethodSignature *methodSignature = invocation.methodSignature;
+    [encoder encodeObject:methodSignature._typeString forKey:@"typeString"];
+    [encoder encodeObject:NSStringFromSelector(invocation.selector) forKey:@"selector"];
+
+    NSUInteger argumentCount = methodSignature.numberOfArguments;
+
+    // The invocation should always have have self and _cmd arguments.
+    ASSERT(argumentCount >= 2);
+
+    // We ignore self and _cmd.
+    for (NSUInteger i = 2; i < argumentCount; ++i) {
+        const char* type = [methodSignature getArgumentTypeAtIndex:i];
+
+        switch (*type) {
+        // double
+        case 'd': {
+            double value;
+            [invocation getArgument:&value atIndex:i];
+
+            encodeToObjectStream(encoder, value);
+            break;
+        }
+
+        // int
+        case 'i': {
+            int value;
+            [invocation getArgument:&value atIndex:i];
+
+            encodeToObjectStream(encoder, value);
+            break;
+        }
+
+        // Objective-C object
+        case '@': {
+            id value;
+            [invocation getArgument:&value atIndex:i];
+
+            encodeToObjectStream(encoder, value);
+            break;
         }
 
-        _currentDictionary->set("arguments", arguments.release());
-    }];
+        default:
+            [NSException raise:NSInvalidArgumentException format:@"Unsupported invocation argument type '%s'", type];
+        }
+    }
 }
 
-- (void)encodeBytes:(const uint8_t *)bytes length:(NSUInteger)length forKey:(NSString *)key
+static void encodeObject(WKRemoteObjectEncoder *encoder, id object)
 {
-    _currentDictionary->set(escapeKey(key), WebData::create(bytes, length));
+    if ([object isKindOfClass:[NSInvocation class]]) {
+        // We have to special case NSInvocation since we don't want to encode the target.
+        encodeInvocation(encoder, object);
+        return;
+    }
+
+    if (![object conformsToProtocol:@protocol(NSSecureCoding)])
+        [NSException raise:NSInvalidArgumentException format:@"%@ does not conform to NSSecureCoding", object];
+
+    [object encodeWithCoder:encoder];
 }
 
-- (RefPtr<MutableDictionary>)_encodedObjectUsingBlock:(void (^)())block
+static PassRefPtr<ImmutableDictionary> createEncodedObject(WKRemoteObjectEncoder *encoder, id object)
 {
     RefPtr<MutableDictionary> dictionary = MutableDictionary::create();
+    TemporaryChange<MutableDictionary*> dictionaryChange(encoder->_currentDictionary, dictionary.get());
 
-    TemporaryChange<MutableDictionary*> dictionaryChange(_currentDictionary, dictionary.get());
-    block();
+    encodeObject(encoder, object);
 
     return dictionary;
 }
 
-- (void)_encodeObjectForKey:(NSString *)key usingBlock:(void (^)())block
+- (BOOL)allowsKeyedCoding
+{
+    return YES;
+}
+
+static NSString *escapeKey(NSString *key)
+{
+    if (key.length && [key characterAtIndex:0] == '$')
+        return [@"$" stringByAppendingString:key];
+
+    return key;
+}
+
+- (void)encodeObject:(id)object forKey:(NSString *)key
+{
+    _currentDictionary->set(escapeKey(key), createEncodedObject(self, object));
+}
+
+- (void)encodeBytes:(const uint8_t *)bytes length:(NSUInteger)length forKey:(NSString *)key
 {
-    _currentDictionary->set(escapeKey(key), [self _encodedObjectUsingBlock:block]);
+    _currentDictionary->set(escapeKey(key), WebData::create(bytes, length));
 }
 
 @end