Clean up how we force invocations of API that happened on background threads over...
authormrowe@apple.com <mrowe@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Jan 2009 23:25:36 +0000 (23:25 +0000)
committermrowe@apple.com <mrowe@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Jan 2009 23:25:36 +0000 (23:25 +0000)
This was previously accomplished in a somewhat ad-hoc manner using a mutable dictionary to pass arguments
and return values back from the function.  The new approach is to use a proxy object that forwards an
NSInvocation over to the main thread and applies it to the target object, which leads to a much cleaner
call site.

Reviewed by Tim Hatcher.

* Misc/WebNSObjectExtras.h:
* Misc/WebNSObjectExtras.mm:
(-[WebMainThreadInvoker initWithTarget:]):
(-[WebMainThreadInvoker forwardInvocation:]):
(-[WebMainThreadInvoker methodSignatureForSelector:]):
(-[WebMainThreadInvoker handleException:]):
(-[NSInvocation _webkit_invokeAndHandleException:]): Execute the invocation and forward any exception that was
raised back to the WebMainThreadInvoker.
(-[NSObject _webkit_invokeOnMainThread]):

The following methods are updated to use the proxy object to forward methods to the main thread:

* WebView/WebArchive.mm:
(-[WebArchive initWithMainResource:subresources:subframeArchives:]):
(-[WebArchive mainResource]):
(-[WebArchive subresources]):
(-[WebArchive subframeArchives]):
* WebView/WebResource.mm:
(-[WebResource data]):
(-[WebResource URL]):
(-[WebResource MIMEType]):
(-[WebResource textEncodingName]):
(-[WebResource frameName]):
(-[WebResource _ignoreWhenUnarchiving]):
(-[WebResource _initWithData:URL:MIMEType:textEncodingName:frameName:response:copyData:]):
(-[WebResource _initWithData:URL:response:]):
(-[WebResource _suggestedFilename]):
(-[WebResource _response]):
(-[WebResource _stringValue]):
* WebView/WebView.mm:
(-[WebView initWithFrame:frameName:groupName:]):
(-[WebView initWithCoder:]):

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

WebKit/mac/ChangeLog
WebKit/mac/Misc/WebNSObjectExtras.h
WebKit/mac/Misc/WebNSObjectExtras.mm
WebKit/mac/WebView/WebArchive.mm
WebKit/mac/WebView/WebResource.mm
WebKit/mac/WebView/WebView.mm

index e000851..11f37d2 100644 (file)
@@ -1,3 +1,47 @@
+2009-01-21  Mark Rowe  <mrowe@apple.com>
+
+        Reviewed by Tim Hatcher.
+
+        Clean up how we force invocations of API that happened on background threads over to the main thread.
+
+        This was previously accomplished in a somewhat ad-hoc manner using a mutable dictionary to pass arguments
+        and return values back from the function.  The new approach is to use a proxy object that forwards an
+        NSInvocation over to the main thread and applies it to the target object, which leads to a much cleaner
+        call site.
+
+        * Misc/WebNSObjectExtras.h:
+        * Misc/WebNSObjectExtras.mm:
+        (-[WebMainThreadInvoker initWithTarget:]):
+        (-[WebMainThreadInvoker forwardInvocation:]):
+        (-[WebMainThreadInvoker methodSignatureForSelector:]):
+        (-[WebMainThreadInvoker handleException:]):
+        (-[NSInvocation _webkit_invokeAndHandleException:]): Execute the invocation and forward any exception that was
+        raised back to the WebMainThreadInvoker.
+        (-[NSObject _webkit_invokeOnMainThread]):
+
+        The following methods are updated to use the proxy object to forward methods to the main thread:
+
+        * WebView/WebArchive.mm:
+        (-[WebArchive initWithMainResource:subresources:subframeArchives:]):
+        (-[WebArchive mainResource]):
+        (-[WebArchive subresources]):
+        (-[WebArchive subframeArchives]):
+        * WebView/WebResource.mm:
+        (-[WebResource data]):
+        (-[WebResource URL]):
+        (-[WebResource MIMEType]):
+        (-[WebResource textEncodingName]):
+        (-[WebResource frameName]):
+        (-[WebResource _ignoreWhenUnarchiving]):
+        (-[WebResource _initWithData:URL:MIMEType:textEncodingName:frameName:response:copyData:]):
+        (-[WebResource _initWithData:URL:response:]):
+        (-[WebResource _suggestedFilename]):
+        (-[WebResource _response]):
+        (-[WebResource _stringValue]):
+        * WebView/WebView.mm:
+        (-[WebView initWithFrame:frameName:groupName:]):
+        (-[WebView initWithCoder:]):
+
 2009-01-20  Nikolas Zimmermann  <nikolas.zimmermann@torchmobile.com>
 
         Reviewed by George Staikos.
index 3638845..f327966 100644 (file)
@@ -54,6 +54,5 @@ static inline IMP method_setImplementation(Method m, IMP i)
 #endif
 
 @interface NSObject (WebNSObjectExtras)
-- (id)_webkit_performSelectorOnMainThread:(SEL)selector withObject:(id)object;
-- (id)_webkit_getPropertyOnMainThread:(SEL)selector;
+- (id)_webkit_invokeOnMainThread;
 @end
index 565f22c..2d682b9 100644 (file)
 
 #import "WebNSObjectExtras.h"
 
-@implementation NSObject (WebNSObjectExtras)
 
-- (void)_webkit_performSelectorWithArguments:(NSMutableDictionary *)arguments
+@interface WebMainThreadInvoker : NSProxy
 {
-    SEL selector = static_cast<SEL>([[arguments objectForKey:@"selector"] pointerValue]);
-    @try {
-        id object = [arguments objectForKey:@"object"];
-        id result = [self performSelector:selector withObject:object];
-        if (result)
-            [arguments setObject:result forKey:@"result"];
-    } @catch(NSException *exception) {
-        [arguments setObject:exception forKey:@"exception"];
+    id target;
+    id exception;
+}
+@end
+
+@implementation WebMainThreadInvoker
+
+- (id)initWithTarget:(id)theTarget
+{
+    target = theTarget;
+    return self;
+}
+
+- (void)forwardInvocation:(NSInvocation *)invocation
+{
+    [invocation setTarget:target];
+    [invocation retainArguments];
+    [invocation performSelectorOnMainThread:@selector(_webkit_invokeAndHandleException:) withObject:self waitUntilDone:YES];
+    if (exception) {
+        id exceptionToThrow = [exception autorelease];
+        exception = nil;
+        @throw exceptionToThrow;
     }
 }
 
-- (id)_webkit_performSelectorOnMainThread:(SEL)selector withObject:(id)object
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
+{
+    return [target methodSignatureForSelector:selector];
+}
+
+- (void)handleException:(id)e
 {
-    NSMutableDictionary *arguments = [[NSMutableDictionary alloc] init];
-    [arguments setObject:[NSValue valueWithPointer:selector] forKey:@"selector"];
-    if (object)
-        [arguments setObject:object forKey:@"object"];
+    exception = [e retain];
+}
+
+@end
 
-    [self performSelectorOnMainThread:@selector(_webkit_performSelectorWithArguments:) withObject:arguments waitUntilDone:TRUE];
 
-    NSException *exception = [[[arguments objectForKey:@"exception"] retain] autorelease];
-    id value = [[[arguments objectForKey:@"result"] retain] autorelease];
-    [arguments release];
+@implementation NSInvocation (WebMainThreadInvoker)
 
-    if (exception)
-        [exception raise];
-    return value;
+- (void)_webkit_invokeAndHandleException:(WebMainThreadInvoker *)exceptionHandler
+{
+    @try {
+        [self invoke];
+    } @catch (id e) {
+        [exceptionHandler handleException:e];
+    }
 }
 
-- (id)_webkit_getPropertyOnMainThread:(SEL)selector
+@end
+
+
+@implementation NSObject (WebNSObjectExtras)
+
+- (id)_webkit_invokeOnMainThread
 {
-    return [self _webkit_performSelectorOnMainThread:selector withObject:nil];
+    return [[[WebMainThreadInvoker alloc] initWithTarget:self] autorelease];
 }
 
 @end
index 685255d..5fbfef4 100644 (file)
@@ -159,20 +159,8 @@ static BOOL isArrayOfClass(id object, Class elementClass)
 - (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
 {
 #ifdef MAIL_THREAD_WORKAROUND
-    if (needMailThreadWorkaround()) {
-        // Maybe this could be done more cleanly with NSInvocation.
-        NSMutableDictionary *arguments = [[NSMutableDictionary alloc] init];
-        if (mainResource)
-            [arguments setObject:mainResource forKey:@"mainResource"];
-        if (subresources)
-            [arguments setObject:subresources forKey:@"subresources"];
-        if (subframeArchives)
-            [arguments setObject:subframeArchives forKey:@"subframeArchives"];
-
-        self = [self _webkit_performSelectorOnMainThread:@selector(_initWithArguments:) withObject:arguments];
-        [arguments release];
-        return self;
-    }
+    if (needMailThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -296,7 +284,7 @@ static BOOL isArrayOfClass(id object, Class elementClass)
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] mainResource];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -316,7 +304,7 @@ static BOOL isArrayOfClass(id object, Class elementClass)
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] subresources];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -348,7 +336,7 @@ static BOOL isArrayOfClass(id object, Class elementClass)
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] subframeArchives];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -422,19 +410,3 @@ static BOOL isArrayOfClass(id object, Class elementClass)
 }
 
 @end
-
-#ifdef MAIL_THREAD_WORKAROUND
-
-@implementation WebArchive (WebMailThreadWorkaround)
-
-- (id)_initWithArguments:(NSDictionary *)arguments
-{
-    WebResource *mainResource = [arguments objectForKey:@"mainResource"];
-    NSArray *subresources = [arguments objectForKey:@"subresources"];
-    NSArray *subframeArchives = [arguments objectForKey:@"subframeArchives"];
-    return [self initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives];
-}
-
-@end
-
-#endif
index 4d195ba..a5caa41 100644 (file)
@@ -202,7 +202,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] data];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -218,7 +218,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] URL];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -233,7 +233,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] MIMEType];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -248,7 +248,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] textEncodingName];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -263,7 +263,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] frameName];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -318,7 +318,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround()) {
-        [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:TRUE];
+        [[self _webkit_invokeOnMainThread] _ignoreWhenUnarchiving];
         return;
     }
 #endif
@@ -339,29 +339,8 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
            copyData:(BOOL)copyData
 {
 #ifdef MAIL_THREAD_WORKAROUND
-    if (needMailThreadWorkaround()) {
-        // Maybe this could be done more cleanly with NSInvocation.
-        NSMutableDictionary *arguments = [[NSMutableDictionary alloc] init];
-        if (data)
-            [arguments setObject:data forKey:@"data"];
-        if (URL)
-            [arguments setObject:URL forKey:@"URL"];
-        if (MIMEType)
-            [arguments setObject:MIMEType forKey:@"MIMEType"];
-        if (textEncodingName)
-            [arguments setObject:textEncodingName forKey:@"textEncodingName"];
-        if (frameName)
-            [arguments setObject:frameName forKey:@"frameName"];
-        if (response)
-            [arguments setObject:response forKey:@"response"];
-        if (copyData)
-            [arguments setObject:[NSNumber numberWithBool:YES] forKey:@"copyData"];
-
-        self = [self _webkit_performSelectorOnMainThread:@selector(_initWithArguments:) withObject:arguments];
-        [arguments release];
-
-        return self;
-    }
+    if (needMailThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] _initWithData:data URL:URL MIMEType:MIMEType textEncodingName:textEncodingName frameName:frameName response:response copyData:copyData];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -374,9 +353,9 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
         [self release];
         return nil;
     }
-            
+
     _private = [[WebResourcePrivate alloc] initWithCoreResource:ArchiveResource::create(SharedBuffer::wrapNSData(copyData ? [[data copy] autorelease] : data), URL, MIMEType, textEncodingName, frameName, response)];
-            
+
     return self;
 }
 
@@ -390,14 +369,14 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
               textEncodingName:[response textEncodingName]
                      frameName:nil
                       response:response
-                      copyData:NO];    
+                      copyData:NO];
 }
 
 - (NSString *)_suggestedFilename
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] _suggestedFilename];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -422,7 +401,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] _response];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -437,7 +416,7 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
 {
 #ifdef MAIL_THREAD_WORKAROUND
     if (needMailThreadWorkaround())
-        return [self _webkit_getPropertyOnMainThread:_cmd];
+        return [[self _webkit_invokeOnMainThread] _stringValue];
 #endif
 
     WebCoreThreadViolationCheck();
@@ -465,18 +444,6 @@ static NSString * const WebResourceResponseKey =          @"WebResourceResponse"
     return isOldMail;
 }
 
-- (id)_initWithArguments:(NSDictionary *)arguments
-{
-    NSData *data = [arguments objectForKey:@"data"];
-    NSURL *URL = [arguments objectForKey:@"URL"];
-    NSString *MIMEType = [arguments objectForKey:@"MIMEType"];
-    NSString *textEncodingName = [arguments objectForKey:@"textEncodingName"];
-    NSString *frameName = [arguments objectForKey:@"frameName"];
-    NSURLResponse *response = [arguments objectForKey:@"response"];
-    BOOL copyData = [[arguments objectForKey:@"copyData"] boolValue];
-    return [self _initWithData:data URL:URL MIMEType:MIMEType textEncodingName:textEncodingName frameName:frameName response:response copyData:copyData];
-}
-
 @end
 
 #endif
index 3175b58..ff7c3a3 100644 (file)
@@ -2279,18 +2279,8 @@ static bool needsWebViewInitThreadWorkaround()
 
 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName
 {
-    if (needsWebViewInitThreadWorkaround()) {
-        NSMutableDictionary *arguments = [[NSMutableDictionary alloc] initWithCapacity:3];
-        [arguments setObject:[NSValue valueWithRect:f] forKey:@"frame"];
-        if (frameName)
-            [arguments setObject:frameName forKey:@"frameName"];
-        if (groupName)
-            [arguments setObject:groupName forKey:@"groupName"];
-
-        self = [self _webkit_performSelectorOnMainThread:@selector(_initWithArguments:) withObject:arguments];
-        [arguments release];
-        return self;
-    }
+    if (needsWebViewInitThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] initWithFrame:f frameName:frameName groupName:groupName];
 
     WebCoreThreadViolationCheck();
     return [self _initWithFrame:f frameName:frameName groupName:groupName usesDocumentViews:YES];
@@ -2298,12 +2288,8 @@ static bool needsWebViewInitThreadWorkaround()
 
 - (id)initWithCoder:(NSCoder *)decoder
 {
-    if (needsWebViewInitThreadWorkaround()) {
-        NSDictionary *arguments = [[NSDictionary alloc] initWithObjectsAndKeys:decoder, @"decoder", nil];
-        self = [self _webkit_performSelectorOnMainThread:@selector(_initWithArguments:) withObject:arguments];
-        [arguments release];
-        return self;
-    }
+    if (needsWebViewInitThreadWorkaround())
+        return [[self _webkit_invokeOnMainThread] initWithCoder:decoder];
 
     WebCoreThreadViolationCheck();
     WebView *result = nil;