Fixed ~2% performance regression problem. The regression
authorrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Apr 2003 19:34:42 +0000 (19:34 +0000)
committerrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Apr 2003 19:34:42 +0000 (19:34 +0000)
        was caused by the allocation of a forwarder on every
        delegate callback.  Modified code to only create forwarders once,
        and reset when delegates change.

        Reviewed by Ken.

        * WebCoreSupport.subproj/WebBridge.m:
        (-[WebBridge objectLoadedFromCacheWithURL:response:size:]):
        * WebView.subproj/WebBaseResourceHandleDelegate.h:
        * WebView.subproj/WebBaseResourceHandleDelegate.m:
        (-[WebBaseResourceHandleDelegate setDataSource:]):
        (-[WebBaseResourceHandleDelegate connection:willSendRequest:redirectResponse:]):
        (-[WebBaseResourceHandleDelegate connection:didReceiveResponse:]):
        (-[WebBaseResourceHandleDelegate connection:didReceiveData:]):
        (-[WebBaseResourceHandleDelegate connectionDidFinishLoading:]):
        * WebView.subproj/WebView.m:
        (-[WebView setWindowOperationsDelegate:]):
        (-[WebView setResourceLoadDelegate:]):
        (-[WebView setContextMenuDelegate:]):
        (-[WebView setPolicyDelegate:]):
        (-[WebView setLocationChangeDelegate:]):
        * WebView.subproj/WebViewPrivate.h:
        * WebView.subproj/WebViewPrivate.m:
        (-[WebViewPrivate dealloc]):
        (-[WebView _locationChangeDelegateForwarder]):
        (-[WebView _resourceLoadDelegateForwarder]):
        (-[WebView _cacheResourceLoadDelegateImplementations]):
        (-[WebView _resourceLoadDelegateImplementations]):
        (-[WebView _policyDelegateForwarder]):
        (-[WebView _contextMenuDelegateForwarder]):
        (-[WebView _windowOperationsDelegateForwarder]):
        (-[_WebSafeForwarder forwardInvocation:]):

        * API-Issues.rtf:
        Notes to self.

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

WebKit/API-Issues.rtf
WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebBridge.m
WebKit/WebView.subproj/WebBaseResourceHandleDelegate.h
WebKit/WebView.subproj/WebBaseResourceHandleDelegate.m
WebKit/WebView.subproj/WebLoader.h
WebKit/WebView.subproj/WebLoader.m
WebKit/WebView.subproj/WebView.m
WebKit/WebView.subproj/WebViewPrivate.h
WebKit/WebView.subproj/WebViewPrivate.m

index a6cba24..086dd40 100644 (file)
@@ -22,6 +22,8 @@
 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
 
 \f1\fs24 \cf0 \CocoaLigature1 \
+Need to add other more complete action methods to WebView.\
+\
 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
 \cf2 \
 It seems non-parallel that WebHistory has change notifications but WebBackForwardList doesn't.\
@@ -35,18 +37,6 @@ It seems non-parallel that WebHistory has change notifications but WebBackForwar
 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
 \cf0 Yes.\
 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
-\cf2 \
-WebHistoryItem\
----\
-\
-Even though we need to have the fields inline for performance, we should add a few void * ivars to the end for future extensibility.\
-\
-WebHistoryItemPrivate,h has a boatload of private methods with no leading underscore.\
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
-\cf0 Good point.\
-\
-\
 \
 On Thursday, March 20, 2003, at 11:43 AM, Ali Ozer wrote:\
 \
@@ -58,25 +48,6 @@ WebHistory:\
 \
 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li400\ql\qnatural
 
-\f2\fs20 \cf3 /*!\
-    @method initWithFile:\
-    @abstract The designated initializer for WebHistory.\
-    @result Returns an initialized WebHistory.\
-*/\
-- initWithFile: (NSString *)file;\
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
-
-\f1\fs24 \cf2 \
-Would it be better to have this take a URL instead?  Like many kit classes you could limit the URLs to those on the local disk for now; but at least the API would support history lists coming from the web...  (On the other hand with WebDav and all perhaps interesting history files from the web will always be representable via file names, I don't know.)\
-\
-The direction in new APIs has been to use URL instead of file names where applicable...\
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
-\cf0 OK.\
-\
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
-\cf2 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li400\ql\qnatural
-
 \f2\fs20 \cf3 - (NSArray *)orderedLastVisitedDays;\
 - (NSArray *)orderedEntriesLastVisitedOnDay: (NSCalendarDate *)calendarDate;\
 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
@@ -191,19 +162,61 @@ See NSArray, NSMutableArray, NSBundle, and NSSet for similar method names.\
 \
 P.S. The WebHistory.h file you dropped a few days ago doesn't contain the file->URL changes you mentioned. Can't write the method descriptions for this class until I get the new headers.\
 \
+
+\f0\b From: 
+\f1\b0 Richard Williamson <rjw@apple.com>\
+
+\f0\b Date: 
+\f1\b0 Mon Mar 31, 2003  4:31:00 PM US/Pacific\
+
+\f0\b To: 
+\f1\b0 Nancy Craighill <ncraighill@apple.com>\
+
+\f0\b Cc: 
+\f1\b0 Scott Anguish <sanguish@apple.com>\
+
+\f0\b Subject: 
+\f1\b0 Re: WK: Feedback on 3/28 Web Kit Headers\
+\
+\
+On Monday, March 31, 2003, at 03:24 PM, Nancy Craighill wrote:\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
+\cf2 Richard,\
+\
+Incorporated the API changes as of March 28th into the current reference docs and discovered these few nits with the headers:\
+\
+WebPreferences.h:\
+\
+(1)\
+- (void)setUserStyleSheetLocation:(NSURL *)string;\
+                                                                                ^ Should be URL.\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+\cf0 OK.\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
+\cf2 (2) The "Is" should be taken out of the following method names (e.g., Cocoa uses -isEnabled and -setEnabled: in NSCell, NSControl, NSFontManager, NSFontPanel, NSLayoutManager...):\
+\
+setIsJavaEnabled:\
+setIsJavaScriptEnabled:\
+\
+NOTE: It's true that a few methods in Cocoa (four to be exact) begin with "setIs" but those methods don't contain the key word "Enabled".\
 \
-From WebHistory.h:\
+(3) And to be consistent, remove the "are" from this method too:\
 \
-// Notifications sent when history is modified.\
-// The first two come with a userInfo dictionary with a single key "Entries", which contains\
-// an array of items that were added or removed.\
+setArePlugInsEnabled:\
 \
-The API has been updated to always call the things items instead of entries, but this key is:\
+Let me know if you decide NOT to make the changes above!\
 \
-    1) still "Entries"\
-    2) still a constant in a comment, rather than an NSString constant\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+\cf0 Gah!  I just changed these methods to include the "is" and "are"!  I thought you had made that suggestion, or maybe it was Ali.\
 \
-I think we should fix this.\
 \
-    -- Darin\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li200\ql\qnatural
+\cf2 \
+(4) You also dropped a WebResourceResponseExtras.h header which should have been replaced by WebNSURLResponseExtras.h, right??\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+\cf0 Yes.\
 }
\ No newline at end of file
index 19ff4f3..786132c 100644 (file)
@@ -1,3 +1,42 @@
+2003-04-01  Richard Williamson  <rjw@apple.com>
+
+        Fixed ~2% performance regression problem.  The regression
+        was caused by the allocation of a forwarder on every 
+        delegate callback.  Modified code to only create forwarders once,
+        and reset when delegates change.
+        
+        Reviewed by Ken.
+
+        * WebCoreSupport.subproj/WebBridge.m:
+        (-[WebBridge objectLoadedFromCacheWithURL:response:size:]):
+        * WebView.subproj/WebBaseResourceHandleDelegate.h:
+        * WebView.subproj/WebBaseResourceHandleDelegate.m:
+        (-[WebBaseResourceHandleDelegate setDataSource:]):
+        (-[WebBaseResourceHandleDelegate connection:willSendRequest:redirectResponse:]):
+        (-[WebBaseResourceHandleDelegate connection:didReceiveResponse:]):
+        (-[WebBaseResourceHandleDelegate connection:didReceiveData:]):
+        (-[WebBaseResourceHandleDelegate connectionDidFinishLoading:]):
+        * WebView.subproj/WebView.m:
+        (-[WebView setWindowOperationsDelegate:]):
+        (-[WebView setResourceLoadDelegate:]):
+        (-[WebView setContextMenuDelegate:]):
+        (-[WebView setPolicyDelegate:]):
+        (-[WebView setLocationChangeDelegate:]):
+        * WebView.subproj/WebViewPrivate.h:
+        * WebView.subproj/WebViewPrivate.m:
+        (-[WebViewPrivate dealloc]):
+        (-[WebView _locationChangeDelegateForwarder]):
+        (-[WebView _resourceLoadDelegateForwarder]):
+        (-[WebView _cacheResourceLoadDelegateImplementations]):
+        (-[WebView _resourceLoadDelegateImplementations]):
+        (-[WebView _policyDelegateForwarder]):
+        (-[WebView _contextMenuDelegateForwarder]):
+        (-[WebView _windowOperationsDelegateForwarder]):
+        (-[_WebSafeForwarder forwardInvocation:]):
+
+        * API-Issues.rtf:
+        Notes to self.
+        
 2003-04-01  Darin Adler  <darin@apple.com>
 
         * English.lproj/StringsNotToBeLocalized.txt: Allowed update-alex-localizable-strings
index ef76e92..7c0ee1e 100644 (file)
     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL _web_URLWithString:URL]];
     WebView *c = [frame webView];
     id delegate = [c resourceLoadDelegate];
-    id _delegate = [c _resourceLoadDelegateForwarder];
+    id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
     id identifier;
+    WebResourceDelegateImplementationCache implementations = [c _resourceLoadDelegateImplementations];
     
     // No chance for delegate to modify request, so we don't send a willSendRequest:redirectResponse: message.
-    if ([delegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
+    if (implementations.delegateImplementsIdentifierForRequest)
         identifier = [delegate webView:c identifierForInitialRequest: request fromDataSource: [self dataSource]];
     else
-        identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:c identifierForInitialRequest:request fromDataSource:[self dataSource]];
-    [_delegate webView:c resource: identifier didReceiveResponse: response fromDataSource: [self dataSource]];
-    [_delegate webView:c resource: identifier didReceiveContentLength: bytes fromDataSource: [self dataSource]];
-    [_delegate webView:c resource: identifier didFinishLoadingFromDataSource: [self dataSource]];
+        identifier = [sharedDelegate webView:c identifierForInitialRequest:request fromDataSource:[self dataSource]];
+    
+    if (implementations.delegateImplementsDidReceiveResponse)
+        [delegate webView:c resource: identifier didReceiveResponse: response fromDataSource: [self dataSource]];
+    else
+        [sharedDelegate webView:c resource: identifier didReceiveResponse: response fromDataSource: [self dataSource]];
+
+    if (implementations.delegateImplementsDidReceiveContentLength)
+        [delegate webView:c resource: identifier didReceiveContentLength: bytes fromDataSource: [self dataSource]];
+    else
+        [sharedDelegate webView:c resource: identifier didReceiveContentLength: bytes fromDataSource: [self dataSource]];
+
+    if (implementations.delegateImplementsDidFinishLoadingFromDataSource)
+        [delegate webView:c resource: identifier didFinishLoadingFromDataSource: [self dataSource]];
+    else
+        [sharedDelegate webView:c resource: identifier didFinishLoadingFromDataSource: [self dataSource]];
     
     [[frame webView] _finishedLoadingResourceFromDataSource:[self dataSource]];
+
     [request release];
 }
 
index 94c7dd4..40c18e0 100644 (file)
@@ -5,6 +5,8 @@
 
 #import <Foundation/Foundation.h>
 
+#import <WebKit/WebViewPrivate.h>
+
 @class WebView;
 @class WebDataSource;
 @class WebError;
@@ -29,6 +31,7 @@
     NSURL *currentURL;
     BOOL reachedTerminalState;
     BOOL defersCallbacks;
+    WebResourceDelegateImplementationCache implementations;
 }
 
 - (BOOL)loadWithRequest:(NSURLRequest *)request;
index 7c75176..920e807 100644 (file)
     
     [resourceLoadDelegate release];
     resourceLoadDelegate = [[controller resourceLoadDelegate] retain];
+    implementations = [controller _resourceLoadDelegateImplementations];
 
     [downloadDelegate release];
     downloadDelegate = [[controller downloadDelegate] retain];
     if (identifier == nil) {
         // The identifier is released after the last callback, rather than in dealloc
         // to avoid potential cycles.
-        if ([resourceLoadDelegate respondsToSelector: @selector(webView:identifierForInitialRequest:fromDataSource:)])
+        if (implementations.delegateImplementsIdentifierForRequest)
             identifier = [[resourceLoadDelegate webView: controller identifierForInitialRequest:newRequest fromDataSource:dataSource] retain];
         else
             identifier = [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller identifierForInitialRequest:newRequest fromDataSource:dataSource] retain];
     }
 
-    if (resourceLoadDelegate) {
-        if ([resourceLoadDelegate respondsToSelector: @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)])
-            newRequest = [resourceLoadDelegate webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
-        else
-            newRequest = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
-    }
+    if (implementations.delegateImplementsWillSendRequest)
+        newRequest = [resourceLoadDelegate webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
+    else
+        newRequest = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
 
     // Store a copy of the request.
     [request autorelease];
     response = r;
 
     [dataSource _addResponse: r];
-    [[controller _resourceLoadDelegateForwarder] webView:controller resource:identifier didReceiveResponse:r fromDataSource:dataSource];
+    
+    if (implementations.delegateImplementsDidReceiveResponse)
+        [resourceLoadDelegate webView:controller resource:identifier didReceiveResponse:r fromDataSource:dataSource];
+    else
+        [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier didReceiveResponse:r fromDataSource:dataSource];
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data
     ASSERT(con == connection);
     ASSERT(!reachedTerminalState);
 
-    [[controller _resourceLoadDelegateForwarder] webView:controller resource:identifier didReceiveContentLength:[data length] fromDataSource:dataSource];
+    if (implementations.delegateImplementsDidReceiveContentLength)
+        [resourceLoadDelegate webView:controller resource:identifier didReceiveContentLength:[data length] fromDataSource:dataSource];
+    else
+        [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier didReceiveContentLength:[data length] fromDataSource:dataSource];
 }
 
 - (void)connectionDidFinishLoading:(NSURLConnection *)con
     ASSERT(con == connection);
     ASSERT(!reachedTerminalState);
 
-    [[controller _resourceLoadDelegateForwarder] webView:controller resource:identifier didFinishLoadingFromDataSource:dataSource];
+    if (implementations.delegateImplementsDidFinishLoadingFromDataSource)
+        [resourceLoadDelegate webView:controller resource:identifier didFinishLoadingFromDataSource:dataSource];
+    else
+        [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier didFinishLoadingFromDataSource:dataSource];
 
     ASSERT(currentURL);
     [[WebStandardPanels sharedStandardPanels] _didStopLoadingURL:currentURL inController:controller];
index 94c7dd4..40c18e0 100644 (file)
@@ -5,6 +5,8 @@
 
 #import <Foundation/Foundation.h>
 
+#import <WebKit/WebViewPrivate.h>
+
 @class WebView;
 @class WebDataSource;
 @class WebError;
@@ -29,6 +31,7 @@
     NSURL *currentURL;
     BOOL reachedTerminalState;
     BOOL defersCallbacks;
+    WebResourceDelegateImplementationCache implementations;
 }
 
 - (BOOL)loadWithRequest:(NSURLRequest *)request;
index 7c75176..920e807 100644 (file)
     
     [resourceLoadDelegate release];
     resourceLoadDelegate = [[controller resourceLoadDelegate] retain];
+    implementations = [controller _resourceLoadDelegateImplementations];
 
     [downloadDelegate release];
     downloadDelegate = [[controller downloadDelegate] retain];
     if (identifier == nil) {
         // The identifier is released after the last callback, rather than in dealloc
         // to avoid potential cycles.
-        if ([resourceLoadDelegate respondsToSelector: @selector(webView:identifierForInitialRequest:fromDataSource:)])
+        if (implementations.delegateImplementsIdentifierForRequest)
             identifier = [[resourceLoadDelegate webView: controller identifierForInitialRequest:newRequest fromDataSource:dataSource] retain];
         else
             identifier = [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller identifierForInitialRequest:newRequest fromDataSource:dataSource] retain];
     }
 
-    if (resourceLoadDelegate) {
-        if ([resourceLoadDelegate respondsToSelector: @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)])
-            newRequest = [resourceLoadDelegate webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
-        else
-            newRequest = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
-    }
+    if (implementations.delegateImplementsWillSendRequest)
+        newRequest = [resourceLoadDelegate webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
+    else
+        newRequest = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier willSendRequest:newRequest redirectResponse:redirectResponse fromDataSource:dataSource];
 
     // Store a copy of the request.
     [request autorelease];
     response = r;
 
     [dataSource _addResponse: r];
-    [[controller _resourceLoadDelegateForwarder] webView:controller resource:identifier didReceiveResponse:r fromDataSource:dataSource];
+    
+    if (implementations.delegateImplementsDidReceiveResponse)
+        [resourceLoadDelegate webView:controller resource:identifier didReceiveResponse:r fromDataSource:dataSource];
+    else
+        [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier didReceiveResponse:r fromDataSource:dataSource];
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data
     ASSERT(con == connection);
     ASSERT(!reachedTerminalState);
 
-    [[controller _resourceLoadDelegateForwarder] webView:controller resource:identifier didReceiveContentLength:[data length] fromDataSource:dataSource];
+    if (implementations.delegateImplementsDidReceiveContentLength)
+        [resourceLoadDelegate webView:controller resource:identifier didReceiveContentLength:[data length] fromDataSource:dataSource];
+    else
+        [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier didReceiveContentLength:[data length] fromDataSource:dataSource];
 }
 
 - (void)connectionDidFinishLoading:(NSURLConnection *)con
     ASSERT(con == connection);
     ASSERT(!reachedTerminalState);
 
-    [[controller _resourceLoadDelegateForwarder] webView:controller resource:identifier didFinishLoadingFromDataSource:dataSource];
+    if (implementations.delegateImplementsDidFinishLoadingFromDataSource)
+        [resourceLoadDelegate webView:controller resource:identifier didFinishLoadingFromDataSource:dataSource];
+    else
+        [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:controller resource:identifier didFinishLoadingFromDataSource:dataSource];
 
     ASSERT(currentURL);
     [[WebStandardPanels sharedStandardPanels] _didStopLoadingURL:currentURL inController:controller];
index 77982bb..ecbb4e5 100644 (file)
@@ -154,6 +154,8 @@ NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
 - (void)setWindowOperationsDelegate:delegate
 {
     _private->windowContext = delegate;
+    [_private->windowOperationsDelegateForwarder release];
+    _private->windowOperationsDelegateForwarder = nil;
 }
 
 - windowOperationsDelegate
@@ -164,6 +166,9 @@ NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
 - (void)setResourceLoadDelegate: delegate
 {
     _private->resourceProgressDelegate = delegate;
+    [_private->resourceProgressDelegateForwarder release];
+    _private->resourceProgressDelegateForwarder = nil;
+    [self _cacheResourceLoadDelegateImplementations];
 }
 
 
@@ -187,6 +192,8 @@ NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
 - (void)setContextMenuDelegate: delegate
 {
     _private->contextMenuDelegate = delegate;
+    [_private->contextMenuDelegateForwarder release];
+    _private->contextMenuDelegateForwarder = nil;
 }
 
 - contextMenuDelegate
@@ -197,6 +204,8 @@ NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
 - (void)setPolicyDelegate:delegate
 {
     _private->policyDelegate = delegate;
+    [_private->policyDelegateForwarder release];
+    _private->policyDelegateForwarder = nil;
 }
 
 - policyDelegate
@@ -207,6 +216,8 @@ NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
 - (void)setLocationChangeDelegate:delegate
 {
     _private->locationChangeDelegate = delegate;
+    [_private->locationChangeDelegateForwarder release];
+    _private->locationChangeDelegateForwarder = nil;
 }
 
 - locationChangeDelegate
index a4bcf0c..ced862c 100644 (file)
@@ -2,7 +2,6 @@
     WebViewPrivate.m
     Copyright 2001, Apple, Inc. All rights reserved.
 */
-
 #import <WebKit/WebPolicyDelegate.h>
 #import <WebKit/WebView.h>
 
@@ -18,17 +17,30 @@ enum { NumUserAgentStringTypes = WinIE + 1 };
 
 #define NUM_LOCATION_CHANGE_DELEGATE_SELECTORS 10
 
+typedef struct _WebResourceDelegateImplementationCache {
+    uint delegateImplementsDidReceiveResponse:1;
+    uint delegateImplementsDidReceiveContentLength:1;
+    uint delegateImplementsDidFinishLoadingFromDataSource:1;
+    uint delegateImplementsWillSendRequest:1;
+    uint delegateImplementsIdentifierForRequest:1;
+} WebResourceDelegateImplementationCache;
+
 @interface WebViewPrivate : NSObject
 {
 @public
     WebFrame *mainFrame;
     
     id windowContext;
+    id windowOperationsDelegateForwarder;
     id resourceProgressDelegate;
+    id resourceProgressDelegateForwarder;
     id downloadDelegate;
     id contextMenuDelegate;
+    id contextMenuDelegateForwarder;
     id policyDelegate;
+    id policyDelegateForwarder;
     id locationChangeDelegate;
+    id locationChangeDelegateForwarder;
     id <WebFormDelegate> formDelegate;
     
     id defaultContextMenuDelegate;
@@ -52,6 +64,8 @@ enum { NumUserAgentStringTypes = WinIE + 1 };
     BOOL lastElementWasNonNil;
 
     NSWindow *hostWindow;
+    
+    WebResourceDelegateImplementationCache resourceLoadDelegateImplementations;
 }
 @end
 
@@ -124,6 +138,8 @@ enum { NumUserAgentStringTypes = WinIE + 1 };
 
 - _locationChangeDelegateForwarder;
 - _resourceLoadDelegateForwarder;
+- (void)_cacheResourceLoadDelegateImplementations;
+- (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations;
 - _policyDelegateForwarder;
 - _contextMenuDelegateForwarder;
 - _windowOperationsDelegateForwarder;
@@ -135,6 +151,7 @@ enum { NumUserAgentStringTypes = WinIE + 1 };
     id defaultTarget;
     Class templateClass;
 }
+- initWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
 + safeForwarderWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
 @end
 
index 9a7e197..8f3b9af 100644 (file)
     [settings release];
     [hostWindow release];
     
+    [policyDelegateForwarder release];
+    [contextMenuDelegateForwarder release];
+    [resourceProgressDelegateForwarder release];
+    [windowOperationsDelegateForwarder release];
+    [locationChangeDelegateForwarder release];
+    
     [super dealloc];
 }
 
 
 - _locationChangeDelegateForwarder
 {
-    return [_WebSafeForwarder safeForwarderWithTarget: [self locationChangeDelegate]  defaultTarget: [WebDefaultLocationChangeDelegate sharedLocationChangeDelegate] templateClass: [WebDefaultLocationChangeDelegate class]];
+    if (!_private->locationChangeDelegateForwarder)
+        _private->locationChangeDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self locationChangeDelegate]  defaultTarget: [WebDefaultLocationChangeDelegate sharedLocationChangeDelegate] templateClass: [WebDefaultLocationChangeDelegate class]];
+    return _private->locationChangeDelegateForwarder;
 }
 
 - _resourceLoadDelegateForwarder
 {
-    return [_WebSafeForwarder safeForwarderWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
+    if (!_private->resourceProgressDelegateForwarder)
+        _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
+    return _private->resourceProgressDelegateForwarder;
+}
+
+- (void)_cacheResourceLoadDelegateImplementations
+{
+    if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didFinishLoadingFromDataSource:)])
+        _private->resourceLoadDelegateImplementations.delegateImplementsDidFinishLoadingFromDataSource = YES;
+    if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didReceiveContentLength:fromDataSource:)])
+        _private->resourceLoadDelegateImplementations.delegateImplementsDidReceiveContentLength = YES;
+    if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didReceiveResponse:fromDataSource:)])
+        _private->resourceLoadDelegateImplementations.delegateImplementsDidReceiveResponse = YES;
+    if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)])
+        _private->resourceLoadDelegateImplementations.delegateImplementsWillSendRequest = YES;
+    if ([[self resourceLoadDelegate] respondsToSelector: @selector(webView:identifierForInitialRequest:fromDataSource:)])
+        _private->resourceLoadDelegateImplementations.delegateImplementsIdentifierForRequest = YES;
+}
+
+- (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations
+{
+    return _private->resourceLoadDelegateImplementations;
 }
 
 - _policyDelegateForwarder
 {
-    return [_WebSafeForwarder safeForwarderWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
+    if (!_private->policyDelegateForwarder)
+        _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
+    return _private->policyDelegateForwarder;
 }
 
 - _contextMenuDelegateForwarder
 {
-    return [_WebSafeForwarder safeForwarderWithTarget: [self contextMenuDelegate] defaultTarget: [WebDefaultContextMenuDelegate sharedContextMenuDelegate] templateClass: [WebDefaultContextMenuDelegate class]];
+    if (!_private->contextMenuDelegateForwarder)
+        _private->contextMenuDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self contextMenuDelegate] defaultTarget: [WebDefaultContextMenuDelegate sharedContextMenuDelegate] templateClass: [WebDefaultContextMenuDelegate class]];
+    return _private->contextMenuDelegateForwarder;
 }
 
 - _windowOperationsDelegateForwarder
 {
-    return [_WebSafeForwarder safeForwarderWithTarget: [self windowOperationsDelegate] defaultTarget: [WebDefaultWindowOperationsDelegate sharedWindowOperationsDelegate] templateClass: [WebDefaultWindowOperationsDelegate class]];
+    if (!_private->windowOperationsDelegateForwarder)
+        _private->windowOperationsDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self windowOperationsDelegate] defaultTarget: [WebDefaultWindowOperationsDelegate sharedWindowOperationsDelegate] templateClass: [WebDefaultWindowOperationsDelegate class]];
+    return _private->windowOperationsDelegateForwarder;
 }
 
 
     return [[[_WebSafeForwarder alloc] initWithTarget: t defaultTarget: dt templateClass: aClass] autorelease];
 }
 
+#ifndef NDEBUG
+NSMutableDictionary *countInvocations;
+#endif
+
 - (void)forwardInvocation:(NSInvocation *)anInvocation
 {
+#ifndef NDEBUG
+    if (!countInvocations){
+        countInvocations = [[NSMutableDictionary alloc] init];
+    }
+    NSNumber *count = [countInvocations objectForKey: NSStringFromSelector([anInvocation selector])];
+    if (!count)
+        count = [NSNumber numberWithInt: 1];
+    else
+        count = [NSNumber numberWithInt: [count intValue] + 1];
+    [countInvocations setObject: count forKey: NSStringFromSelector([anInvocation selector])];
+#endif
     if ([target respondsToSelector: [anInvocation selector]])
         [anInvocation invokeWithTarget: target];
     else if ([defaultTarget respondsToSelector: [anInvocation selector]])