blob: ab7f7646158994b72aaeaeab1b4feeed58c1ce06 [file] [log] [blame]
/*
* Copyright (C) 2006, 2007, 2008, 2009 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 "WebCachedFramePlatformData.h"
#import "WebChromeClient.h"
#import "WebDataSourceInternal.h"
#import "WebDelegateImplementationCaching.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 "WebNetscapePluginView.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 "WebUIDelegate.h"
#import "WebUIDelegatePrivate.h"
#import "WebViewInternal.h"
#import <WebKitSystemInterface.h>
#import <WebCore/AuthenticationMac.h>
#import <WebCore/BlockExceptions.h>
#import <WebCore/CachedFrame.h>
#import <WebCore/Chrome.h>
#import <WebCore/Document.h>
#import <WebCore/DocumentLoader.h>
#import <WebCore/EventHandler.h>
#import <WebCore/FocusController.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/HTMLAppletElement.h>
#import <WebCore/HTMLHeadElement.h>
#import <WebCore/HTMLFormElement.h>
#import <WebCore/HTMLFrameElement.h>
#import <WebCore/HTMLFrameOwnerElement.h>
#import <WebCore/HTMLNames.h>
#import <WebCore/HTMLPlugInElement.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/ScriptString.h>
#import <WebCore/SharedBuffer.h>
#import <WebCore/WebCoreObjCExtras.h>
#import <WebCore/Widget.h>
#import <WebKit/DOMElement.h>
#import <WebKit/DOMHTMLFormElement.h>
#import <runtime/InitializeThreading.h>
#import <wtf/PassRefPtr.h>
#if ENABLE(MAC_JAVA_BRIDGE)
#import "WebJavaPlugIn.h"
#endif
#if USE(PLUGIN_HOST_PROCESS)
#import "NetscapePluginHostManager.h"
#import "WebHostedNetscapePluginView.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;
}
// Quirk for the Apple Dictionary application.
//
// If a top level frame has a <script> element in its <head> for a script named MainPageJavaScript.js,
// then for that frame's document, ignore changes to the scrolling attribute of frames. That script
// has a bug in it where it sets the scrolling attribute on frames, and that erroneous scrolling
// attribute needs to be ignored to avoid showing extra scroll bars in the window.
// This quirk can be removed when Apple Dictionary is fixed (see <rdar://problem/6471058>).
static void applyAppleDictionaryApplicationQuirkNonInlinePart(WebFrameLoaderClient* client, const ResourceRequest& request)
{
if (!request.url().isLocalFile())
return;
if (!request.url().string().endsWith("MainPageJavaScript.js"))
return;
Frame* frame = core(client->webFrame());
if (!frame)
return;
if (frame->tree()->parent())
return;
Document* document = frame->document();
if (!document)
return;
HTMLHeadElement* head = document->head();
if (!head)
return;
for (Node* c = head->firstChild(); c; c = c->nextSibling()) {
if (c->hasTagName(scriptTag) && static_cast<Element*>(c)->getAttribute(srcAttr) == "MainPageJavaScript.js") {
document->setFrameElementsShouldIgnoreScrolling(true);
return;
}
}
}
static inline void applyAppleDictionaryApplicationQuirk(WebFrameLoaderClient* client, const ResourceRequest& request)
{
// Use a one-time-initialized global variable so we can quickly determine there's nothing to do in
// all applications other than Apple Dictionary.
static bool isAppleDictionary = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Dictionary"];
if (isAppleDictionary)
applyAppleDictionaryApplicationQuirkNonInlinePart(client, request);
}
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)
{
applyAppleDictionaryApplicationQuirk(this, request);
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::dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString)
{
}
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)
{
applyAppleDictionaryApplicationQuirk(this, request);
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));
}
bool WebFrameLoaderClient::shouldUseCredentialStorage(DocumentLoader* loader, unsigned long identifier)
{
WebView *webView = getWebView(m_webFrame.get());
WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
if (implementations->shouldUseCredentialStorageFunc) {
if (id resource = [webView _objectForIdentifier:identifier])
return CallResourceLoadDelegateReturningBoolean(NO, implementations->shouldUseCredentialStorageFunc, webView, @selector(webView:resource:shouldUseCredentialStorageForDataSource:), resource, dataSource(loader));
}
return true;
}
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());
}
void WebFrameLoaderClient::dispatchDidFirstVisuallyNonEmptyLayout()
{
WebView *webView = getWebView(m_webFrame.get());
WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
if (implementations->didFirstVisuallyNonEmptyLayoutInFrameFunc)
CallFrameLoadDelegate(implementations->didFirstVisuallyNonEmptyLayoutInFrameFunc, webView, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:), 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];
#if USE(PLUGIN_HOST_PROCESS)
if (newWebView)
WebKit::NetscapePluginHostManager::shared().didCreateWindow();
#endif
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;
}
const StringPairVector& textFieldValues = formState->textFieldValues();
size_t size = textFieldValues.size();
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:size];
for (size_t i = 0; i < size; ++i)
[dictionary setObject:textFieldValues[i].second forKey:textFieldValues[i].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()
{
DocumentLoader* loader = core(m_webFrame.get())->loader()->documentLoader();
[[WebHistory optionalSharedHistory] _visitedURL:loader->urlForHistory()
withTitle:loader->title()
method:loader->originalRequestCopy().httpMethod()
wasFailure:loader->urlForHistoryReflectsFailure()
increaseVisitCount:!loader->clientRedirectSourceForHistory()]; // Do not increase visit count due to navigations that were not initiated by the user directly, avoiding growth from programmatic reloads.
}
void WebFrameLoaderClient::updateGlobalHistoryRedirectLinks()
{
DocumentLoader* loader = core(m_webFrame.get())->loader()->documentLoader();
ASSERT(loader->unreachableURL().isEmpty());
if (!loader->clientRedirectSourceForHistory().isNull()) {
if (WebHistoryItem *item = [[WebHistory optionalSharedHistory] _itemForURLString:loader->clientRedirectSourceForHistory()])
core(item)->addRedirectURL(loader->clientRedirectDestinationForHistory());
}
if (!loader->serverRedirectSourceForHistory().isNull()) {
if (WebHistoryItem *item = [[WebHistory optionalSharedHistory] _itemForURLString:loader->serverRedirectSourceForHistory()])
core(item)->addRedirectURL(loader->serverRedirectDestinationForHistory());
}
}
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.
// See WebFrameLoaderClient::provisionalLoadStarted.
if ([getWebView(m_webFrame.get()) drawsBackground])
[[m_webFrame->_private->webFrameView _scrollView] setDrawsBackground:YES];
}
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()
{
// Tell the scroll view not to draw a background so we can leave the contents of
// the old page showing during the beginning of the loading process.
// This will stay set to NO until:
// 1) The load gets far enough along: WebFrameLoader::frameLoadCompleted.
// 2) The window is resized: -[WebFrameView setFrameSize:].
// or 3) The view is moved out of the window: -[WebFrameView viewDidMoveToWindow].
// Please keep the comments in these four functions in agreement with each other.
[[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::savePlatformDataToCachedFrame(CachedFrame* cachedFrame)
{
WebCachedFramePlatformData* webPlatformData = new WebCachedFramePlatformData([m_webFrame->_private->webFrameView documentView]);
cachedFrame->setCachedFramePlatformData(webPlatformData);
}
void WebFrameLoaderClient::transitionToCommittedFromCachedFrame(CachedFrame* cachedFrame)
{
WebCachedFramePlatformData* platformData = reinterpret_cast<WebCachedFramePlatformData*>(cachedFrame->cachedFramePlatformData());
NSView <WebDocumentView> *cachedView = platformData->webDocumentView();
ASSERT(cachedView != nil);
ASSERT(cachedFrame->documentLoader());
[cachedView setDataSource:dataSource(cachedFrame->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()
{
WebView *webView = getWebView(m_webFrame.get());
WebDataSource *dataSource = [m_webFrame.get() _dataSource];
bool usesDocumentViews = [webView _usesDocumentViews];
if (usesDocumentViews) {
// FIXME (Viewless): I assume we want the equivalent of this optimization for viewless mode too.
bool willProduceHTMLView = [[WebFrameView class] _viewClassForMIMEType:[dataSource _responseMIMEType]] == [WebHTMLView class];
bool canSkipCreation = core(m_webFrame.get())->loader()->committingFirstRealLoad() && willProduceHTMLView;
if (canSkipCreation) {
[[m_webFrame->_private->webFrameView documentView] setDataSource:dataSource];
return;
}
// Don't suppress scrollbars before the view creation if we're making the view for a non-HTML view.
if (!willProduceHTMLView)
[[m_webFrame->_private->webFrameView _scrollView] setScrollBarsSuppressed:NO repaintOnUnsuppress:NO];
}
// clean up webkit plugin instances before WebHTMLView gets freed.
[webView removePluginInstanceViewsFor:(m_webFrame.get())];
NSView <WebDocumentView> *documentView = nil;
if (usesDocumentViews) {
documentView = [m_webFrame->_private->webFrameView _makeDocumentViewForDataSource:dataSource];
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);
RefPtr<FrameView> coreView;
if (usesDocumentViews)
coreView = FrameView::create(coreFrame);
else
coreView = FrameView::create(coreFrame, IntSize([webView bounds].size));
coreFrame->setView(coreView);
[m_webFrame.get() _updateBackgroundAndUpdatesWhileOffscreen];
if (usesDocumentViews)
[m_webFrame->_private->webFrameView _install];
if (isMainFrame)
coreView->setParentVisible(true);
if (usesDocumentViews) {
// 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:dataSource];
}
if (HTMLFrameOwnerElement* owner = coreFrame->ownerElement())
coreFrame->view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
// If the WebHTMLView implicitly became first responder, make sure to set the focused frame properly.
if (usesDocumentViews && [[documentView window] firstResponder] == documentView) {
page->focusController()->setFocusedFrame(coreFrame);
page->focusController()->setFocused(true);
}
}
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)) {
WebElementDictionary *element = [[WebElementDictionary alloc]
initWithHitTestResult:core(m_webFrame.get())->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), 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)
#if USE(PLUGIN_HOST_PROCESS)
#define NETSCAPE_PLUGIN_VIEW WebHostedNetscapePluginView
#else
#define NETSCAPE_PLUGIN_VIEW WebNetscapePluginView
#endif
PassRefPtr<Widget> WebFrameLoaderClient::createPlugin(const IntSize& size, HTMLPlugInElement* 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 adoptRef(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 ENABLE(PLUGIN_PROXY_FOR_VIDEO)
// don't allow proxy plug-in selection by file extension
if (element->hasTagName(videoTag) || element->hasTagName(audioTag))
extension = @"";
#endif
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 *pluginView = [[[NETSCAPE_PLUGIN_VIEW 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
element:element] autorelease];
return adoptRef(new NetscapePluginWidget(pluginView));
}
#endif
} else
errorCode = WebKitErrorCannotFindPlugIn;
if (!errorCode && !view)
errorCode = WebKitErrorCannotLoadPlugIn;
if (errorCode) {
KURL pluginPageURL = document->completeURL(parseURL(parameterValue(paramNames, paramValues, "pluginspage")));
if (!pluginPageURL.protocolInHTTPFamily())
pluginPageURL = KURL();
NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode
contentURL:URL pluginPageURL:pluginPageURL 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 adoptRef(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:[NETSCAPE_PLUGIN_VIEW class]])
[representation _redirectDataToManualLoader:(NETSCAPE_PLUGIN_VIEW *)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;
}
PassRefPtr<Widget> WebFrameLoaderClient::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const KURL& baseURL,
const Vector<String>& paramNames, const Vector<String>& paramValues)
{
#if ENABLE(MAC_JAVA_BRIDGE)
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.height()]];
}
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 = [[[NETSCAPE_PLUGIN_VIEW 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
element: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 adoptRef(new PluginWidget(view));
END_BLOCK_OBJC_EXCEPTIONS;
return adoptRef(new PluginWidget);
#else
return 0;
#endif // ENABLE(MAC_JAVA_BRIDGE)
}
String WebFrameLoaderClient::overrideMediaType() const
{
NSString* overrideType = [getWebView(m_webFrame.get()) mediaStyle];
if (overrideType)
return overrideType;
return String();
}
void WebFrameLoaderClient::documentElementAvailable() {
}
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
+ (void)initialize
{
JSC::initializeThreading();
#ifndef BUILDING_ON_TIGER
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