diff options
Diffstat (limited to 'WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm')
-rw-r--r-- | WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm | 1599 |
1 files changed, 1599 insertions, 0 deletions
diff --git a/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm b/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm new file mode 100644 index 0000000..eb538e0 --- /dev/null +++ b/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm @@ -0,0 +1,1599 @@ +/* + * Copyright (C) 2006, 2007, 2008 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 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. + */ + +#import "WebFrameLoaderClient.h" + +// Terrible hack; lets us get at the WebFrame private structure. +#define private public +#import "WebFrame.h" +#undef private + +#import "DOMElementInternal.h" +#import "WebBackForwardList.h" +#import "WebCachedPagePlatformData.h" +#import "WebChromeClient.h" +#import "WebDataSourceInternal.h" +#import "WebDocumentInternal.h" +#import "WebDocumentLoaderMac.h" +#import "WebDownloadInternal.h" +#import "WebDynamicScrollBarsViewInternal.h" +#import "WebElementDictionary.h" +#import "WebFormDelegate.h" +#import "WebFrameInternal.h" +#import "WebFrameLoadDelegate.h" +#import "WebFrameViewInternal.h" +#import "WebHTMLRepresentationPrivate.h" +#import "WebHTMLViewInternal.h" +#import "WebHistoryItemInternal.h" +#import "WebHistoryInternal.h" +#import "WebIconDatabaseInternal.h" +#import "WebKitErrorsPrivate.h" +#import "WebKitLogging.h" +#import "WebKitNSStringExtras.h" +#import "WebNSURLExtras.h" +#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginPackage.h" +#import "WebNullPluginView.h" +#import "WebPanelAuthenticationHandler.h" +#import "WebPluginController.h" +#import "WebPluginPackage.h" +#import "WebPluginViewFactoryPrivate.h" +#import "WebPolicyDelegate.h" +#import "WebPolicyDelegatePrivate.h" +#import "WebPreferences.h" +#import "WebResourceLoadDelegate.h" +#import "WebResourcePrivate.h" +#import "WebUIDelegate.h" +#import "WebUIDelegatePrivate.h" +#import "WebViewInternal.h" +#import <WebKitSystemInterface.h> +#import <WebCore/AuthenticationMac.h> +#import <WebCore/BlockExceptions.h> +#import <WebCore/CachedPage.h> +#import <WebCore/Chrome.h> +#import <WebCore/Document.h> +#import <WebCore/DocumentLoader.h> +#import <WebCore/EventHandler.h> +#import <WebCore/FormState.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameLoader.h> +#import <WebCore/FrameLoaderTypes.h> +#import <WebCore/FrameTree.h> +#import <WebCore/FrameView.h> +#import <WebCore/HTMLFormElement.h> +#import <WebCore/HTMLFrameElement.h> +#import <WebCore/HTMLFrameOwnerElement.h> +#import <WebCore/HTMLNames.h> +#import <WebCore/HistoryItem.h> +#import <WebCore/HitTestResult.h> +#import <WebCore/IconDatabase.h> +#import <WebCore/LoaderNSURLExtras.h> +#import <WebCore/MIMETypeRegistry.h> +#import <WebCore/MouseEvent.h> +#import <WebCore/Page.h> +#import <WebCore/PlatformString.h> +#import <WebCore/ResourceError.h> +#import <WebCore/ResourceHandle.h> +#import <WebCore/ResourceLoader.h> +#import <WebCore/ResourceRequest.h> +#import <WebCore/ScriptController.h> +#import <WebCore/SharedBuffer.h> +#import <WebCore/WebCoreObjCExtras.h> +#import <WebCore/Widget.h> +#import <WebKit/DOMElement.h> +#import <WebKit/DOMHTMLFormElement.h> +#import <wtf/PassRefPtr.h> + +#if ENABLE(MAC_JAVA_BRIDGE) +#import "WebJavaPlugIn.h" +#endif + +using namespace WebCore; +using namespace HTMLNames; + +#if ENABLE(MAC_JAVA_BRIDGE) +@interface NSView (WebJavaPluginDetails) +- (jobject)pollForAppletInWindow:(NSWindow *)window; +@end +#endif + +@interface NSURLDownload (WebNSURLDownloadDetails) +- (void)_setOriginatingURL:(NSURL *)originatingURL; +@end + +// For backwards compatibility with older WebKit plug-ins. +NSString *WebPluginBaseURLKey = @"WebPluginBaseURL"; +NSString *WebPluginAttributesKey = @"WebPluginAttributes"; +NSString *WebPluginContainerKey = @"WebPluginContainer"; + +@interface WebFramePolicyListener : NSObject <WebPolicyDecisionListener, WebFormSubmissionListener> { + Frame* m_frame; +} +- (id)initWithWebCoreFrame:(Frame*)frame; +- (void)invalidate; +@end + +static inline WebDataSource *dataSource(DocumentLoader* loader) +{ + return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil; +} + +WebFrameLoaderClient::WebFrameLoaderClient(WebFrame *webFrame) + : m_webFrame(webFrame) + , m_policyFunction(0) +{ +} + +void WebFrameLoaderClient::frameLoaderDestroyed() +{ + [m_webFrame.get() _clearCoreFrame]; + delete this; +} + +bool WebFrameLoaderClient::hasWebView() const +{ + return [m_webFrame.get() webView] != nil; +} + +void WebFrameLoaderClient::makeRepresentation(DocumentLoader* loader) +{ + [dataSource(loader) _makeRepresentation]; +} + +bool WebFrameLoaderClient::hasHTMLView() const +{ + NSView <WebDocumentView> *view = [m_webFrame->_private->webFrameView documentView]; + return [view isKindOfClass:[WebHTMLView class]]; +} + +void WebFrameLoaderClient::forceLayout() +{ + NSView <WebDocumentView> *view = [m_webFrame->_private->webFrameView documentView]; + if ([view isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)view setNeedsToApplyStyles:YES]; + [view setNeedsLayout:YES]; + [view layout]; +} + +void WebFrameLoaderClient::forceLayoutForNonHTML() +{ + WebFrameView *thisView = m_webFrame->_private->webFrameView; + if (!thisView) // Viewless mode. + return; + NSView <WebDocumentView> *thisDocumentView = [thisView documentView]; + ASSERT(thisDocumentView != nil); + + // Tell the just loaded document to layout. This may be necessary + // for non-html content that needs a layout message. + if (!([[m_webFrame.get() _dataSource] _isDocumentHTML])) { + [thisDocumentView setNeedsLayout:YES]; + [thisDocumentView layout]; + [thisDocumentView setNeedsDisplay:YES]; + } +} + +void WebFrameLoaderClient::setCopiesOnScroll() +{ + [[[m_webFrame->_private->webFrameView _scrollView] contentView] setCopiesOnScroll:YES]; +} + +void WebFrameLoaderClient::detachedFromParent2() +{ + //remove any NetScape plugins that are children of this frame because they are about to be detached + WebView *webView = getWebView(m_webFrame.get()); + [webView removePluginInstanceViewsFor:(m_webFrame.get())]; + [m_webFrame->_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior +} + +void WebFrameLoaderClient::detachedFromParent3() +{ + [m_webFrame->_private->webFrameView release]; + m_webFrame->_private->webFrameView = nil; +} + +void WebFrameLoaderClient::download(ResourceHandle* handle, const ResourceRequest& request, const ResourceRequest& initialRequest, const ResourceResponse& response) +{ + id proxy = handle->releaseProxy(); + ASSERT(proxy); + + WebView *webView = getWebView(m_webFrame.get()); + WebDownload *download = [WebDownload _downloadWithLoadingConnection:handle->connection() + request:request.nsURLRequest() + response:response.nsURLResponse() + delegate:[webView downloadDelegate] + proxy:proxy]; + + setOriginalURLForDownload(download, initialRequest); +} + +void WebFrameLoaderClient::setOriginalURLForDownload(WebDownload *download, const ResourceRequest& initialRequest) const +{ + NSURLRequest *initialURLRequest = initialRequest.nsURLRequest(); + NSURL *originalURL = nil; + + // If there was no referrer, don't traverse the back/forward history + // since this download was initiated directly. <rdar://problem/5294691> + if ([initialURLRequest valueForHTTPHeaderField:@"Referer"]) { + // find the first item in the history that was originated by the user + WebView *webView = getWebView(m_webFrame.get()); + WebBackForwardList *history = [webView backForwardList]; + int backListCount = [history backListCount]; + for (int backIndex = 0; backIndex <= backListCount && !originalURL; backIndex++) { + // FIXME: At one point we had code here to check a "was user gesture" flag. + // Do we need to restore that logic? + originalURL = [[history itemAtIndex:-backIndex] URL]; + } + } + + if (!originalURL) + originalURL = [initialURLRequest URL]; + + if ([download respondsToSelector:@selector(_setOriginatingURL:)]) { + NSString *scheme = [originalURL scheme]; + NSString *host = [originalURL host]; + if (scheme && host && [scheme length] && [host length]) { + NSNumber *port = [originalURL port]; + if (port && [port intValue] < 0) + port = nil; + NSString *hostOnlyURLString; + if (port) + hostOnlyURLString = [[NSString alloc] initWithFormat:@"%@://%@:%d", scheme, host, [port intValue]]; + else + hostOnlyURLString = [[NSString alloc] initWithFormat:@"%@://%@", scheme, host]; + NSURL *hostOnlyURL = [[NSURL alloc] initWithString:hostOnlyURLString]; + [hostOnlyURLString release]; + [download _setOriginatingURL:hostOnlyURL]; + [hostOnlyURL release]; + } + } +} + +bool WebFrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + if (!implementations->didLoadResourceFromMemoryCacheFunc) + return false; + + CallResourceLoadDelegate(implementations->didLoadResourceFromMemoryCacheFunc, webView, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:), request.nsURLRequest(), response.nsURLResponse(), length, dataSource(loader)); + return true; +} + +void WebFrameLoaderClient::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + + id object = nil; + BOOL shouldRelease = NO; + if (implementations->identifierForRequestFunc) + object = CallResourceLoadDelegate(implementations->identifierForRequestFunc, webView, @selector(webView:identifierForInitialRequest:fromDataSource:), request.nsURLRequest(), dataSource(loader)); + else { + object = [[NSObject alloc] init]; + shouldRelease = YES; + } + + [webView _addObject:object forIdentifier:identifier]; + + if (shouldRelease) + [object release]; +} + +void WebFrameLoaderClient::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + + if (redirectResponse.isNull()) + static_cast<WebDocumentLoaderMac*>(loader)->increaseLoadCount(identifier); + + if (implementations->willSendRequestFunc) + request = (NSURLRequest *)CallResourceLoadDelegate(implementations->willSendRequestFunc, webView, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:), [webView _objectForIdentifier:identifier], request.nsURLRequest(), redirectResponse.nsURLResponse(), dataSource(loader)); +} + +void WebFrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(DocumentLoader* loader, unsigned long identifier, const AuthenticationChallenge& challenge) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + + NSURLAuthenticationChallenge *webChallenge = mac(challenge); + + if (implementations->didReceiveAuthenticationChallengeFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) { + CallResourceLoadDelegate(implementations->didReceiveAuthenticationChallengeFunc, webView, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:), resource, webChallenge, dataSource(loader)); + return; + } + } + + NSWindow *window = [webView hostWindow] ? [webView hostWindow] : [webView window]; + [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:webChallenge window:window]; +} + +void WebFrameLoaderClient::dispatchDidCancelAuthenticationChallenge(DocumentLoader* loader, unsigned long identifier, const AuthenticationChallenge&challenge) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + NSURLAuthenticationChallenge *webChallenge = mac(challenge); + + if (implementations->didCancelAuthenticationChallengeFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) { + CallResourceLoadDelegate(implementations->didCancelAuthenticationChallengeFunc, webView, @selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:), resource, webChallenge, dataSource(loader)); + return; + } + } + + [(WebPanelAuthenticationHandler *)[WebPanelAuthenticationHandler sharedHandler] cancelAuthentication:webChallenge]; +} + +void WebFrameLoaderClient::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& response) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + if (implementations->didReceiveResponseFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) + CallResourceLoadDelegate(implementations->didReceiveResponseFunc, webView, @selector(webView:resource:didReceiveResponse:fromDataSource:), resource, response.nsURLResponse(), dataSource(loader)); + } +} + +NSCachedURLResponse* WebFrameLoaderClient::willCacheResponse(DocumentLoader* loader, unsigned long identifier, NSCachedURLResponse* response) const +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + + if (implementations->willCacheResponseFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) + return CallResourceLoadDelegate(implementations->willCacheResponseFunc, webView, @selector(webView:resource:willCacheResponse:fromDataSource:), resource, response, dataSource(loader)); + } + + return response; +} + +void WebFrameLoaderClient::dispatchDidReceiveContentLength(DocumentLoader* loader, unsigned long identifier, int lengthReceived) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + if (implementations->didReceiveContentLengthFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) + CallResourceLoadDelegate(implementations->didReceiveContentLengthFunc, webView, @selector(webView:resource:didReceiveContentLength:fromDataSource:), resource, (NSInteger)lengthReceived, dataSource(loader)); + } +} + +void WebFrameLoaderClient::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + + if (implementations->didFinishLoadingFromDataSourceFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) + CallResourceLoadDelegate(implementations->didFinishLoadingFromDataSourceFunc, webView, @selector(webView:resource:didFinishLoadingFromDataSource:), resource, dataSource(loader)); + } + + [webView _removeObjectForIdentifier:identifier]; + + static_cast<WebDocumentLoaderMac*>(loader)->decreaseLoadCount(identifier); +} + +void WebFrameLoaderClient::dispatchDidFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); + + if (implementations->didFailLoadingWithErrorFromDataSourceFunc) { + if (id resource = [webView _objectForIdentifier:identifier]) + CallResourceLoadDelegate(implementations->didFailLoadingWithErrorFromDataSourceFunc, webView, @selector(webView:resource:didFailLoadingWithError:fromDataSource:), resource, (NSError *)error, dataSource(loader)); + } + + [webView _removeObjectForIdentifier:identifier]; + + static_cast<WebDocumentLoaderMac*>(loader)->decreaseLoadCount(identifier); +} + +void WebFrameLoaderClient::dispatchDidHandleOnloadEvents() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didHandleOnloadEventsForFrameFunc) + CallFrameLoadDelegate(implementations->didHandleOnloadEventsForFrameFunc, webView, @selector(webView:didHandleOnloadEventsForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didReceiveServerRedirectForProvisionalLoadForFrameFunc) + CallFrameLoadDelegate(implementations->didReceiveServerRedirectForProvisionalLoadForFrameFunc, webView, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidCancelClientRedirect() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didCancelClientRedirectForFrameFunc) + CallFrameLoadDelegate(implementations->didCancelClientRedirectForFrameFunc, webView, @selector(webView:didCancelClientRedirectForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchWillPerformClientRedirect(const KURL& url, double delay, double fireDate) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->willPerformClientRedirectToURLDelayFireDateForFrameFunc) { + NSURL *cocoaURL = url; + CallFrameLoadDelegate(implementations->willPerformClientRedirectToURLDelayFireDateForFrameFunc, webView, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:), cocoaURL, delay, [NSDate dateWithTimeIntervalSince1970:fireDate], m_webFrame.get()); + } +} + +void WebFrameLoaderClient::dispatchDidChangeLocationWithinPage() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didChangeLocationWithinPageForFrameFunc) + CallFrameLoadDelegate(implementations->didChangeLocationWithinPageForFrameFunc, webView, @selector(webView:didChangeLocationWithinPageForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchWillClose() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->willCloseFrameFunc) + CallFrameLoadDelegate(implementations->willCloseFrameFunc, webView, @selector(webView:willCloseFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidReceiveIcon() +{ + WebView *webView = getWebView(m_webFrame.get()); + ASSERT(m_webFrame == [webView mainFrame]); + [webView _dispatchDidReceiveIconFromWebFrame:m_webFrame.get()]; +} + +void WebFrameLoaderClient::dispatchDidStartProvisionalLoad() +{ + WebView *webView = getWebView(m_webFrame.get()); + [webView _didStartProvisionalLoadForFrame:m_webFrame.get()]; + + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didStartProvisionalLoadForFrameFunc) + CallFrameLoadDelegate(implementations->didStartProvisionalLoadForFrameFunc, webView, @selector(webView:didStartProvisionalLoadForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidReceiveTitle(const String& title) +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didReceiveTitleForFrameFunc) + CallFrameLoadDelegate(implementations->didReceiveTitleForFrameFunc, webView, @selector(webView:didReceiveTitle:forFrame:), (NSString *)title, m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidCommitLoad() +{ + // Tell the client we've committed this URL. + ASSERT([m_webFrame->_private->webFrameView documentView] != nil || ![getWebView(m_webFrame.get()) _usesDocumentViews]); + + WebView *webView = getWebView(m_webFrame.get()); + [webView _didCommitLoadForFrame:m_webFrame.get()]; + + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didCommitLoadForFrameFunc) + CallFrameLoadDelegate(implementations->didCommitLoadForFrameFunc, webView, @selector(webView:didCommitLoadForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidFailProvisionalLoad(const ResourceError& error) +{ + WebView *webView = getWebView(m_webFrame.get()); + [webView _didFailProvisionalLoadWithError:error forFrame:m_webFrame.get()]; + + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didFailProvisionalLoadWithErrorForFrameFunc) + CallFrameLoadDelegate(implementations->didFailProvisionalLoadWithErrorForFrameFunc, webView, @selector(webView:didFailProvisionalLoadWithError:forFrame:), (NSError *)error, m_webFrame.get()); + + [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:error]; +} + +void WebFrameLoaderClient::dispatchDidFailLoad(const ResourceError& error) +{ + WebView *webView = getWebView(m_webFrame.get()); + [webView _didFailLoadWithError:error forFrame:m_webFrame.get()]; + + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didFailLoadWithErrorForFrameFunc) + CallFrameLoadDelegate(implementations->didFailLoadWithErrorForFrameFunc, webView, @selector(webView:didFailLoadWithError:forFrame:), (NSError *)error, m_webFrame.get()); + + [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:error]; +} + +void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didFinishDocumentLoadForFrameFunc) + CallFrameLoadDelegate(implementations->didFinishDocumentLoadForFrameFunc, webView, @selector(webView:didFinishDocumentLoadForFrame:), m_webFrame.get()); +} + +void WebFrameLoaderClient::dispatchDidFinishLoad() +{ + WebView *webView = getWebView(m_webFrame.get()); + [webView _didFinishLoadForFrame:m_webFrame.get()]; + + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didFinishLoadForFrameFunc) + CallFrameLoadDelegate(implementations->didFinishLoadForFrameFunc, webView, @selector(webView:didFinishLoadForFrame:), m_webFrame.get()); + + [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:nil]; +} + +void WebFrameLoaderClient::dispatchDidFirstLayout() +{ + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didFirstLayoutInFrameFunc) + CallFrameLoadDelegate(implementations->didFirstLayoutInFrameFunc, webView, @selector(webView:didFirstLayoutInFrame:), m_webFrame.get()); +} + +Frame* WebFrameLoaderClient::dispatchCreatePage() +{ + WebView *currentWebView = getWebView(m_webFrame.get()); + NSDictionary *features = [[NSDictionary alloc] init]; + WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView + createWebViewWithRequest:nil + windowFeatures:features]; + [features release]; + return core([newWebView mainFrame]); +} + +void WebFrameLoaderClient::dispatchShow() +{ + WebView *webView = getWebView(m_webFrame.get()); + [[webView _UIDelegateForwarder] webViewShow:webView]; +} + +void WebFrameLoaderClient::dispatchDecidePolicyForMIMEType(FramePolicyFunction function, + const String& MIMEType, const ResourceRequest& request) +{ + WebView *webView = getWebView(m_webFrame.get()); + + [[webView _policyDelegateForwarder] webView:webView + decidePolicyForMIMEType:MIMEType + request:request.nsURLRequest() + frame:m_webFrame.get() + decisionListener:setUpPolicyListener(function).get()]; +} + +void WebFrameLoaderClient::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction function, + const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName) +{ + WebView *webView = getWebView(m_webFrame.get()); + [[webView _policyDelegateForwarder] webView:webView + decidePolicyForNewWindowAction:actionDictionary(action, formState) + request:request.nsURLRequest() + newFrameName:frameName + decisionListener:setUpPolicyListener(function).get()]; +} + +void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(FramePolicyFunction function, + const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState) +{ + WebView *webView = getWebView(m_webFrame.get()); + [[webView _policyDelegateForwarder] webView:webView + decidePolicyForNavigationAction:actionDictionary(action, formState) + request:request.nsURLRequest() + frame:m_webFrame.get() + decisionListener:setUpPolicyListener(function).get()]; +} + +void WebFrameLoaderClient::cancelPolicyCheck() +{ + [m_policyListener.get() invalidate]; + m_policyListener = nil; + m_policyFunction = 0; +} + +void WebFrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError& error) +{ + WebView *webView = getWebView(m_webFrame.get()); + [[webView _policyDelegateForwarder] webView:webView unableToImplementPolicyWithError:error frame:m_webFrame.get()]; +} + +void WebFrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction function, PassRefPtr<FormState> formState) +{ + id <WebFormDelegate> formDelegate = [getWebView(m_webFrame.get()) _formDelegate]; + if (!formDelegate) { + (core(m_webFrame.get())->loader()->*function)(PolicyUse); + return; + } + + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:formState->values().size()]; + HashMap<String, String>::const_iterator end = formState->values().end(); + for (HashMap<String, String>::const_iterator it = formState->values().begin(); it != end; ++it) + [dictionary setObject:it->second forKey:it->first]; + + CallFormDelegate(getWebView(m_webFrame.get()), @selector(frame:sourceFrame:willSubmitForm:withValues:submissionListener:), m_webFrame.get(), kit(formState->sourceFrame()), kit(formState->form()), dictionary, setUpPolicyListener(function).get()); + + [dictionary release]; +} + +void WebFrameLoaderClient::dispatchDidLoadMainResource(DocumentLoader* loader) +{ +} + +void WebFrameLoaderClient::revertToProvisionalState(DocumentLoader* loader) +{ + [dataSource(loader) _revertToProvisionalState]; +} + +void WebFrameLoaderClient::setMainDocumentError(DocumentLoader* loader, const ResourceError& error) +{ + [dataSource(loader) _setMainDocumentError:error]; +} + +void WebFrameLoaderClient::willChangeEstimatedProgress() +{ + [getWebView(m_webFrame.get()) _willChangeValueForKey:_WebEstimatedProgressKey]; +} + +void WebFrameLoaderClient::didChangeEstimatedProgress() +{ + [getWebView(m_webFrame.get()) _didChangeValueForKey:_WebEstimatedProgressKey]; +} + +void WebFrameLoaderClient::postProgressStartedNotification() +{ + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:getWebView(m_webFrame.get())]; +} + +void WebFrameLoaderClient::postProgressEstimateChangedNotification() +{ + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:getWebView(m_webFrame.get())]; +} + +void WebFrameLoaderClient::postProgressFinishedNotification() +{ + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:getWebView(m_webFrame.get())]; +} + +void WebFrameLoaderClient::setMainFrameDocumentReady(bool ready) +{ + [getWebView(m_webFrame.get()) setMainFrameDocumentReady:ready]; +} + +void WebFrameLoaderClient::startDownload(const ResourceRequest& request) +{ + // FIXME: Should download full request. + WebDownload *download = [getWebView(m_webFrame.get()) _downloadURL:request.url()]; + + setOriginalURLForDownload(download, request); +} + +void WebFrameLoaderClient::willChangeTitle(DocumentLoader* loader) +{ + // FIXME: Should do this only in main frame case, right? + [getWebView(m_webFrame.get()) _willChangeValueForKey:_WebMainFrameTitleKey]; +} + +void WebFrameLoaderClient::didChangeTitle(DocumentLoader* loader) +{ + // FIXME: Should do this only in main frame case, right? + [getWebView(m_webFrame.get()) _didChangeValueForKey:_WebMainFrameTitleKey]; +} + +void WebFrameLoaderClient::committedLoad(DocumentLoader* loader, const char* data, int length) +{ + NSData *nsData = [[NSData alloc] initWithBytesNoCopy:(void*)data length:length freeWhenDone:NO]; + [dataSource(loader) _receivedData:nsData]; + [nsData release]; +} + +void WebFrameLoaderClient::finishedLoading(DocumentLoader* loader) +{ + [dataSource(loader) _finishedLoading]; +} + +void WebFrameLoaderClient::updateGlobalHistory(const KURL& url) +{ + NSURL *cocoaURL = url; + const String& pageTitle = core(m_webFrame.get())->loader()->documentLoader()->title(); + [[WebHistory optionalSharedHistory] _addItemForURL:cocoaURL title:pageTitle]; +} + +bool WebFrameLoaderClient::shouldGoToHistoryItem(HistoryItem* item) const +{ + WebView* view = getWebView(m_webFrame.get()); + WebHistoryItem *webItem = kit(item); + + return [[view _policyDelegateForwarder] webView:view shouldGoToHistoryItem:webItem]; +} + +ResourceError WebFrameLoaderClient::cancelledError(const ResourceRequest& request) +{ + return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:request.url()]; +} + +ResourceError WebFrameLoaderClient::blockedError(const ResourceRequest& request) +{ + return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorCannotUseRestrictedPort URL:request.url()]; +} + +ResourceError WebFrameLoaderClient::cannotShowURLError(const ResourceRequest& request) +{ + return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorCannotShowURL URL:request.url()]; +} + +ResourceError WebFrameLoaderClient::interruptForPolicyChangeError(const ResourceRequest& request) +{ + return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:request.url()]; +} + +ResourceError WebFrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse& response) +{ + return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:WebKitErrorCannotShowMIMEType URL:response.url()]; +} + +ResourceError WebFrameLoaderClient::fileDoesNotExistError(const ResourceResponse& response) +{ + return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist URL:response.url()]; +} + +ResourceError WebFrameLoaderClient::pluginWillHandleLoadError(const ResourceResponse& response) +{ + NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad + contentURL:response.url() + pluginPageURL:nil + pluginName:nil + MIMEType:response.mimeType()]; + return [error autorelease]; +} + +bool WebFrameLoaderClient::shouldFallBack(const ResourceError& error) +{ + // FIXME: Needs to check domain. + // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent + // loading plugin content twice. See <rdar://problem/4258008> + return error.errorCode() != NSURLErrorCancelled && error.errorCode() != WebKitErrorPlugInWillHandleLoad; +} + +bool WebFrameLoaderClient::canHandleRequest(const ResourceRequest& request) const +{ + Frame* frame = core(m_webFrame.get()); + Page* page = frame->page(); + BOOL forMainFrame = page && page->mainFrame() == frame; + return [WebView _canHandleRequest:request.nsURLRequest() forMainFrame:forMainFrame]; +} + +bool WebFrameLoaderClient::canShowMIMEType(const String& MIMEType) const +{ + return [WebView canShowMIMEType:MIMEType]; +} + +bool WebFrameLoaderClient::representationExistsForURLScheme(const String& URLScheme) const +{ + return [WebView _representationExistsForURLScheme:URLScheme]; +} + +String WebFrameLoaderClient::generatedMIMETypeForURLScheme(const String& URLScheme) const +{ + return [WebView _generatedMIMETypeForURLScheme:URLScheme]; +} + +void WebFrameLoaderClient::frameLoadCompleted() +{ + // Note: Can be called multiple times. + // Even if already complete, we might have set a previous item on a frame that + // didn't do any data loading on the past transaction. Make sure to clear these out. + NSScrollView *sv = [m_webFrame->_private->webFrameView _scrollView]; + if ([getWebView(m_webFrame.get()) drawsBackground]) + [sv setDrawsBackground:YES]; + core(m_webFrame.get())->loader()->setPreviousHistoryItem(0); +} + + +void WebFrameLoaderClient::saveViewStateToItem(HistoryItem* item) +{ + if (!item) + return; + + NSView <WebDocumentView> *docView = [m_webFrame->_private->webFrameView documentView]; + + // we might already be detached when this is called from detachFromParent, in which + // case we don't want to override real data earlier gathered with (0,0) + if ([docView superview] && [docView conformsToProtocol:@protocol(_WebDocumentViewState)]) + item->setViewState([(id <_WebDocumentViewState>)docView viewState]); +} + +void WebFrameLoaderClient::restoreViewState() +{ + HistoryItem* currentItem = core(m_webFrame.get())->loader()->currentHistoryItem(); + ASSERT(currentItem); + + // FIXME: As the ASSERT attests, it seems we should always have a currentItem here. + // One counterexample is <rdar://problem/4917290> + // For now, to cover this issue in release builds, there is no technical harm to returning + // early and from a user standpoint - as in the above radar - the previous page load failed + // so there *is* no scroll state to restore! + if (!currentItem) + return; + + NSView <WebDocumentView> *docView = [m_webFrame->_private->webFrameView documentView]; + if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) { + id state = currentItem->viewState(); + if (state) { + [(id <_WebDocumentViewState>)docView setViewState:state]; + } + } +} + +void WebFrameLoaderClient::provisionalLoadStarted() +{ + // FIXME: This is OK as long as no one resizes the window, + // but in the case where someone does, it means garbage outside + // the occupied part of the scroll view. + [[m_webFrame->_private->webFrameView _scrollView] setDrawsBackground:NO]; +} + +void WebFrameLoaderClient::didFinishLoad() +{ + [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:nil]; +} + +void WebFrameLoaderClient::prepareForDataSourceReplacement() +{ + if (![m_webFrame.get() _dataSource]) { + ASSERT(!core(m_webFrame.get())->tree()->childCount()); + return; + } + + // Make sure that any work that is triggered by resigning first reponder can get done. + // The main example where this came up is the textDidEndEditing that is sent to the + // FormsDelegate (3223413). We need to do this before _detachChildren, since that will + // remove the views as a side-effect of freeing the frame, at which point we can't + // post the FormDelegate messages. + // + // Note that this can also take FirstResponder away from a child of our frameView that + // is not in a child frame's view. This is OK because we are in the process + // of loading new content, which will blow away all editors in this top frame, and if + // a non-editor is firstReponder it will not be affected by endEditingFor:. + // Potentially one day someone could write a DocView whose editors were not all + // replaced by loading new content, but that does not apply currently. + NSView *frameView = m_webFrame->_private->webFrameView; + NSWindow *window = [frameView window]; + NSResponder *firstResp = [window firstResponder]; + if ([firstResp isKindOfClass:[NSView class]] && [(NSView *)firstResp isDescendantOf:frameView]) + [window endEditingFor:firstResp]; +} + +PassRefPtr<DocumentLoader> WebFrameLoaderClient::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData) +{ + RefPtr<WebDocumentLoaderMac> loader = WebDocumentLoaderMac::create(request, substituteData); + + WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoader:loader.get()]; + loader->setDataSource(dataSource, getWebView(m_webFrame.get())); + [dataSource release]; + + return loader.release(); +} + +// FIXME: <rdar://problem/4880065> - Push Global History into WebCore +// Once that task is complete, this will go away +void WebFrameLoaderClient::setTitle(const String& title, const KURL& URL) +{ + NSURL* nsURL = URL; + nsURL = [nsURL _webkit_canonicalize]; + if(!nsURL) + return; + NSString *titleNSString = title; + [[[WebHistory optionalSharedHistory] itemForURL:nsURL] setTitle:titleNSString]; +} + +void WebFrameLoaderClient::savePlatformDataToCachedPage(CachedPage* cachedPage) +{ + WebCachedPagePlatformData* webPlatformData = new WebCachedPagePlatformData([m_webFrame->_private->webFrameView documentView]); + cachedPage->setCachedPagePlatformData(webPlatformData); +} + +void WebFrameLoaderClient::transitionToCommittedFromCachedPage(CachedPage* cachedPage) +{ + WebCachedPagePlatformData* platformData = reinterpret_cast<WebCachedPagePlatformData*>(cachedPage->cachedPagePlatformData()); + NSView <WebDocumentView> *cachedView = platformData->webDocumentView(); + ASSERT(cachedView != nil); + ASSERT(cachedPage->documentLoader()); + [cachedView setDataSource:dataSource(cachedPage->documentLoader())]; + + // clean up webkit plugin instances before WebHTMLView gets freed. + WebView *webView = getWebView(m_webFrame.get()); + [webView removePluginInstanceViewsFor:(m_webFrame.get())]; + + [m_webFrame->_private->webFrameView _setDocumentView:cachedView]; +} + +void WebFrameLoaderClient::transitionToCommittedForNewPage() +{ + WebFrameView *v = m_webFrame->_private->webFrameView; + WebDataSource *ds = [m_webFrame.get() _dataSource]; + + bool willProduceHTMLView = [[WebFrameView class] _viewClassForMIMEType:[ds _responseMIMEType]] == [WebHTMLView class]; + bool canSkipCreation = core(m_webFrame.get())->loader()->committingFirstRealLoad() && willProduceHTMLView; + if (canSkipCreation) { + [[v documentView] setDataSource:ds]; + return; + } + + // Don't suppress scrollbars before the view creation if we're making the view for a non-HTML view. + if (!willProduceHTMLView) + [[v _scrollView] setScrollBarsSuppressed:NO repaintOnUnsuppress:NO]; + + // clean up webkit plugin instances before WebHTMLView gets freed. + WebView *webView = getWebView(m_webFrame.get()); + [webView removePluginInstanceViewsFor:(m_webFrame.get())]; + + BOOL useDocumentViews = [webView _usesDocumentViews]; + NSView <WebDocumentView> *documentView = nil; + if (useDocumentViews) { + documentView = [v _makeDocumentViewForDataSource:ds]; + if (!documentView) + return; + } + + // FIXME: Could we skip some of this work for a top-level view that is not a WebHTMLView? + + // If we own the view, delete the old one - otherwise the render m_frame will take care of deleting the view. + Frame* coreFrame = core(m_webFrame.get()); + Page* page = coreFrame->page(); + bool isMainFrame = coreFrame == page->mainFrame(); + if (isMainFrame && coreFrame->view()) + coreFrame->view()->setParentVisible(false); + coreFrame->setView(0); + FrameView* coreView; + if (useDocumentViews) + coreView = new FrameView(coreFrame); + else + coreView = new FrameView(coreFrame, IntSize([webView bounds].size)); + coreFrame->setView(coreView); + coreView->deref(); // FIXME: Eliminate this crazy refcounting! + + [m_webFrame.get() _updateBackgroundAndUpdatesWhileOffscreen]; + + [v _install]; + + if (isMainFrame) + coreView->setParentVisible(true); + + // Call setDataSource on the document view after it has been placed in the view hierarchy. + // This what we for the top-level view, so should do this for views in subframes as well. + [documentView setDataSource:ds]; + + if (HTMLFrameOwnerElement* owner = coreFrame->ownerElement()) + coreFrame->view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); + +} + +RetainPtr<WebFramePolicyListener> WebFrameLoaderClient::setUpPolicyListener(FramePolicyFunction function) +{ + // FIXME: <rdar://5634381> We need to support multiple active policy listeners. + + [m_policyListener.get() invalidate]; + + WebFramePolicyListener *listener = [[WebFramePolicyListener alloc] initWithWebCoreFrame:core(m_webFrame.get())]; + m_policyListener = listener; + [listener release]; + m_policyFunction = function; + + return listener; +} + +void WebFrameLoaderClient::receivedPolicyDecison(PolicyAction action) +{ + ASSERT(m_policyListener); + ASSERT(m_policyFunction); + + FramePolicyFunction function = m_policyFunction; + + m_policyListener = nil; + m_policyFunction = 0; + + (core(m_webFrame.get())->loader()->*function)(action); +} + +String WebFrameLoaderClient::userAgent(const KURL& url) +{ + WebView *webView = getWebView(m_webFrame.get()); + ASSERT(webView); + + // We should never get here with nil for the WebView unless there is a bug somewhere else. + // But if we do, it's better to return the empty string than just crashing on the spot. + // Most other call sites are tolerant of nil because of Objective-C behavior, but this one + // is not because the return value of _userAgentForURL is a const KURL&. + if (!webView) + return String(""); + + return [webView _userAgentForURL:url]; +} + +static const MouseEvent* findMouseEvent(const Event* event) +{ + for (const Event* e = event; e; e = e->underlyingEvent()) + if (e->isMouseEvent()) + return static_cast<const MouseEvent*>(e); + return 0; +} + +NSDictionary *WebFrameLoaderClient::actionDictionary(const NavigationAction& action, PassRefPtr<FormState> formState) const +{ + unsigned modifierFlags = 0; + const Event* event = action.event(); + if (const UIEventWithKeyState* keyStateEvent = findEventWithKeyState(const_cast<Event*>(event))) { + if (keyStateEvent->ctrlKey()) + modifierFlags |= NSControlKeyMask; + if (keyStateEvent->altKey()) + modifierFlags |= NSAlternateKeyMask; + if (keyStateEvent->shiftKey()) + modifierFlags |= NSShiftKeyMask; + if (keyStateEvent->metaKey()) + modifierFlags |= NSCommandKeyMask; + } + + NSURL *originalURL = action.url(); + + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt:action.type()], WebActionNavigationTypeKey, + [NSNumber numberWithInt:modifierFlags], WebActionModifierFlagsKey, + originalURL, WebActionOriginalURLKey, + nil]; + + if (const MouseEvent* mouseEvent = findMouseEvent(event)) { + IntPoint point(mouseEvent->pageX(), mouseEvent->pageY()); + WebElementDictionary *element = [[WebElementDictionary alloc] + initWithHitTestResult:core(m_webFrame.get())->eventHandler()->hitTestResultAtPoint(point, false)]; + [result setObject:element forKey:WebActionElementKey]; + [element release]; + + [result setObject:[NSNumber numberWithInt:mouseEvent->button()] forKey:WebActionButtonKey]; + } + + if (formState) { + ASSERT(formState->form()); + [result setObject:kit(formState->form()) forKey:WebActionFormKey]; + } + + return result; +} + +bool WebFrameLoaderClient::canCachePage() const +{ + // We can only cache HTML pages right now + return [[[m_webFrame.get() _dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]]; +} + +PassRefPtr<Frame> WebFrameLoaderClient::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, + const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + ASSERT(m_webFrame); + + WebFrameView *childView = [getWebView(m_webFrame.get()) _usesDocumentViews] ? [[WebFrameView alloc] init] : nil; + + RefPtr<Frame> result = [WebFrame _createSubframeWithOwnerElement:ownerElement frameName:name frameView:childView]; + [childView release]; + + WebFrame *newFrame = kit(result.get()); + + if ([newFrame _dataSource]) + [[newFrame _dataSource] _documentLoader]->setOverrideEncoding([[m_webFrame.get() _dataSource] _documentLoader]->overrideEncoding()); + + // The creation of the frame may have run arbitrary JavaScript that removed it from the page already. + if (!result->page()) + return 0; + + core(m_webFrame.get())->loader()->loadURLIntoChildFrame(url, referrer, result.get()); + + // The frame's onload handler may have removed it from the document. + if (!result->tree()->parent()) + return 0; + + return result.release(); + + END_BLOCK_OBJC_EXCEPTIONS; + + return 0; +} + +ObjectContentType WebFrameLoaderClient::objectContentType(const KURL& url, const String& mimeType) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + // This is a quirk that ensures Tiger Mail's WebKit plug-in will load during layout + // and not attach time. (5520541) + static BOOL isTigerMail = WKAppVersionCheckLessThan(@"com.apple.mail", -1, 3.0); + if (isTigerMail && mimeType == "application/x-apple-msg-attachment") + return ObjectContentNetscapePlugin; + + String type = mimeType; + + if (type.isEmpty()) { + // Try to guess the MIME type based off the extension. + NSURL *URL = url; + NSString *extension = [[URL path] pathExtension]; + if ([extension length] > 0) { + type = WKGetMIMETypeForExtension(extension); + if (type.isEmpty()) { + // If no MIME type is specified, use a plug-in if we have one that can handle the extension. + if (WebBasePluginPackage *package = [getWebView(m_webFrame.get()) _pluginForExtension:extension]) { + if ([package isKindOfClass:[WebPluginPackage class]]) + return ObjectContentOtherPlugin; +#if ENABLE(NETSCAPE_PLUGIN_API) + else { + ASSERT([package isKindOfClass:[WebNetscapePluginPackage class]]); + return ObjectContentNetscapePlugin; + } +#endif + } + } + } + } + + if (type.isEmpty()) + return ObjectContentFrame; // Go ahead and hope that we can display the content. + + if (MIMETypeRegistry::isSupportedImageMIMEType(type)) + return ObjectContentImage; + + WebBasePluginPackage *package = [getWebView(m_webFrame.get()) _pluginForMIMEType:type]; + if (package) { +#if ENABLE(NETSCAPE_PLUGIN_API) + if ([package isKindOfClass:[WebNetscapePluginPackage class]]) + return ObjectContentNetscapePlugin; +#endif + ASSERT([package isKindOfClass:[WebPluginPackage class]]); + return ObjectContentOtherPlugin; + } + + if ([WebFrameView _viewClassForMIMEType:type]) + return ObjectContentFrame; + + return ObjectContentNone; + + END_BLOCK_OBJC_EXCEPTIONS; + + return ObjectContentNone; +} + +static NSMutableArray* kit(const Vector<String>& vector) +{ + unsigned len = vector.size(); + NSMutableArray* array = [NSMutableArray arrayWithCapacity:len]; + for (unsigned x = 0; x < len; x++) + [array addObject:vector[x]]; + return array; +} + +static String parameterValue(const Vector<String>& paramNames, const Vector<String>& paramValues, const String& name) +{ + size_t size = paramNames.size(); + ASSERT(size == paramValues.size()); + for (size_t i = 0; i < size; ++i) { + if (equalIgnoringCase(paramNames[i], name)) + return paramValues[i]; + } + return String(); +} + +static NSView *pluginView(WebFrame *frame, WebPluginPackage *pluginPackage, + NSArray *attributeNames, NSArray *attributeValues, NSURL *baseURL, + DOMElement *element, BOOL loadManually) +{ + WebHTMLView *docView = (WebHTMLView *)[[frame frameView] documentView]; + ASSERT([docView isKindOfClass:[WebHTMLView class]]); + + WebPluginController *pluginController = [docView _pluginController]; + + // Store attributes in a dictionary so they can be passed to WebPlugins. + NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:attributeValues forKeys:attributeNames]; + + [pluginPackage load]; + Class viewFactory = [pluginPackage viewFactory]; + + NSView *view = nil; + NSDictionary *arguments = nil; + + if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) { + arguments = [NSDictionary dictionaryWithObjectsAndKeys: + baseURL, WebPlugInBaseURLKey, + attributes, WebPlugInAttributesKey, + pluginController, WebPlugInContainerKey, + [NSNumber numberWithInt:loadManually ? WebPlugInModeFull : WebPlugInModeEmbed], WebPlugInModeKey, + [NSNumber numberWithBool:!loadManually], WebPlugInShouldLoadMainResourceKey, + element, WebPlugInContainingElementKey, + nil]; + LOG(Plugins, "arguments:\n%@", arguments); + } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) { + arguments = [NSDictionary dictionaryWithObjectsAndKeys: + baseURL, WebPluginBaseURLKey, + attributes, WebPluginAttributesKey, + pluginController, WebPluginContainerKey, + element, WebPlugInContainingElementKey, + nil]; + LOG(Plugins, "arguments:\n%@", arguments); + } + + view = [WebPluginController plugInViewWithArguments:arguments fromPluginPackage:pluginPackage]; + [attributes release]; + return view; +} + +class PluginWidget : public Widget { +public: + PluginWidget(NSView *view = 0) + : Widget(view) + { + } + + virtual void invalidateRect(const IntRect& rect) + { + [platformWidget() setNeedsDisplayInRect:rect]; + } +}; + +#if ENABLE(NETSCAPE_PLUGIN_API) + +class NetscapePluginWidget : public PluginWidget { +public: + NetscapePluginWidget(WebBaseNetscapePluginView *view) + : PluginWidget(view) + { + } + + virtual void handleEvent(Event*) + { + Frame* frame = Frame::frameForWidget(this); + if (!frame) + return; + + NSEvent* event = frame->eventHandler()->currentNSEvent(); + if ([event type] == NSMouseMoved) + [(WebBaseNetscapePluginView *)platformWidget() handleMouseMoved:event]; + } + +}; + +#endif // ENABLE(NETSCAPE_PLUGIN_API) + +Widget* WebFrameLoaderClient::createPlugin(const IntSize& size, Element* element, const KURL& url, + const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + ASSERT(paramNames.size() == paramValues.size()); + + int errorCode = 0; + + WebView *webView = getWebView(m_webFrame.get()); + SEL selector = @selector(webView:plugInViewWithArguments:); + NSURL *URL = url; + + if ([[webView UIDelegate] respondsToSelector:selector]) { + NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:kit(paramValues) forKeys:kit(paramNames)]; + NSDictionary *arguments = [[NSDictionary alloc] initWithObjectsAndKeys: + attributes, WebPlugInAttributesKey, + [NSNumber numberWithInt:loadManually ? WebPlugInModeFull : WebPlugInModeEmbed], WebPlugInModeKey, + [NSNumber numberWithBool:!loadManually], WebPlugInShouldLoadMainResourceKey, + kit(element), WebPlugInContainingElementKey, + URL, WebPlugInBaseURLKey, // URL might be nil, so add it last + nil]; + + NSView *view = CallUIDelegate(webView, selector, arguments); + + [attributes release]; + [arguments release]; + + if (view) + return new PluginWidget(view); + } + + NSString *MIMEType; + WebBasePluginPackage *pluginPackage; + if (mimeType.isEmpty()) { + MIMEType = nil; + pluginPackage = nil; + } else { + MIMEType = mimeType; + pluginPackage = [webView _pluginForMIMEType:mimeType]; + } + + NSString *extension = [[URL path] pathExtension]; + if (!pluginPackage && [extension length] != 0) { + pluginPackage = [webView _pluginForExtension:extension]; + if (pluginPackage) { + NSString *newMIMEType = [pluginPackage MIMETypeForExtension:extension]; + if ([newMIMEType length] != 0) + MIMEType = newMIMEType; + } + } + + NSView *view = nil; + + Document* document = core(m_webFrame.get())->document(); + NSURL *baseURL = document->baseURL(); + if (pluginPackage) { + if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) + view = pluginView(m_webFrame.get(), (WebPluginPackage *)pluginPackage, kit(paramNames), kit(paramValues), baseURL, kit(element), loadManually); + +#if ENABLE(NETSCAPE_PLUGIN_API) + else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) { + WebBaseNetscapePluginView *embeddedView = [[[WebBaseNetscapePluginView alloc] + initWithFrame:NSMakeRect(0, 0, size.width(), size.height()) + pluginPackage:(WebNetscapePluginPackage *)pluginPackage + URL:URL + baseURL:baseURL + MIMEType:MIMEType + attributeKeys:kit(paramNames) + attributeValues:kit(paramValues) + loadManually:loadManually + DOMElement:kit(element)] autorelease]; + + return new NetscapePluginWidget(embeddedView); + } +#endif + } else + errorCode = WebKitErrorCannotFindPlugIn; + + if (!errorCode && !view) + errorCode = WebKitErrorCannotLoadPlugIn; + + if (errorCode) { + NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode + contentURL:URL + pluginPageURL:document->completeURL(parseURL(parameterValue(paramNames, paramValues, "pluginspage"))) + pluginName:[pluginPackage name] + MIMEType:MIMEType]; + WebNullPluginView *nullView = [[[WebNullPluginView alloc] initWithFrame:NSMakeRect(0, 0, size.width(), size.height()) + error:error DOMElement:kit(element)] autorelease]; + view = nullView; + [error release]; + } + + ASSERT(view); + return new PluginWidget(view); + + END_BLOCK_OBJC_EXCEPTIONS; + + return 0; +} + +void WebFrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + WebHTMLRepresentation *representation = (WebHTMLRepresentation *)[[m_webFrame.get() _dataSource] representation]; + + NSView *pluginView = pluginWidget->platformWidget(); + +#if ENABLE(NETSCAPE_PLUGIN_API) + if ([pluginView isKindOfClass:[WebBaseNetscapePluginView class]]) + [representation _redirectDataToManualLoader:(WebBaseNetscapePluginView *)pluginView forPluginView:pluginView]; + else { +#else + { +#endif + WebHTMLView *documentView = (WebHTMLView *)[[m_webFrame.get() frameView] documentView]; + ASSERT([documentView isKindOfClass:[WebHTMLView class]]); + [representation _redirectDataToManualLoader:[documentView _pluginController] forPluginView:pluginView]; + } + + END_BLOCK_OBJC_EXCEPTIONS; +} + +Widget* WebFrameLoaderClient::createJavaAppletWidget(const IntSize& size, Element* element, const KURL& baseURL, + const Vector<String>& paramNames, const Vector<String>& paramValues) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + NSView *view = nil; + + NSString *MIMEType = @"application/x-java-applet"; + + WebView *webView = getWebView(m_webFrame.get()); + + WebBasePluginPackage *pluginPackage = [webView _pluginForMIMEType:MIMEType]; + + if (pluginPackage) { + if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) { + // For some reason, the Java plug-in requires that we pass the dimension of the plug-in as attributes. + NSMutableArray *names = kit(paramNames); + NSMutableArray *values = kit(paramValues); + if (parameterValue(paramNames, paramValues, "width").isNull()) { + [names addObject:@"width"]; + [values addObject:[NSString stringWithFormat:@"%d", size.width()]]; + } + if (parameterValue(paramNames, paramValues, "height").isNull()) { + [names addObject:@"height"]; + [values addObject:[NSString stringWithFormat:@"%d", size.width()]]; + } + view = pluginView(m_webFrame.get(), (WebPluginPackage *)pluginPackage, names, values, baseURL, kit(element), NO); + } +#if ENABLE(NETSCAPE_PLUGIN_API) + else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) { + view = [[[WebBaseNetscapePluginView alloc] initWithFrame:NSMakeRect(0, 0, size.width(), size.height()) + pluginPackage:(WebNetscapePluginPackage *)pluginPackage + URL:nil + baseURL:baseURL + MIMEType:MIMEType + attributeKeys:kit(paramNames) + attributeValues:kit(paramValues) + loadManually:NO + DOMElement:kit(element)] autorelease]; + } else { + ASSERT_NOT_REACHED(); + } +#endif + } + + if (!view) { + NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorJavaUnavailable + contentURL:nil + pluginPageURL:nil + pluginName:[pluginPackage name] + MIMEType:MIMEType]; + view = [[[WebNullPluginView alloc] initWithFrame:NSMakeRect(0, 0, size.width(), size.height()) + error:error DOMElement:kit(element)] autorelease]; + [error release]; + } + + ASSERT(view); + return new PluginWidget(view); + + END_BLOCK_OBJC_EXCEPTIONS; + + return new PluginWidget; +} + +String WebFrameLoaderClient::overrideMediaType() const +{ + NSString* overrideType = [getWebView(m_webFrame.get()) mediaStyle]; + if (overrideType) + return overrideType; + return String(); +} + +void WebFrameLoaderClient::windowObjectCleared() +{ + Frame *frame = core(m_webFrame.get()); + ScriptController *script = frame->script(); + WebView *webView = getWebView(m_webFrame.get()); + WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView); + if (implementations->didClearWindowObjectForFrameFunc) { + CallFrameLoadDelegate(implementations->didClearWindowObjectForFrameFunc, webView, @selector(webView:didClearWindowObject:forFrame:), + script->windowScriptObject(), m_webFrame.get()); + } else if (implementations->windowScriptObjectAvailableFunc) { + CallFrameLoadDelegate(implementations->windowScriptObjectAvailableFunc, webView, @selector(webView:windowScriptObjectAvailable:), + script->windowScriptObject()); + } + + if ([webView scriptDebugDelegate]) { + [m_webFrame.get() _detachScriptDebugger]; + [m_webFrame.get() _attachScriptDebugger]; + } +} + +void WebFrameLoaderClient::registerForIconNotification(bool listen) +{ + [[m_webFrame.get() webView] _registerForIconNotification:listen]; +} + +void WebFrameLoaderClient::didPerformFirstNavigation() const +{ + WebPreferences *preferences = [[m_webFrame.get() webView] preferences]; + if ([preferences automaticallyDetectsCacheModel] && [preferences cacheModel] < WebCacheModelDocumentBrowser) + [preferences setCacheModel:WebCacheModelDocumentBrowser]; +} + +#if ENABLE(MAC_JAVA_BRIDGE) +jobject WebFrameLoaderClient::javaApplet(NSView* view) +{ + if ([view respondsToSelector:@selector(webPlugInGetApplet)]) + return [view webPlugInGetApplet]; + + // Compatibility with older versions of Java. + // FIXME: Do we still need this? + if ([view respondsToSelector:@selector(pollForAppletInWindow:)]) + return [view pollForAppletInWindow:[[m_webFrame.get() frameView] window]]; + + return 0; +} +#endif + +@implementation WebFramePolicyListener + +#ifndef BUILDING_ON_TIGER ++ (void)initialize +{ + WebCoreObjCFinalizeOnMainThread(self); +} +#endif + +- (id)initWithWebCoreFrame:(Frame*)frame +{ + self = [self init]; + if (!self) + return nil; + frame->ref(); + m_frame = frame; + return self; +} + +- (void)invalidate +{ + if (m_frame) { + m_frame->deref(); + m_frame = 0; + } +} + +- (void)dealloc +{ + if (WebCoreObjCScheduleDeallocateOnMainThread([WebFramePolicyListener class], self)) + return; + + if (m_frame) + m_frame->deref(); + [super dealloc]; +} + +- (void)finalize +{ + ASSERT_MAIN_THREAD(); + if (m_frame) + m_frame->deref(); + [super finalize]; +} + +- (void)receivedPolicyDecision:(PolicyAction)action +{ + RefPtr<Frame> frame = adoptRef(m_frame); + m_frame = 0; + if (frame) + static_cast<WebFrameLoaderClient*>(frame->loader()->client())->receivedPolicyDecison(action); +} + +- (void)ignore +{ + [self receivedPolicyDecision:PolicyIgnore]; +} + +- (void)download +{ + [self receivedPolicyDecision:PolicyDownload]; +} + +- (void)use +{ + [self receivedPolicyDecision:PolicyUse]; +} + +- (void)continue +{ + [self receivedPolicyDecision:PolicyUse]; +} + +@end |