1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#import "WebFrameLoaderClient.h"
30
31// Terrible hack; lets us get at the WebFrame private structure.
32#define private public
33#import "WebFrame.h"
34#undef private
35
36#import "DOMElementInternal.h"
37#import "DOMHTMLFormElementInternal.h"
38#import "WebBackForwardList.h"
39#import "WebCachedFramePlatformData.h"
40#import "WebChromeClient.h"
41#import "WebDataSourceInternal.h"
42#import "WebDelegateImplementationCaching.h"
43#import "WebDocumentInternal.h"
44#import "WebDocumentLoaderMac.h"
45#import "WebDownloadInternal.h"
46#import "WebDynamicScrollBarsViewInternal.h"
47#import "WebElementDictionary.h"
48#import "WebFormDelegate.h"
49#import "WebFrameInternal.h"
50#import "WebFrameLoadDelegate.h"
51#import "WebFrameNetworkingContext.h"
52#import "WebFrameViewInternal.h"
53#import "WebHTMLRepresentationPrivate.h"
54#import "WebHTMLViewInternal.h"
55#import "WebHistoryInternal.h"
56#import "WebHistoryItemInternal.h"
57#import "WebIconDatabaseInternal.h"
58#import "WebKitErrorsPrivate.h"
59#import "WebKitLogging.h"
60#import "WebKitNSStringExtras.h"
61#import "WebNSURLExtras.h"
62#import "WebNavigationData.h"
63#import "WebNetscapePluginPackage.h"
64#import "WebNetscapePluginView.h"
65#import "WebPanelAuthenticationHandler.h"
66#import "WebPluginController.h"
67#import "WebPluginPackage.h"
68#import "WebPluginViewFactoryPrivate.h"
69#import "WebPolicyDelegate.h"
70#import "WebPolicyDelegatePrivate.h"
71#import "WebPreferences.h"
72#import "WebResourceLoadDelegate.h"
73#import "WebScriptWorldInternal.h"
74#import "WebSecurityOriginInternal.h"
75#import "WebUIDelegate.h"
76#import "WebUIDelegatePrivate.h"
77#import "WebViewInternal.h"
78#import <JavaScriptCore/JSContextInternal.h>
79#import <WebCore/AuthenticationCF.h>
80#import <WebCore/AuthenticationMac.h>
81#import <WebCore/BackForwardController.h>
82#import <WebCore/BlockExceptions.h>
83#import <WebCore/CachedFrame.h>
84#import <WebCore/Chrome.h>
85#import <WebCore/Document.h>
86#import <WebCore/DocumentLoader.h>
87#import <WebCore/EventHandler.h>
88#import <WebCore/FocusController.h>
89#import <WebCore/FormState.h>
90#import <WebCore/Frame.h>
91#import <WebCore/FrameLoader.h>
92#import <WebCore/FrameLoaderStateMachine.h>
93#import <WebCore/FrameLoaderTypes.h>
94#import <WebCore/FrameTree.h>
95#import <WebCore/FrameView.h>
96#import <WebCore/HTMLAppletElement.h>
97#import <WebCore/HTMLFormElement.h>
98#import <WebCore/HTMLFrameElement.h>
99#import <WebCore/HTMLFrameOwnerElement.h>
100#import <WebCore/HTMLHeadElement.h>
101#import <WebCore/HTMLNames.h>
102#import <WebCore/HTMLParserIdioms.h>
103#import <WebCore/HTMLPlugInElement.h>
104#import <WebCore/HistoryController.h>
105#import <WebCore/HistoryItem.h>
106#import <WebCore/HitTestResult.h>
107#import <WebCore/IconDatabase.h>
108#import <WebCore/LoaderNSURLExtras.h>
109#import <WebCore/MIMETypeRegistry.h>
110#import <WebCore/MouseEvent.h>
111#import <WebCore/Page.h>
112#import <WebCore/PluginViewBase.h>
113#import <WebCore/ProtectionSpace.h>
114#import <WebCore/ResourceError.h>
115#import <WebCore/ResourceHandle.h>
116#import <WebCore/ResourceLoader.h>
117#import <WebCore/ResourceRequest.h>
118#import <WebCore/RunLoop.h>
119#import <WebCore/ScriptController.h>
120#import <WebCore/SharedBuffer.h>
121#import <WebCore/WebCoreObjCExtras.h>
122#import <WebCore/WebScriptObjectPrivate.h>
123#import <WebCore/Widget.h>
124#import <WebKit/DOMElement.h>
125#import <WebKit/DOMHTMLFormElement.h>
126#import <WebKitSystemInterface.h>
127#import <runtime/InitializeThreading.h>
128#import <wtf/MainThread.h>
129#import <wtf/PassRefPtr.h>
130#import <wtf/text/WTFString.h>
131
132#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
133#import <WebCore/HTMLMediaElement.h>
134#endif
135
136#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
137#import "NetscapePluginHostManager.h"
138#import "WebHostedNetscapePluginView.h"
139#endif
140
141using namespace WebCore;
142using namespace HTMLNames;
143
144// For backwards compatibility with older WebKit plug-ins.
145NSString *WebPluginBaseURLKey = @"WebPluginBaseURL";
146NSString *WebPluginAttributesKey = @"WebPluginAttributes";
147NSString *WebPluginContainerKey = @"WebPluginContainer";
148
149@interface WebFramePolicyListener : NSObject <WebPolicyDecisionListener, WebFormSubmissionListener> {
150    RefPtr<Frame> _frame;
151    FramePolicyFunction _policyFunction;
152}
153
154- (id)initWithFrame:(Frame*)frame policyFunction:(FramePolicyFunction)policyFunction;
155- (void)invalidate;
156
157@end
158
159static inline WebDataSource *dataSource(DocumentLoader* loader)
160{
161    return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
162}
163
164// Quirk for the Apple Dictionary application.
165//
166// If a top level frame has a <script> element in its <head> for a script named MainPageJavaScript.js,
167// then for that frame's document, ignore changes to the scrolling attribute of frames. That script
168// has a bug in it where it sets the scrolling attribute on frames, and that erroneous scrolling
169// attribute needs to be ignored to avoid showing extra scroll bars in the window.
170// This quirk can be removed when Apple Dictionary is fixed (see <rdar://problem/6471058>).
171
172static void applyAppleDictionaryApplicationQuirkNonInlinePart(WebFrameLoaderClient* client, const ResourceRequest& request)
173{
174    if (!request.url().isLocalFile())
175        return;
176    if (!request.url().string().endsWith("MainPageJavaScript.js"))
177        return;
178    Frame* frame = core(client->webFrame());
179    if (!frame)
180        return;
181    if (frame->tree()->parent())
182        return;
183    Document* document = frame->document();
184    if (!document)
185        return;
186    HTMLHeadElement* head = document->head();
187    if (!head)
188        return;
189    for (Node* c = head->firstChild(); c; c = c->nextSibling()) {
190        if (c->hasTagName(scriptTag) && toElement(c)->getAttribute(srcAttr) == "MainPageJavaScript.js") {
191            document->setFrameElementsShouldIgnoreScrolling(true);
192            return;
193        }
194    }
195}
196
197static inline void applyAppleDictionaryApplicationQuirk(WebFrameLoaderClient* client, const ResourceRequest& request)
198{
199    // Use a one-time-initialized global variable so we can quickly determine there's nothing to do in
200    // all applications other than Apple Dictionary.
201    static bool isAppleDictionary = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Dictionary"];
202    if (isAppleDictionary)
203        applyAppleDictionaryApplicationQuirkNonInlinePart(client, request);
204}
205
206WebFrameLoaderClient::WebFrameLoaderClient(WebFrame *webFrame)
207    : m_webFrame(webFrame)
208{
209}
210
211void WebFrameLoaderClient::frameLoaderDestroyed()
212{
213    [m_webFrame.get() _clearCoreFrame];
214    delete this;
215}
216
217bool WebFrameLoaderClient::hasWebView() const
218{
219    return [m_webFrame.get() webView] != nil;
220}
221
222void WebFrameLoaderClient::makeRepresentation(DocumentLoader* loader)
223{
224    [dataSource(loader) _makeRepresentation];
225}
226
227bool WebFrameLoaderClient::hasHTMLView() const
228{
229    NSView <WebDocumentView> *view = [m_webFrame->_private->webFrameView documentView];
230    return [view isKindOfClass:[WebHTMLView class]];
231}
232
233void WebFrameLoaderClient::forceLayout()
234{
235    NSView <WebDocumentView> *view = [m_webFrame->_private->webFrameView documentView];
236    [view setNeedsLayout:YES];
237    [view layout];
238}
239
240void WebFrameLoaderClient::forceLayoutForNonHTML()
241{
242    WebFrameView *thisView = m_webFrame->_private->webFrameView;
243    NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
244    ASSERT(thisDocumentView != nil);
245
246    // Tell the just loaded document to layout.  This may be necessary
247    // for non-html content that needs a layout message.
248    if (!([[m_webFrame.get() _dataSource] _isDocumentHTML])) {
249        [thisDocumentView setNeedsLayout:YES];
250        [thisDocumentView layout];
251        [thisDocumentView setNeedsDisplay:YES];
252    }
253}
254
255void WebFrameLoaderClient::setCopiesOnScroll()
256{
257    [[[m_webFrame->_private->webFrameView _scrollView] contentView] setCopiesOnScroll:YES];
258}
259
260void WebFrameLoaderClient::detachedFromParent2()
261{
262    //remove any NetScape plugins that are children of this frame because they are about to be detached
263    WebView *webView = getWebView(m_webFrame.get());
264    [webView removePluginInstanceViewsFor:(m_webFrame.get())];
265    [m_webFrame->_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
266
267    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
268    if (implementations->didRemoveFrameFromHierarchyFunc)
269        CallFrameLoadDelegate(implementations->didRemoveFrameFromHierarchyFunc, webView, @selector(webView:didRemoveFrameFromHierarchy:), m_webFrame.get());
270}
271
272void WebFrameLoaderClient::detachedFromParent3()
273{
274    [m_webFrame->_private->webFrameView release];
275    m_webFrame->_private->webFrameView = nil;
276}
277
278void WebFrameLoaderClient::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
279{
280    WebView *webView = getWebView(m_webFrame.get());
281
282    if (!documentLoader->mainResourceLoader()) {
283        // The resource has already been cached, start a new download.
284        WebDownload *webDownload = [[WebDownload alloc] initWithRequest:request.nsURLRequest(UpdateHTTPBody) delegate:[webView downloadDelegate]];
285        [webDownload autorelease];
286        return;
287    }
288
289    ResourceHandle* handle = documentLoader->mainResourceLoader()->handle();
290
291#if USE(CFNETWORK)
292    ASSERT([WebDownload respondsToSelector:@selector(_downloadWithLoadingCFURLConnection:request:response:delegate:proxy:)]);
293    CFURLConnectionRef connection = handle->connection();
294    [WebDownload _downloadWithLoadingCFURLConnection:connection
295                                                                     request:request.cfURLRequest(UpdateHTTPBody)
296                                                                    response:response.cfURLResponse()
297                                                                    delegate:[webView downloadDelegate]
298                                                                       proxy:nil];
299
300    // Release the connection since the NSURLDownload (actually CFURLDownload) will retain the connection and use it.
301    handle->releaseConnectionForDownload();
302    CFRelease(connection);
303#else
304    [WebDownload _downloadWithLoadingConnection:handle->connection()
305                                                                request:request.nsURLRequest(UpdateHTTPBody)
306                                                               response:response.nsURLResponse()
307                                                               delegate:[webView downloadDelegate]
308                                                                  proxy:nil];
309#endif
310}
311
312bool WebFrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
313{
314    applyAppleDictionaryApplicationQuirk(this, request);
315
316    WebView *webView = getWebView(m_webFrame.get());
317    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
318    if (!implementations->didLoadResourceFromMemoryCacheFunc)
319        return false;
320
321    CallResourceLoadDelegate(implementations->didLoadResourceFromMemoryCacheFunc, webView, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:), request.nsURLRequest(UpdateHTTPBody), response.nsURLResponse(), length, dataSource(loader));
322    return true;
323}
324
325void WebFrameLoaderClient::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
326{
327    WebView *webView = getWebView(m_webFrame.get());
328    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
329
330    id object = nil;
331    BOOL shouldRelease = NO;
332    if (implementations->identifierForRequestFunc)
333        object = CallResourceLoadDelegate(implementations->identifierForRequestFunc, webView, @selector(webView:identifierForInitialRequest:fromDataSource:), request.nsURLRequest(UpdateHTTPBody), dataSource(loader));
334    else {
335        object = [[NSObject alloc] init];
336        shouldRelease = YES;
337    }
338
339    [webView _addObject:object forIdentifier:identifier];
340
341    if (shouldRelease)
342        [object release];
343}
344
345void WebFrameLoaderClient::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
346{
347    applyAppleDictionaryApplicationQuirk(this, request);
348
349    WebView *webView = getWebView(m_webFrame.get());
350    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
351
352    if (redirectResponse.isNull())
353        static_cast<WebDocumentLoaderMac*>(loader)->increaseLoadCount(identifier);
354
355    NSURLRequest *currentURLRequest = request.nsURLRequest(UpdateHTTPBody);
356    NSURLRequest *newURLRequest = currentURLRequest;
357    if (implementations->willSendRequestFunc)
358        newURLRequest = (NSURLRequest *)CallResourceLoadDelegate(implementations->willSendRequestFunc, webView, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:), [webView _objectForIdentifier:identifier], currentURLRequest, redirectResponse.nsURLResponse(), dataSource(loader));
359
360    if (newURLRequest != currentURLRequest)
361        request = newURLRequest;
362}
363
364bool WebFrameLoaderClient::shouldUseCredentialStorage(DocumentLoader* loader, unsigned long identifier)
365{
366    WebView *webView = getWebView(m_webFrame.get());
367    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
368
369    if (implementations->shouldUseCredentialStorageFunc) {
370        if (id resource = [webView _objectForIdentifier:identifier])
371            return CallResourceLoadDelegateReturningBoolean(NO, implementations->shouldUseCredentialStorageFunc, webView, @selector(webView:resource:shouldUseCredentialStorageForDataSource:), resource, dataSource(loader));
372    }
373
374    return true;
375}
376
377void WebFrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(DocumentLoader* loader, unsigned long identifier, const AuthenticationChallenge& challenge)
378{
379    WebView *webView = getWebView(m_webFrame.get());
380    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
381
382    NSURLAuthenticationChallenge *webChallenge = mac(challenge);
383
384    if (implementations->didReceiveAuthenticationChallengeFunc) {
385        if (id resource = [webView _objectForIdentifier:identifier]) {
386            CallResourceLoadDelegate(implementations->didReceiveAuthenticationChallengeFunc, webView, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:), resource, webChallenge, dataSource(loader));
387            return;
388        }
389    }
390
391    NSWindow *window = [webView hostWindow] ? [webView hostWindow] : [webView window];
392    [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:webChallenge window:window];
393}
394
395#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
396bool WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace(DocumentLoader* loader, unsigned long identifier, const ProtectionSpace& protectionSpace)
397{
398    WebView *webView = getWebView(m_webFrame.get());
399    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
400
401    NSURLProtectionSpace *webProtectionSpace = mac(protectionSpace);
402
403    if (implementations->canAuthenticateAgainstProtectionSpaceFunc) {
404        if (id resource = [webView _objectForIdentifier:identifier]) {
405            return CallResourceLoadDelegateReturningBoolean(NO, implementations->canAuthenticateAgainstProtectionSpaceFunc, webView, @selector(webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource:), resource, webProtectionSpace, dataSource(loader));
406        }
407    }
408
409    // If our resource load delegate doesn't handle the question, then only send authentication
410    // challenges for pre-10.6 protection spaces.  This is the same as the default implementation
411    // in CFNetwork.
412    return (protectionSpace.authenticationScheme() < ProtectionSpaceAuthenticationSchemeClientCertificateRequested);
413}
414#endif
415
416bool WebFrameLoaderClient::shouldPaintBrokenImage(const KURL& imageURL) const
417{
418    WebView *webView = getWebView(m_webFrame.get());
419    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
420
421    if (implementations->shouldPaintBrokenImageForURLFunc) {
422        NSURL* url = imageURL;
423        return CallResourceLoadDelegateReturningBoolean(YES, implementations->shouldPaintBrokenImageForURLFunc, webView, @selector(webView:shouldPaintBrokenImageForURL:), url);
424    }
425    return true;
426}
427
428void WebFrameLoaderClient::dispatchDidCancelAuthenticationChallenge(DocumentLoader* loader, unsigned long identifier, const AuthenticationChallenge&challenge)
429{
430    WebView *webView = getWebView(m_webFrame.get());
431    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
432    NSURLAuthenticationChallenge *webChallenge = mac(challenge);
433
434    if (implementations->didCancelAuthenticationChallengeFunc) {
435        if (id resource = [webView _objectForIdentifier:identifier]) {
436            CallResourceLoadDelegate(implementations->didCancelAuthenticationChallengeFunc, webView, @selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:), resource, webChallenge, dataSource(loader));
437            return;
438        }
439    }
440
441    [(WebPanelAuthenticationHandler *)[WebPanelAuthenticationHandler sharedHandler] cancelAuthentication:webChallenge];
442}
443
444void WebFrameLoaderClient::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& response)
445{
446    WebView *webView = getWebView(m_webFrame.get());
447    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
448    if (implementations->didReceiveResponseFunc) {
449        if (id resource = [webView _objectForIdentifier:identifier])
450            CallResourceLoadDelegate(implementations->didReceiveResponseFunc, webView, @selector(webView:resource:didReceiveResponse:fromDataSource:), resource, response.nsURLResponse(), dataSource(loader));
451    }
452}
453
454NSCachedURLResponse* WebFrameLoaderClient::willCacheResponse(DocumentLoader* loader, unsigned long identifier, NSCachedURLResponse* response) const
455{
456    WebView *webView = getWebView(m_webFrame.get());
457    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
458
459    if (implementations->willCacheResponseFunc) {
460        if (id resource = [webView _objectForIdentifier:identifier])
461            return CallResourceLoadDelegate(implementations->willCacheResponseFunc, webView, @selector(webView:resource:willCacheResponse:fromDataSource:), resource, response, dataSource(loader));
462    }
463
464    return response;
465}
466
467void WebFrameLoaderClient::dispatchDidReceiveContentLength(DocumentLoader* loader, unsigned long identifier, int dataLength)
468{
469    WebView *webView = getWebView(m_webFrame.get());
470    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
471    if (implementations->didReceiveContentLengthFunc) {
472        if (id resource = [webView _objectForIdentifier:identifier])
473            CallResourceLoadDelegate(implementations->didReceiveContentLengthFunc, webView, @selector(webView:resource:didReceiveContentLength:fromDataSource:), resource, (NSInteger)dataLength, dataSource(loader));
474    }
475}
476
477void WebFrameLoaderClient::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier)
478{
479    WebView *webView = getWebView(m_webFrame.get());
480    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
481
482    if (implementations->didFinishLoadingFromDataSourceFunc) {
483        if (id resource = [webView _objectForIdentifier:identifier])
484            CallResourceLoadDelegate(implementations->didFinishLoadingFromDataSourceFunc, webView, @selector(webView:resource:didFinishLoadingFromDataSource:), resource, dataSource(loader));
485    }
486
487    [webView _removeObjectForIdentifier:identifier];
488
489    static_cast<WebDocumentLoaderMac*>(loader)->decreaseLoadCount(identifier);
490}
491
492void WebFrameLoaderClient::dispatchDidFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
493{
494    WebView *webView = getWebView(m_webFrame.get());
495    WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
496
497    if (implementations->didFailLoadingWithErrorFromDataSourceFunc) {
498        if (id resource = [webView _objectForIdentifier:identifier])
499            CallResourceLoadDelegate(implementations->didFailLoadingWithErrorFromDataSourceFunc, webView, @selector(webView:resource:didFailLoadingWithError:fromDataSource:), resource, (NSError *)error, dataSource(loader));
500    }
501
502    [webView _removeObjectForIdentifier:identifier];
503
504    static_cast<WebDocumentLoaderMac*>(loader)->decreaseLoadCount(identifier);
505}
506
507void WebFrameLoaderClient::dispatchDidHandleOnloadEvents()
508{
509    WebView *webView = getWebView(m_webFrame.get());
510    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
511    if (implementations->didHandleOnloadEventsForFrameFunc)
512        CallFrameLoadDelegate(implementations->didHandleOnloadEventsForFrameFunc, webView, @selector(webView:didHandleOnloadEventsForFrame:), m_webFrame.get());
513}
514
515void WebFrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad()
516{
517    m_webFrame->_private->provisionalURL = core(m_webFrame.get())->loader()->provisionalDocumentLoader()->url().string();
518
519    WebView *webView = getWebView(m_webFrame.get());
520    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
521    if (implementations->didReceiveServerRedirectForProvisionalLoadForFrameFunc)
522        CallFrameLoadDelegate(implementations->didReceiveServerRedirectForProvisionalLoadForFrameFunc, webView, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:), m_webFrame.get());
523}
524
525void WebFrameLoaderClient::dispatchDidCancelClientRedirect()
526{
527    WebView *webView = getWebView(m_webFrame.get());
528    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
529    if (implementations->didCancelClientRedirectForFrameFunc)
530        CallFrameLoadDelegate(implementations->didCancelClientRedirectForFrameFunc, webView, @selector(webView:didCancelClientRedirectForFrame:), m_webFrame.get());
531}
532
533void WebFrameLoaderClient::dispatchWillPerformClientRedirect(const KURL& url, double delay, double fireDate)
534{
535    WebView *webView = getWebView(m_webFrame.get());
536    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
537    if (implementations->willPerformClientRedirectToURLDelayFireDateForFrameFunc) {
538        NSURL *cocoaURL = url;
539        CallFrameLoadDelegate(implementations->willPerformClientRedirectToURLDelayFireDateForFrameFunc, webView, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:), cocoaURL, delay, [NSDate dateWithTimeIntervalSince1970:fireDate], m_webFrame.get());
540    }
541}
542
543void WebFrameLoaderClient::dispatchDidChangeLocationWithinPage()
544{
545    m_webFrame->_private->url = core(m_webFrame.get())->document()->url().string();
546
547    WebView *webView = getWebView(m_webFrame.get());
548    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
549    if (implementations->didChangeLocationWithinPageForFrameFunc)
550        CallFrameLoadDelegate(implementations->didChangeLocationWithinPageForFrameFunc, webView, @selector(webView:didChangeLocationWithinPageForFrame:), m_webFrame.get());
551}
552
553void WebFrameLoaderClient::dispatchDidPushStateWithinPage()
554{
555    m_webFrame->_private->url = core(m_webFrame.get())->document()->url().string();
556
557    WebView *webView = getWebView(m_webFrame.get());
558    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
559    if (implementations->didPushStateWithinPageForFrameFunc)
560        CallFrameLoadDelegate(implementations->didPushStateWithinPageForFrameFunc, webView, @selector(webView:didPushStateWithinPageForFrame:), m_webFrame.get());
561}
562
563void WebFrameLoaderClient::dispatchDidReplaceStateWithinPage()
564{
565    m_webFrame->_private->url = core(m_webFrame.get())->document()->url().string();
566
567    WebView *webView = getWebView(m_webFrame.get());
568    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
569    if (implementations->didReplaceStateWithinPageForFrameFunc)
570        CallFrameLoadDelegate(implementations->didReplaceStateWithinPageForFrameFunc, webView, @selector(webView:didReplaceStateWithinPageForFrame:), m_webFrame.get());
571}
572
573void WebFrameLoaderClient::dispatchDidPopStateWithinPage()
574{
575    m_webFrame->_private->url = core(m_webFrame.get())->document()->url().string();
576
577    WebView *webView = getWebView(m_webFrame.get());
578    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
579    if (implementations->didPopStateWithinPageForFrameFunc)
580        CallFrameLoadDelegate(implementations->didPopStateWithinPageForFrameFunc, webView, @selector(webView:didPopStateWithinPageForFrame:), m_webFrame.get());
581}
582
583void WebFrameLoaderClient::dispatchWillClose()
584{
585    WebView *webView = getWebView(m_webFrame.get());
586    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
587    if (implementations->willCloseFrameFunc)
588        CallFrameLoadDelegate(implementations->willCloseFrameFunc, webView, @selector(webView:willCloseFrame:), m_webFrame.get());
589}
590
591void WebFrameLoaderClient::dispatchDidReceiveIcon()
592{
593#if ENABLE(ICONDATABASE)
594    WebView *webView = getWebView(m_webFrame.get());
595    ASSERT(m_webFrame == [webView mainFrame]);
596    [webView _dispatchDidReceiveIconFromWebFrame:m_webFrame.get()];
597#endif
598}
599
600void WebFrameLoaderClient::dispatchDidStartProvisionalLoad()
601{
602    ASSERT(!m_webFrame->_private->provisionalURL);
603    m_webFrame->_private->provisionalURL = core(m_webFrame.get())->loader()->provisionalDocumentLoader()->url().string();
604
605    WebView *webView = getWebView(m_webFrame.get());
606    [webView _didStartProvisionalLoadForFrame:m_webFrame.get()];
607
608    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
609    if (implementations->didStartProvisionalLoadForFrameFunc)
610        CallFrameLoadDelegate(implementations->didStartProvisionalLoadForFrameFunc, webView, @selector(webView:didStartProvisionalLoadForFrame:), m_webFrame.get());
611}
612
613void WebFrameLoaderClient::dispatchDidReceiveTitle(const StringWithDirection& title)
614{
615    WebView *webView = getWebView(m_webFrame.get());
616    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
617    if (implementations->didReceiveTitleForFrameFunc)
618        // FIXME: use direction of title.
619        CallFrameLoadDelegate(implementations->didReceiveTitleForFrameFunc, webView, @selector(webView:didReceiveTitle:forFrame:), (NSString *)title.string(), m_webFrame.get());
620}
621
622void WebFrameLoaderClient::dispatchDidChangeIcons(WebCore::IconType)
623{
624     // FIXME: Implement this to allow container to update favicon.
625}
626
627void WebFrameLoaderClient::dispatchDidCommitLoad()
628{
629    // Tell the client we've committed this URL.
630    ASSERT([m_webFrame->_private->webFrameView documentView] != nil);
631
632    WebView *webView = getWebView(m_webFrame.get());
633    [webView _didCommitLoadForFrame:m_webFrame.get()];
634
635    m_webFrame->_private->url = m_webFrame->_private->provisionalURL;
636    m_webFrame->_private->provisionalURL = nullptr;
637
638    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
639    if (implementations->didCommitLoadForFrameFunc)
640        CallFrameLoadDelegate(implementations->didCommitLoadForFrameFunc, webView, @selector(webView:didCommitLoadForFrame:), m_webFrame.get());
641}
642
643void WebFrameLoaderClient::dispatchDidFailProvisionalLoad(const ResourceError& error)
644{
645    m_webFrame->_private->provisionalURL = nullptr;
646
647    WebView *webView = getWebView(m_webFrame.get());
648    [webView _didFailProvisionalLoadWithError:error forFrame:m_webFrame.get()];
649
650    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
651    if (implementations->didFailProvisionalLoadWithErrorForFrameFunc)
652        CallFrameLoadDelegate(implementations->didFailProvisionalLoadWithErrorForFrameFunc, webView, @selector(webView:didFailProvisionalLoadWithError:forFrame:), (NSError *)error, m_webFrame.get());
653
654    [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:error];
655}
656
657void WebFrameLoaderClient::dispatchDidFailLoad(const ResourceError& error)
658{
659    ASSERT(!m_webFrame->_private->provisionalURL);
660
661    WebView *webView = getWebView(m_webFrame.get());
662    [webView _didFailLoadWithError:error forFrame:m_webFrame.get()];
663
664    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
665    if (implementations->didFailLoadWithErrorForFrameFunc)
666        CallFrameLoadDelegate(implementations->didFailLoadWithErrorForFrameFunc, webView, @selector(webView:didFailLoadWithError:forFrame:), (NSError *)error, m_webFrame.get());
667
668    [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:error];
669}
670
671void WebFrameLoaderClient::dispatchDidFinishDocumentLoad()
672{
673    WebView *webView = getWebView(m_webFrame.get());
674    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
675    if (implementations->didFinishDocumentLoadForFrameFunc)
676        CallFrameLoadDelegate(implementations->didFinishDocumentLoadForFrameFunc, webView, @selector(webView:didFinishDocumentLoadForFrame:), m_webFrame.get());
677}
678
679void WebFrameLoaderClient::dispatchDidFinishLoad()
680{
681    ASSERT(!m_webFrame->_private->provisionalURL);
682
683    WebView *webView = getWebView(m_webFrame.get());
684    [webView _didFinishLoadForFrame:m_webFrame.get()];
685
686    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
687    if (implementations->didFinishLoadForFrameFunc)
688        CallFrameLoadDelegate(implementations->didFinishLoadForFrameFunc, webView, @selector(webView:didFinishLoadForFrame:), m_webFrame.get());
689
690    [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:nil];
691}
692
693void WebFrameLoaderClient::dispatchDidLayout(LayoutMilestones milestones)
694{
695    WebView *webView = getWebView(m_webFrame.get());
696    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
697
698    if (implementations->didLayoutFunc)
699        CallFrameLoadDelegate(implementations->didLayoutFunc, webView, @selector(webView:didLayout:), kitLayoutMilestones(milestones));
700
701    if (milestones & DidFirstLayout) {
702        // FIXME: We should consider removing the old didFirstLayout API since this is doing double duty with the
703        // new didLayout API.
704        if (implementations->didFirstLayoutInFrameFunc)
705            CallFrameLoadDelegate(implementations->didFirstLayoutInFrameFunc, webView, @selector(webView:didFirstLayoutInFrame:), m_webFrame.get());
706
707        // See WebFrameLoaderClient::provisionalLoadStarted.
708        WebDynamicScrollBarsView *scrollView = [m_webFrame->_private->webFrameView _scrollView];
709        if ([getWebView(m_webFrame.get()) drawsBackground])
710            [scrollView setDrawsBackground:YES];
711#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
712        [scrollView setVerticalScrollElasticity:NSScrollElasticityAutomatic];
713        [scrollView setHorizontalScrollElasticity:NSScrollElasticityAutomatic];
714#endif
715    }
716
717    if (milestones & DidFirstVisuallyNonEmptyLayout) {
718        // FIXME: We should consider removing the old didFirstVisuallyNonEmptyLayoutForFrame API since this is doing
719        // double duty with the new didLayout API.
720        if (implementations->didFirstVisuallyNonEmptyLayoutInFrameFunc)
721            CallFrameLoadDelegate(implementations->didFirstVisuallyNonEmptyLayoutInFrameFunc, webView, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:), m_webFrame.get());
722    }
723}
724
725Frame* WebFrameLoaderClient::dispatchCreatePage(const NavigationAction&)
726{
727    WebView *currentWebView = getWebView(m_webFrame.get());
728    NSDictionary *features = [[NSDictionary alloc] init];
729    WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
730                                                createWebViewWithRequest:nil
731                                                          windowFeatures:features];
732    [features release];
733
734#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
735    if (newWebView)
736        WebKit::NetscapePluginHostManager::shared().didCreateWindow();
737#endif
738
739    return core([newWebView mainFrame]);
740}
741
742void WebFrameLoaderClient::dispatchShow()
743{
744    WebView *webView = getWebView(m_webFrame.get());
745    [[webView _UIDelegateForwarder] webViewShow:webView];
746}
747
748void WebFrameLoaderClient::dispatchDecidePolicyForResponse(FramePolicyFunction function,
749    const ResourceResponse& response, const ResourceRequest& request)
750{
751    WebView *webView = getWebView(m_webFrame.get());
752
753    [[webView _policyDelegateForwarder] webView:webView
754                        decidePolicyForMIMEType:response.mimeType()
755                                        request:request.nsURLRequest(UpdateHTTPBody)
756                                          frame:m_webFrame.get()
757                               decisionListener:setUpPolicyListener(function).get()];
758}
759
760void WebFrameLoaderClient::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction function,
761    const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName)
762{
763    WebView *webView = getWebView(m_webFrame.get());
764    [[webView _policyDelegateForwarder] webView:webView
765            decidePolicyForNewWindowAction:actionDictionary(action, formState)
766                                   request:request.nsURLRequest(UpdateHTTPBody)
767                              newFrameName:frameName
768                          decisionListener:setUpPolicyListener(function).get()];
769}
770
771void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(FramePolicyFunction function,
772    const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState)
773{
774    WebView *webView = getWebView(m_webFrame.get());
775    [[webView _policyDelegateForwarder] webView:webView
776                decidePolicyForNavigationAction:actionDictionary(action, formState)
777                                        request:request.nsURLRequest(UpdateHTTPBody)
778                                          frame:m_webFrame.get()
779                               decisionListener:setUpPolicyListener(function).get()];
780}
781
782void WebFrameLoaderClient::cancelPolicyCheck()
783{
784    [m_policyListener invalidate];
785    m_policyListener = nullptr;
786}
787
788void WebFrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError& error)
789{
790    WebView *webView = getWebView(m_webFrame.get());
791    [[webView _policyDelegateForwarder] webView:webView unableToImplementPolicyWithError:error frame:m_webFrame.get()];
792}
793
794static NSDictionary *makeFormFieldValuesDictionary(FormState* formState)
795{
796    const StringPairVector& textFieldValues = formState->textFieldValues();
797    size_t size = textFieldValues.size();
798    NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:size];
799    for (size_t i = 0; i < size; ++i)
800        [dictionary setObject:textFieldValues[i].second forKey:textFieldValues[i].first];
801
802    return [dictionary autorelease];
803}
804
805void WebFrameLoaderClient::dispatchWillSendSubmitEvent(PassRefPtr<WebCore::FormState> formState)
806{
807    id <WebFormDelegate> formDelegate = [getWebView(m_webFrame.get()) _formDelegate];
808    if (!formDelegate)
809        return;
810
811    DOMHTMLFormElement *formElement = kit(formState->form());
812    NSDictionary *values = makeFormFieldValuesDictionary(formState.get());
813    CallFormDelegate(getWebView(m_webFrame.get()), @selector(willSendSubmitEventToForm:inFrame:withValues:), formElement, m_webFrame.get(), values);
814}
815
816void WebFrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction function, PassRefPtr<FormState> formState)
817{
818    id <WebFormDelegate> formDelegate = [getWebView(m_webFrame.get()) _formDelegate];
819    if (!formDelegate) {
820        (core(m_webFrame.get())->loader()->policyChecker()->*function)(PolicyUse);
821        return;
822    }
823
824    NSDictionary *values = makeFormFieldValuesDictionary(formState.get());
825    CallFormDelegate(getWebView(m_webFrame.get()), @selector(frame:sourceFrame:willSubmitForm:withValues:submissionListener:), m_webFrame.get(), kit(formState->sourceDocument()->frame()), kit(formState->form()), values, setUpPolicyListener(function).get());
826}
827
828void WebFrameLoaderClient::revertToProvisionalState(DocumentLoader* loader)
829{
830    [dataSource(loader) _revertToProvisionalState];
831}
832
833void WebFrameLoaderClient::setMainDocumentError(DocumentLoader* loader, const ResourceError& error)
834{
835    [dataSource(loader) _setMainDocumentError:error];
836}
837
838void WebFrameLoaderClient::willChangeEstimatedProgress()
839{
840    [getWebView(m_webFrame.get()) _willChangeValueForKey:_WebEstimatedProgressKey];
841}
842
843void WebFrameLoaderClient::didChangeEstimatedProgress()
844{
845    [getWebView(m_webFrame.get()) _didChangeValueForKey:_WebEstimatedProgressKey];
846}
847
848void WebFrameLoaderClient::postProgressStartedNotification()
849{
850    [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:getWebView(m_webFrame.get())];
851}
852
853void WebFrameLoaderClient::postProgressEstimateChangedNotification()
854{
855    [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:getWebView(m_webFrame.get())];
856}
857
858void WebFrameLoaderClient::postProgressFinishedNotification()
859{
860    [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:getWebView(m_webFrame.get())];
861}
862
863void WebFrameLoaderClient::setMainFrameDocumentReady(bool ready)
864{
865    [getWebView(m_webFrame.get()) setMainFrameDocumentReady:ready];
866}
867
868void WebFrameLoaderClient::startDownload(const ResourceRequest& request, const String& /* suggestedName */)
869{
870    // FIXME: Should download full request.
871    [getWebView(m_webFrame.get()) _downloadURL:request.url()];
872}
873
874void WebFrameLoaderClient::willChangeTitle(DocumentLoader* loader)
875{
876    // FIXME: Should do this only in main frame case, right?
877    [getWebView(m_webFrame.get()) _willChangeValueForKey:_WebMainFrameTitleKey];
878}
879
880void WebFrameLoaderClient::didChangeTitle(DocumentLoader* loader)
881{
882    // FIXME: Should do this only in main frame case, right?
883    [getWebView(m_webFrame.get()) _didChangeValueForKey:_WebMainFrameTitleKey];
884}
885
886void WebFrameLoaderClient::committedLoad(DocumentLoader* loader, const char* data, int length)
887{
888    NSData *nsData = [[NSData alloc] initWithBytesNoCopy:(void*)data length:length freeWhenDone:NO];
889    [dataSource(loader) _receivedData:nsData];
890    [nsData release];
891}
892
893void WebFrameLoaderClient::finishedLoading(DocumentLoader* loader)
894{
895    [dataSource(loader) _finishedLoading];
896}
897
898static inline NSString *nilOrNSString(const String& string)
899{
900    if (string.isNull())
901        return nil;
902    return string;
903}
904
905void WebFrameLoaderClient::updateGlobalHistory()
906{
907    WebView* view = getWebView(m_webFrame.get());
908    DocumentLoader* loader = core(m_webFrame.get())->loader()->documentLoader();
909
910    if ([view historyDelegate]) {
911        WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(view);
912        if (implementations->navigatedFunc) {
913            WebNavigationData *data = [[WebNavigationData alloc] initWithURLString:loader->url()
914                                                                             title:nilOrNSString(loader->title().string())
915                                                                   originalRequest:loader->originalRequestCopy().nsURLRequest(UpdateHTTPBody)
916                                                                          response:loader->response().nsURLResponse()
917                                                                 hasSubstituteData:loader->substituteData().isValid()
918                                                              clientRedirectSource:loader->clientRedirectSourceForHistory()];
919
920            CallHistoryDelegate(implementations->navigatedFunc, view, @selector(webView:didNavigateWithNavigationData:inFrame:), data, m_webFrame.get());
921            [data release];
922        }
923
924        return;
925    }
926
927    [[WebHistory optionalSharedHistory] _visitedURL:loader->urlForHistory()
928                                          withTitle:loader->title().string()
929                                             method:loader->originalRequestCopy().httpMethod()
930                                         wasFailure:loader->urlForHistoryReflectsFailure()
931                                 increaseVisitCount:!loader->clientRedirectSourceForHistory()]; // Do not increase visit count due to navigations that were not initiated by the user directly, avoiding growth from programmatic reloads.
932}
933
934void WebFrameLoaderClient::updateGlobalHistoryRedirectLinks()
935{
936    WebView* view = getWebView(m_webFrame.get());
937    WebHistoryDelegateImplementationCache* implementations = [view historyDelegate] ? WebViewGetHistoryDelegateImplementations(view) : 0;
938
939    DocumentLoader* loader = core(m_webFrame.get())->loader()->documentLoader();
940    ASSERT(loader->unreachableURL().isEmpty());
941
942    if (!loader->clientRedirectSourceForHistory().isNull()) {
943        if (implementations) {
944            if (implementations->clientRedirectFunc) {
945                CallHistoryDelegate(implementations->clientRedirectFunc, view, @selector(webView:didPerformClientRedirectFromURL:toURL:inFrame:),
946                    m_webFrame->_private->url.get(), loader->clientRedirectDestinationForHistory(), m_webFrame.get());
947            }
948        } else if (WebHistoryItem *item = [[WebHistory optionalSharedHistory] _itemForURLString:loader->clientRedirectSourceForHistory()])
949            core(item)->addRedirectURL(loader->clientRedirectDestinationForHistory());
950    }
951
952    if (!loader->serverRedirectSourceForHistory().isNull()) {
953        if (implementations) {
954            if (implementations->serverRedirectFunc) {
955                CallHistoryDelegate(implementations->serverRedirectFunc, view, @selector(webView:didPerformServerRedirectFromURL:toURL:inFrame:),
956                    loader->serverRedirectSourceForHistory(), loader->serverRedirectDestinationForHistory(), m_webFrame.get());
957            }
958        } else if (WebHistoryItem *item = [[WebHistory optionalSharedHistory] _itemForURLString:loader->serverRedirectSourceForHistory()])
959            core(item)->addRedirectURL(loader->serverRedirectDestinationForHistory());
960    }
961}
962
963bool WebFrameLoaderClient::shouldGoToHistoryItem(HistoryItem* item) const
964{
965    WebView* view = getWebView(m_webFrame.get());
966    WebHistoryItem *webItem = kit(item);
967
968    return [[view _policyDelegateForwarder] webView:view shouldGoToHistoryItem:webItem];
969}
970
971bool WebFrameLoaderClient::shouldStopLoadingForHistoryItem(HistoryItem* item) const
972{
973    return true;
974}
975
976void WebFrameLoaderClient::updateGlobalHistoryItemForPage()
977{
978    HistoryItem* historyItem = 0;
979
980    if (Page* page = core(m_webFrame.get())->page()) {
981        if (!page->settings()->privateBrowsingEnabled())
982            historyItem = page->backForward()->currentItem();
983    }
984
985    WebView *webView = getWebView(m_webFrame.get());
986    [webView _setGlobalHistoryItem:historyItem];
987}
988
989void WebFrameLoaderClient::didDisplayInsecureContent()
990{
991    WebView *webView = getWebView(m_webFrame.get());
992    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
993    if (implementations->didDisplayInsecureContentFunc)
994        CallFrameLoadDelegate(implementations->didDisplayInsecureContentFunc, webView, @selector(webViewDidDisplayInsecureContent:));
995}
996
997void WebFrameLoaderClient::didRunInsecureContent(SecurityOrigin* origin, const KURL& insecureURL)
998{
999    WebView *webView = getWebView(m_webFrame.get());
1000    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
1001    if (implementations->didRunInsecureContentFunc) {
1002        RetainPtr<WebSecurityOrigin> webSecurityOrigin = adoptNS([[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin]);
1003        CallFrameLoadDelegate(implementations->didRunInsecureContentFunc, webView, @selector(webView:didRunInsecureContent:), webSecurityOrigin.get());
1004    }
1005}
1006
1007void WebFrameLoaderClient::didDetectXSS(const KURL& insecureURL, bool didBlockEntirePage)
1008{
1009    WebView *webView = getWebView(m_webFrame.get());
1010    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
1011    if (implementations->didDetectXSSFunc) {
1012        // FIXME: must pass didBlockEntirePage if we want to do more on mac than just pass tests.
1013        NSURL* insecureNSURL = insecureURL;
1014        CallFrameLoadDelegate(implementations->didDetectXSSFunc, webView, @selector(webView:didDetectXSS:), insecureNSURL);
1015    }
1016}
1017
1018ResourceError WebFrameLoaderClient::cancelledError(const ResourceRequest& request)
1019{
1020    return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:request.url()];
1021}
1022
1023ResourceError WebFrameLoaderClient::blockedError(const ResourceRequest& request)
1024{
1025    return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorCannotUseRestrictedPort URL:request.url()];
1026}
1027
1028ResourceError WebFrameLoaderClient::cannotShowURLError(const ResourceRequest& request)
1029{
1030    return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorCannotShowURL URL:request.url()];
1031}
1032
1033ResourceError WebFrameLoaderClient::interruptedForPolicyChangeError(const ResourceRequest& request)
1034{
1035    return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:request.url()];
1036}
1037
1038ResourceError WebFrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse& response)
1039{
1040    return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:WebKitErrorCannotShowMIMEType URL:response.url()];
1041}
1042
1043ResourceError WebFrameLoaderClient::fileDoesNotExistError(const ResourceResponse& response)
1044{
1045    return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist URL:response.url()];
1046}
1047
1048ResourceError WebFrameLoaderClient::pluginWillHandleLoadError(const ResourceResponse& response)
1049{
1050    NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
1051                                                    contentURL:response.url()
1052                                                 pluginPageURL:nil
1053                                                    pluginName:nil
1054                                                      MIMEType:response.mimeType()];
1055    return [error autorelease];
1056}
1057
1058bool WebFrameLoaderClient::shouldFallBack(const ResourceError& error)
1059{
1060    // FIXME: Needs to check domain.
1061    // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent
1062    // loading plugin content twice.  See <rdar://problem/4258008>
1063    return error.errorCode() != NSURLErrorCancelled && error.errorCode() != WebKitErrorPlugInWillHandleLoad;
1064}
1065
1066bool WebFrameLoaderClient::canHandleRequest(const ResourceRequest& request) const
1067{
1068    Frame* frame = core(m_webFrame.get());
1069    Page* page = frame->page();
1070    BOOL forMainFrame = page && page->mainFrame() == frame;
1071    return [WebView _canHandleRequest:request.nsURLRequest(UpdateHTTPBody) forMainFrame:forMainFrame];
1072}
1073
1074bool WebFrameLoaderClient::canShowMIMEType(const String& MIMEType) const
1075{
1076    return [getWebView(m_webFrame.get()) _canShowMIMEType:MIMEType];
1077}
1078
1079bool WebFrameLoaderClient::canShowMIMETypeAsHTML(const String& MIMEType) const
1080{
1081    return [WebView canShowMIMETypeAsHTML:MIMEType];
1082}
1083
1084bool WebFrameLoaderClient::representationExistsForURLScheme(const String& URLScheme) const
1085{
1086    return [WebView _representationExistsForURLScheme:URLScheme];
1087}
1088
1089String WebFrameLoaderClient::generatedMIMETypeForURLScheme(const String& URLScheme) const
1090{
1091    return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1092}
1093
1094void WebFrameLoaderClient::frameLoadCompleted()
1095{
1096    // Note: Can be called multiple times.
1097
1098    // See WebFrameLoaderClient::provisionalLoadStarted.
1099    if ([getWebView(m_webFrame.get()) drawsBackground])
1100        [[m_webFrame->_private->webFrameView _scrollView] setDrawsBackground:YES];
1101}
1102
1103void WebFrameLoaderClient::saveViewStateToItem(HistoryItem* item)
1104{
1105    if (!item)
1106        return;
1107
1108    NSView <WebDocumentView> *docView = [m_webFrame->_private->webFrameView documentView];
1109
1110    // we might already be detached when this is called from detachFromParent, in which
1111    // case we don't want to override real data earlier gathered with (0,0)
1112    if ([docView superview] && [docView conformsToProtocol:@protocol(_WebDocumentViewState)])
1113        item->setViewState([(id <_WebDocumentViewState>)docView viewState]);
1114}
1115
1116void WebFrameLoaderClient::restoreViewState()
1117{
1118    HistoryItem* currentItem = core(m_webFrame.get())->loader()->history()->currentItem();
1119    ASSERT(currentItem);
1120
1121    // FIXME: As the ASSERT attests, it seems we should always have a currentItem here.
1122    // One counterexample is <rdar://problem/4917290>
1123    // For now, to cover this issue in release builds, there is no technical harm to returning
1124    // early and from a user standpoint - as in the above radar - the previous page load failed
1125    // so there *is* no scroll state to restore!
1126    if (!currentItem)
1127        return;
1128
1129    NSView <WebDocumentView> *docView = [m_webFrame->_private->webFrameView documentView];
1130    if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1131        id state = currentItem->viewState();
1132        if (state) {
1133            [(id <_WebDocumentViewState>)docView setViewState:state];
1134        }
1135    }
1136}
1137
1138void WebFrameLoaderClient::provisionalLoadStarted()
1139{
1140    // Tell the scroll view not to draw a background so we can leave the contents of
1141    // the old page showing during the beginning of the loading process.
1142
1143    // This will stay set to NO until:
1144    //    1) The load gets far enough along: WebFrameLoader::frameLoadCompleted.
1145    //    2) The window is resized: -[WebFrameView setFrameSize:].
1146    // or 3) The view is moved out of the window: -[WebFrameView viewDidMoveToWindow].
1147    // Please keep the comments in these four functions in agreement with each other.
1148
1149    WebDynamicScrollBarsView *scrollView = [m_webFrame->_private->webFrameView _scrollView];
1150    [scrollView setDrawsBackground:NO];
1151#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1152    [scrollView setVerticalScrollElasticity:NSScrollElasticityNone];
1153    [scrollView setHorizontalScrollElasticity:NSScrollElasticityNone];
1154#endif
1155}
1156
1157void WebFrameLoaderClient::didFinishLoad()
1158{
1159    [m_webFrame->_private->internalLoadDelegate webFrame:m_webFrame.get() didFinishLoadWithError:nil];
1160}
1161
1162void WebFrameLoaderClient::prepareForDataSourceReplacement()
1163{
1164    if (![m_webFrame.get() _dataSource]) {
1165        ASSERT(!core(m_webFrame.get())->tree()->childCount());
1166        return;
1167    }
1168
1169    // Make sure that any work that is triggered by resigning first reponder can get done.
1170    // The main example where this came up is the textDidEndEditing that is sent to the
1171    // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
1172    // remove the views as a side-effect of freeing the frame, at which point we can't
1173    // post the FormDelegate messages.
1174    //
1175    // Note that this can also take FirstResponder away from a child of our frameView that
1176    // is not in a child frame's view.  This is OK because we are in the process
1177    // of loading new content, which will blow away all editors in this top frame, and if
1178    // a non-editor is firstReponder it will not be affected by endEditingFor:.
1179    // Potentially one day someone could write a DocView whose editors were not all
1180    // replaced by loading new content, but that does not apply currently.
1181    NSView *frameView = m_webFrame->_private->webFrameView;
1182    NSWindow *window = [frameView window];
1183    NSResponder *firstResp = [window firstResponder];
1184    if ([firstResp isKindOfClass:[NSView class]] && [(NSView *)firstResp isDescendantOf:frameView])
1185        [window endEditingFor:firstResp];
1186}
1187
1188PassRefPtr<DocumentLoader> WebFrameLoaderClient::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
1189{
1190    RefPtr<WebDocumentLoaderMac> loader = WebDocumentLoaderMac::create(request, substituteData);
1191
1192    WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoader:loader.get()];
1193    loader->setDataSource(dataSource, getWebView(m_webFrame.get()));
1194    [dataSource release];
1195
1196    return loader.release();
1197}
1198
1199void WebFrameLoaderClient::setTitle(const StringWithDirection& title, const KURL& url)
1200{
1201    WebView* view = getWebView(m_webFrame.get());
1202
1203    if ([view historyDelegate]) {
1204        WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(view);
1205        // FIXME: use direction of title.
1206        if (implementations->setTitleFunc)
1207            CallHistoryDelegate(implementations->setTitleFunc, view, @selector(webView:updateHistoryTitle:forURL:inFrame:), (NSString *)title.string(), (NSString *)url, m_webFrame.get());
1208        else if (implementations->deprecatedSetTitleFunc)
1209            CallHistoryDelegate(implementations->deprecatedSetTitleFunc, view, @selector(webView:updateHistoryTitle:forURL:), (NSString *)title.string(), (NSString *)url);
1210
1211        return;
1212    }
1213
1214    NSURL* nsURL = url;
1215    nsURL = [nsURL _webkit_canonicalize];
1216    if(!nsURL)
1217        return;
1218    NSString *titleNSString = title.string();
1219
1220    [[[WebHistory optionalSharedHistory] itemForURL:nsURL] setTitle:titleNSString];
1221}
1222
1223void WebFrameLoaderClient::savePlatformDataToCachedFrame(CachedFrame* cachedFrame)
1224{
1225    OwnPtr<WebCachedFramePlatformData> webPlatformData = adoptPtr(new WebCachedFramePlatformData([m_webFrame->_private->webFrameView documentView]));
1226    cachedFrame->setCachedFramePlatformData(webPlatformData.release());
1227}
1228
1229void WebFrameLoaderClient::transitionToCommittedFromCachedFrame(CachedFrame* cachedFrame)
1230{
1231    WebCachedFramePlatformData* platformData = reinterpret_cast<WebCachedFramePlatformData*>(cachedFrame->cachedFramePlatformData());
1232    NSView <WebDocumentView> *cachedView = platformData->webDocumentView();
1233    ASSERT(cachedView != nil);
1234    ASSERT(cachedFrame->documentLoader());
1235    [cachedView setDataSource:dataSource(cachedFrame->documentLoader())];
1236
1237    // clean up webkit plugin instances before WebHTMLView gets freed.
1238    WebView *webView = getWebView(m_webFrame.get());
1239    [webView removePluginInstanceViewsFor:(m_webFrame.get())];
1240
1241    [m_webFrame->_private->webFrameView _setDocumentView:cachedView];
1242}
1243
1244void WebFrameLoaderClient::transitionToCommittedForNewPage()
1245{
1246    WebView *webView = getWebView(m_webFrame.get());
1247    WebDataSource *dataSource = [m_webFrame.get() _dataSource];
1248
1249    bool willProduceHTMLView = [m_webFrame->_private->webFrameView _viewClassForMIMEType:[dataSource _responseMIMEType]] == [WebHTMLView class];
1250    bool canSkipCreation = core(m_webFrame.get())->loader()->stateMachine()->committingFirstRealLoad() && willProduceHTMLView;
1251    if (canSkipCreation) {
1252        [[m_webFrame->_private->webFrameView documentView] setDataSource:dataSource];
1253        return;
1254    }
1255
1256    // Don't suppress scrollbars before the view creation if we're making the view for a non-HTML view.
1257    if (!willProduceHTMLView)
1258        [[m_webFrame->_private->webFrameView _scrollView] setScrollBarsSuppressed:NO repaintOnUnsuppress:NO];
1259
1260    // clean up webkit plugin instances before WebHTMLView gets freed.
1261    [webView removePluginInstanceViewsFor:(m_webFrame.get())];
1262
1263    NSView <WebDocumentView> *documentView = [m_webFrame->_private->webFrameView _makeDocumentViewForDataSource:dataSource];
1264    if (!documentView)
1265        return;
1266
1267    // FIXME: Could we skip some of this work for a top-level view that is not a WebHTMLView?
1268
1269    // If we own the view, delete the old one - otherwise the render m_frame will take care of deleting the view.
1270    Frame* coreFrame = core(m_webFrame.get());
1271    Page* page = coreFrame->page();
1272    bool isMainFrame = coreFrame == page->mainFrame();
1273    if (isMainFrame && coreFrame->view())
1274        coreFrame->view()->setParentVisible(false);
1275    coreFrame->setView(0);
1276    RefPtr<FrameView> coreView = FrameView::create(coreFrame);
1277    coreFrame->setView(coreView);
1278
1279    [m_webFrame.get() _updateBackgroundAndUpdatesWhileOffscreen];
1280    [m_webFrame->_private->webFrameView _install];
1281
1282    if (isMainFrame)
1283        coreView->setParentVisible(true);
1284
1285    // Call setDataSource on the document view after it has been placed in the view hierarchy.
1286    // This what we for the top-level view, so should do this for views in subframes as well.
1287    [documentView setDataSource:dataSource];
1288
1289    // The following is a no-op for WebHTMLRepresentation, but for custom document types
1290    // like the ones that Safari uses for bookmarks it is the only way the DocumentLoader
1291    // will get the proper title.
1292    if (DocumentLoader* documentLoader = [dataSource _documentLoader])
1293        documentLoader->setTitle(StringWithDirection([dataSource pageTitle], LTR));
1294
1295    if (HTMLFrameOwnerElement* owner = coreFrame->ownerElement())
1296        coreFrame->view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
1297
1298    // If the document view implicitly became first responder, make sure to set the focused frame properly.
1299    if ([[documentView window] firstResponder] == documentView) {
1300        page->focusController()->setFocusedFrame(coreFrame);
1301        page->focusController()->setFocused(true);
1302    }
1303}
1304
1305void WebFrameLoaderClient::didSaveToPageCache()
1306{
1307}
1308
1309void WebFrameLoaderClient::didRestoreFromPageCache()
1310{
1311}
1312
1313void WebFrameLoaderClient::dispatchDidBecomeFrameset(bool)
1314{
1315}
1316
1317RetainPtr<WebFramePolicyListener> WebFrameLoaderClient::setUpPolicyListener(FramePolicyFunction function)
1318{
1319    // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
1320    [m_policyListener invalidate];
1321
1322    m_policyListener = adoptNS([[WebFramePolicyListener alloc] initWithFrame:core(m_webFrame.get()) policyFunction:function]);
1323
1324    return m_policyListener;
1325}
1326
1327String WebFrameLoaderClient::userAgent(const KURL& url)
1328{
1329    WebView *webView = getWebView(m_webFrame.get());
1330    ASSERT(webView);
1331
1332    // We should never get here with nil for the WebView unless there is a bug somewhere else.
1333    // But if we do, it's better to return the empty string than just crashing on the spot.
1334    // Most other call sites are tolerant of nil because of Objective-C behavior, but this one
1335    // is not because the return value of _userAgentForURL is a const KURL&.
1336    if (!webView)
1337        return String("");
1338
1339    return [webView _userAgentString];
1340}
1341
1342static const MouseEvent* findMouseEvent(const Event* event)
1343{
1344    for (const Event* e = event; e; e = e->underlyingEvent())
1345        if (e->isMouseEvent())
1346            return static_cast<const MouseEvent*>(e);
1347    return 0;
1348}
1349
1350NSDictionary *WebFrameLoaderClient::actionDictionary(const NavigationAction& action, PassRefPtr<FormState> formState) const
1351{
1352    unsigned modifierFlags = 0;
1353    const Event* event = action.event();
1354    if (const UIEventWithKeyState* keyStateEvent = findEventWithKeyState(const_cast<Event*>(event))) {
1355        if (keyStateEvent->ctrlKey())
1356            modifierFlags |= NSControlKeyMask;
1357        if (keyStateEvent->altKey())
1358            modifierFlags |= NSAlternateKeyMask;
1359        if (keyStateEvent->shiftKey())
1360            modifierFlags |= NSShiftKeyMask;
1361        if (keyStateEvent->metaKey())
1362            modifierFlags |= NSCommandKeyMask;
1363    }
1364
1365    NSURL *originalURL = action.url();
1366
1367    NSMutableDictionary *result = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1368        [NSNumber numberWithInt:action.type()], WebActionNavigationTypeKey,
1369        [NSNumber numberWithInt:modifierFlags], WebActionModifierFlagsKey,
1370        originalURL, WebActionOriginalURLKey,
1371        nil];
1372
1373    if (const MouseEvent* mouseEvent = findMouseEvent(event)) {
1374        WebElementDictionary *element = [[WebElementDictionary alloc]
1375            initWithHitTestResult:core(m_webFrame.get())->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation())];
1376        [result setObject:element forKey:WebActionElementKey];
1377        [element release];
1378
1379        [result setObject:[NSNumber numberWithInt:mouseEvent->button()] forKey:WebActionButtonKey];
1380    }
1381
1382    if (formState) {
1383        ASSERT(formState->form());
1384        [result setObject:kit(formState->form()) forKey:WebActionFormKey];
1385    }
1386
1387    return result;
1388}
1389
1390bool WebFrameLoaderClient::canCachePage() const
1391{
1392    // We can only cache HTML pages right now
1393    return [[[m_webFrame.get() _dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]];
1394}
1395
1396PassRefPtr<Frame> WebFrameLoaderClient::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
1397    const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
1398{
1399    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1400
1401    ASSERT(m_webFrame);
1402
1403    WebFrameView *childView = [[WebFrameView alloc] init];
1404
1405    RefPtr<Frame> result = [WebFrame _createSubframeWithOwnerElement:ownerElement frameName:name frameView:childView];
1406    [childView release];
1407
1408    WebFrame *newFrame = kit(result.get());
1409
1410    if ([newFrame _dataSource])
1411        [[newFrame _dataSource] _documentLoader]->setOverrideEncoding([[m_webFrame.get() _dataSource] _documentLoader]->overrideEncoding());
1412
1413    // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
1414    if (!result->page())
1415        return 0;
1416
1417    core(m_webFrame.get())->loader()->loadURLIntoChildFrame(url, referrer, result.get());
1418
1419    // The frame's onload handler may have removed it from the document.
1420    if (!result->tree()->parent())
1421        return 0;
1422
1423    return result.release();
1424
1425    END_BLOCK_OBJC_EXCEPTIONS;
1426
1427    return 0;
1428}
1429
1430ObjectContentType WebFrameLoaderClient::objectContentType(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages)
1431{
1432    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1433
1434    String type = mimeType;
1435
1436    if (type.isEmpty()) {
1437        // Try to guess the MIME type based off the extension.
1438        NSURL *URL = url;
1439        NSString *extension = [[URL path] pathExtension];
1440        if ([extension length] > 0) {
1441            type = WKGetMIMETypeForExtension(extension);
1442            if (type.isEmpty()) {
1443                // If no MIME type is specified, use a plug-in if we have one that can handle the extension.
1444                if (WebBasePluginPackage *package = [getWebView(m_webFrame.get()) _pluginForExtension:extension]) {
1445                    if ([package isKindOfClass:[WebPluginPackage class]])
1446                        return ObjectContentOtherPlugin;
1447#if ENABLE(NETSCAPE_PLUGIN_API)
1448                    else {
1449                        ASSERT([package isKindOfClass:[WebNetscapePluginPackage class]]);
1450                        return ObjectContentNetscapePlugin;
1451                    }
1452#endif
1453                }
1454            }
1455        }
1456    }
1457
1458    if (type.isEmpty())
1459        return ObjectContentFrame; // Go ahead and hope that we can display the content.
1460
1461    WebBasePluginPackage *package = [getWebView(m_webFrame.get()) _pluginForMIMEType:type];
1462    ObjectContentType plugInType = ObjectContentNone;
1463    if (package) {
1464#if ENABLE(NETSCAPE_PLUGIN_API)
1465        if ([package isKindOfClass:[WebNetscapePluginPackage class]])
1466            plugInType = ObjectContentNetscapePlugin;
1467        else
1468#endif
1469        {
1470            ASSERT([package isKindOfClass:[WebPluginPackage class]]);
1471            plugInType = ObjectContentOtherPlugin;
1472        }
1473    }
1474
1475    if (MIMETypeRegistry::isSupportedImageMIMEType(type))
1476        return shouldPreferPlugInsForImages && plugInType != ObjectContentNone ? plugInType : ObjectContentImage;
1477
1478    if (plugInType != ObjectContentNone)
1479        return plugInType;
1480
1481    if ([m_webFrame->_private->webFrameView _viewClassForMIMEType:type])
1482        return ObjectContentFrame;
1483
1484    return ObjectContentNone;
1485
1486    END_BLOCK_OBJC_EXCEPTIONS;
1487
1488    return ObjectContentNone;
1489}
1490
1491static NSMutableArray* kit(const Vector<String>& vector)
1492{
1493    unsigned len = vector.size();
1494    NSMutableArray* array = [NSMutableArray arrayWithCapacity:len];
1495    for (unsigned x = 0; x < len; x++)
1496        [array addObject:vector[x]];
1497    return array;
1498}
1499
1500static String parameterValue(const Vector<String>& paramNames, const Vector<String>& paramValues, const String& name)
1501{
1502    size_t size = paramNames.size();
1503    ASSERT(size == paramValues.size());
1504    for (size_t i = 0; i < size; ++i) {
1505        if (equalIgnoringCase(paramNames[i], name))
1506            return paramValues[i];
1507    }
1508    return String();
1509}
1510
1511static NSView *pluginView(WebFrame *frame, WebPluginPackage *pluginPackage,
1512    NSArray *attributeNames, NSArray *attributeValues, NSURL *baseURL,
1513    DOMElement *element, BOOL loadManually)
1514{
1515    WebHTMLView *docView = (WebHTMLView *)[[frame frameView] documentView];
1516    ASSERT([docView isKindOfClass:[WebHTMLView class]]);
1517
1518    WebPluginController *pluginController = [docView _pluginController];
1519
1520    // Store attributes in a dictionary so they can be passed to WebPlugins.
1521    NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:attributeValues forKeys:attributeNames];
1522
1523    [pluginPackage load];
1524    Class viewFactory = [pluginPackage viewFactory];
1525
1526    NSView *view = nil;
1527    NSDictionary *arguments = nil;
1528
1529    if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) {
1530        arguments = [NSDictionary dictionaryWithObjectsAndKeys:
1531            baseURL, WebPlugInBaseURLKey,
1532            attributes, WebPlugInAttributesKey,
1533            pluginController, WebPlugInContainerKey,
1534            [NSNumber numberWithInt:loadManually ? WebPlugInModeFull : WebPlugInModeEmbed], WebPlugInModeKey,
1535            [NSNumber numberWithBool:!loadManually], WebPlugInShouldLoadMainResourceKey,
1536            element, WebPlugInContainingElementKey,
1537            nil];
1538        LOG(Plugins, "arguments:\n%@", arguments);
1539    } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) {
1540        arguments = [NSDictionary dictionaryWithObjectsAndKeys:
1541            baseURL, WebPluginBaseURLKey,
1542            attributes, WebPluginAttributesKey,
1543            pluginController, WebPluginContainerKey,
1544            element, WebPlugInContainingElementKey,
1545            nil];
1546        LOG(Plugins, "arguments:\n%@", arguments);
1547    }
1548
1549    view = [WebPluginController plugInViewWithArguments:arguments fromPluginPackage:pluginPackage];
1550    [attributes release];
1551    return view;
1552}
1553
1554class PluginWidget : public PluginViewBase {
1555public:
1556    PluginWidget(NSView *view = 0)
1557        : PluginViewBase(view)
1558    {
1559    }
1560
1561private:
1562    virtual void invalidateRect(const IntRect& rect)
1563    {
1564        [platformWidget() setNeedsDisplayInRect:rect];
1565    }
1566};
1567
1568#if ENABLE(NETSCAPE_PLUGIN_API)
1569
1570class NetscapePluginWidget : public PluginWidget {
1571public:
1572    NetscapePluginWidget(WebBaseNetscapePluginView *view)
1573        : PluginWidget(view)
1574    {
1575    }
1576
1577#if USE(ACCELERATED_COMPOSITING)
1578    virtual PlatformLayer* platformLayer() const
1579    {
1580        return [(WebBaseNetscapePluginView *)platformWidget() pluginLayer];
1581    }
1582#endif
1583
1584    virtual bool getFormValue(String& value)
1585    {
1586        NSString* nsValue = 0;
1587        if ([(WebBaseNetscapePluginView *)platformWidget() getFormValue:&nsValue]) {
1588            if (!nsValue)
1589                return false;
1590            value = String(nsValue);
1591            [nsValue release];
1592            return true;
1593        }
1594        return false;
1595    }
1596
1597    virtual void handleEvent(Event* event)
1598    {
1599        Frame* frame = Frame::frameForWidget(this);
1600        if (!frame)
1601            return;
1602
1603        NSEvent* currentNSEvent = frame->eventHandler()->currentNSEvent();
1604        if (event->type() == eventNames().mousemoveEvent)
1605            [(WebBaseNetscapePluginView *)platformWidget() handleMouseMoved:currentNSEvent];
1606        else if (event->type() == eventNames().mouseoverEvent)
1607            [(WebBaseNetscapePluginView *)platformWidget() handleMouseEntered:currentNSEvent];
1608        else if (event->type() == eventNames().mouseoutEvent)
1609            [(WebBaseNetscapePluginView *)platformWidget() handleMouseExited:currentNSEvent];
1610        else if (event->type() == eventNames().contextmenuEvent)
1611            event->setDefaultHandled(); // We don't know if the plug-in has handled mousedown event by displaying a context menu, so we never want WebKit to show a default one.
1612    }
1613
1614    virtual void clipRectChanged()
1615    {
1616        // Changing the clip rect doesn't affect the view hierarchy, so the plugin must be told about the change directly.
1617        [(WebBaseNetscapePluginView *)platformWidget() updateAndSetWindow];
1618    }
1619
1620private:
1621    virtual void notifyWidget(WidgetNotification notification)
1622    {
1623        switch (notification) {
1624        case WillPaintFlattened: {
1625            BEGIN_BLOCK_OBJC_EXCEPTIONS;
1626            [(WebBaseNetscapePluginView *)platformWidget() cacheSnapshot];
1627            END_BLOCK_OBJC_EXCEPTIONS;
1628            break;
1629        }
1630        case DidPaintFlattened: {
1631            BEGIN_BLOCK_OBJC_EXCEPTIONS;
1632            [(WebBaseNetscapePluginView *)platformWidget() clearCachedSnapshot];
1633            END_BLOCK_OBJC_EXCEPTIONS;
1634            break;
1635        }
1636        }
1637    }
1638};
1639
1640#if USE(PLUGIN_HOST_PROCESS)
1641#define NETSCAPE_PLUGIN_VIEW WebHostedNetscapePluginView
1642#else
1643#define NETSCAPE_PLUGIN_VIEW WebNetscapePluginView
1644#endif
1645
1646#endif // ENABLE(NETSCAPE_PLUGIN_API)
1647
1648PassRefPtr<Widget> WebFrameLoaderClient::createPlugin(const IntSize& size, HTMLPlugInElement* element, const KURL& url,
1649    const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
1650{
1651    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1652
1653    ASSERT(paramNames.size() == paramValues.size());
1654
1655    int errorCode = 0;
1656
1657    WebView *webView = getWebView(m_webFrame.get());
1658    SEL selector = @selector(webView:plugInViewWithArguments:);
1659
1660    Document* document = core(m_webFrame.get())->document();
1661    NSURL *baseURL = document->baseURL();
1662    NSURL *pluginURL = url;
1663
1664    // <rdar://problem/8366089>: AppleConnect has a bug where it does not
1665    // understand the parameter names specified in the <object> element that
1666    // embeds its plug-in. This site-specific hack works around the issue by
1667    // converting the parameter names to lowercase before passing them to the
1668    // plug-in.
1669    Frame* frame = core(m_webFrame.get());
1670    NSMutableArray *attributeKeys = kit(paramNames);
1671    if (frame && frame->settings()->needsSiteSpecificQuirks() && equalIgnoringCase(mimeType, "application/x-snkp")) {
1672        for (NSUInteger i = 0; i < [attributeKeys count]; ++i)
1673            [attributeKeys replaceObjectAtIndex:i withObject:[[attributeKeys objectAtIndex:i] lowercaseString]];
1674    }
1675
1676    if ([[webView UIDelegate] respondsToSelector:selector]) {
1677        NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:kit(paramValues) forKeys:attributeKeys];
1678        NSDictionary *arguments = [[NSDictionary alloc] initWithObjectsAndKeys:
1679            attributes, WebPlugInAttributesKey,
1680            [NSNumber numberWithInt:loadManually ? WebPlugInModeFull : WebPlugInModeEmbed], WebPlugInModeKey,
1681            [NSNumber numberWithBool:!loadManually], WebPlugInShouldLoadMainResourceKey,
1682            kit(element), WebPlugInContainingElementKey,
1683            // FIXME: We should be passing base URL, see <https://bugs.webkit.org/show_bug.cgi?id=35215>.
1684            pluginURL, WebPlugInBaseURLKey, // pluginURL might be nil, so add it last
1685            nil];
1686
1687        NSView *view = CallUIDelegate(webView, selector, arguments);
1688
1689        [attributes release];
1690        [arguments release];
1691
1692        if (view)
1693            return adoptRef(new PluginWidget(view));
1694    }
1695
1696    NSString *MIMEType;
1697    WebBasePluginPackage *pluginPackage;
1698    if (mimeType.isEmpty()) {
1699        MIMEType = nil;
1700        pluginPackage = nil;
1701    } else {
1702        MIMEType = mimeType;
1703        pluginPackage = [webView _pluginForMIMEType:mimeType];
1704    }
1705
1706    NSString *extension = [[pluginURL path] pathExtension];
1707    if (!pluginPackage && [extension length] && ![MIMEType length]) {
1708        pluginPackage = [webView _pluginForExtension:extension];
1709        if (pluginPackage) {
1710            NSString *newMIMEType = [pluginPackage MIMETypeForExtension:extension];
1711            if ([newMIMEType length] != 0)
1712                MIMEType = newMIMEType;
1713        }
1714    }
1715
1716    NSView *view = nil;
1717
1718    if (pluginPackage) {
1719        if (WKShouldBlockPlugin([pluginPackage bundleIdentifier], [pluginPackage bundleVersion])) {
1720            errorCode = WebKitErrorBlockedPlugInVersion;
1721            if (element->renderer()->isEmbeddedObject())
1722                toRenderEmbeddedObject(element->renderer())->setPluginUnavailabilityReason(RenderEmbeddedObject::InsecurePluginVersion);
1723        } else {
1724            if ([pluginPackage isKindOfClass:[WebPluginPackage class]])
1725                view = pluginView(m_webFrame.get(), (WebPluginPackage *)pluginPackage, attributeKeys, kit(paramValues), baseURL, kit(element), loadManually);
1726
1727#if ENABLE(NETSCAPE_PLUGIN_API)
1728            else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) {
1729                WebBaseNetscapePluginView *pluginView = [[[NETSCAPE_PLUGIN_VIEW alloc]
1730                    initWithFrame:NSMakeRect(0, 0, size.width(), size.height())
1731                    pluginPackage:(WebNetscapePluginPackage *)pluginPackage
1732                    URL:pluginURL
1733                    baseURL:baseURL
1734                    MIMEType:MIMEType
1735                    attributeKeys:attributeKeys
1736                    attributeValues:kit(paramValues)
1737                    loadManually:loadManually
1738                    element:element] autorelease];
1739
1740                return adoptRef(new NetscapePluginWidget(pluginView));
1741            }
1742#endif
1743        }
1744    } else
1745        errorCode = WebKitErrorCannotFindPlugIn;
1746
1747    if (!errorCode && !view)
1748        errorCode = WebKitErrorCannotLoadPlugIn;
1749
1750    if (errorCode && m_webFrame) {
1751        WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
1752        if (implementations->plugInFailedWithErrorFunc) {
1753            KURL pluginPageURL = document->completeURL(stripLeadingAndTrailingHTMLSpaces(parameterValue(paramNames, paramValues, "pluginspage")));
1754            if (!pluginPageURL.protocolIsInHTTPFamily())
1755                pluginPageURL = KURL();
1756            NSString *pluginName = pluginPackage ? (NSString *)[pluginPackage pluginInfo].name : nil;
1757
1758            NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode
1759                                                            contentURL:pluginURL pluginPageURL:pluginPageURL pluginName:pluginName MIMEType:MIMEType];
1760            CallResourceLoadDelegate(implementations->plugInFailedWithErrorFunc, [m_webFrame.get() webView],
1761                                     @selector(webView:plugInFailedWithError:dataSource:), error, [m_webFrame.get() _dataSource]);
1762            [error release];
1763        }
1764
1765        return 0;
1766    }
1767
1768    ASSERT(view);
1769    return adoptRef(new PluginWidget(view));
1770
1771    END_BLOCK_OBJC_EXCEPTIONS;
1772
1773    return 0;
1774}
1775
1776void WebFrameLoaderClient::recreatePlugin(Widget*)
1777{
1778}
1779
1780void WebFrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget)
1781{
1782    if (!pluginWidget)
1783        return;
1784
1785    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1786
1787    WebHTMLRepresentation *representation = (WebHTMLRepresentation *)[[m_webFrame.get() _dataSource] representation];
1788
1789    NSView *pluginView = pluginWidget->platformWidget();
1790
1791#if ENABLE(NETSCAPE_PLUGIN_API)
1792    if ([pluginView isKindOfClass:[NETSCAPE_PLUGIN_VIEW class]])
1793        [representation _redirectDataToManualLoader:(NETSCAPE_PLUGIN_VIEW *)pluginView forPluginView:pluginView];
1794    else {
1795#else
1796    {
1797#endif
1798        WebHTMLView *documentView = (WebHTMLView *)[[m_webFrame.get() frameView] documentView];
1799        ASSERT([documentView isKindOfClass:[WebHTMLView class]]);
1800        [representation _redirectDataToManualLoader:[documentView _pluginController] forPluginView:pluginView];
1801    }
1802
1803    END_BLOCK_OBJC_EXCEPTIONS;
1804}
1805
1806PassRefPtr<Widget> WebFrameLoaderClient::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const KURL& baseURL,
1807    const Vector<String>& paramNames, const Vector<String>& paramValues)
1808{
1809    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1810
1811    NSView *view = nil;
1812
1813    NSString *MIMEType = @"application/x-java-applet";
1814
1815    WebView *webView = getWebView(m_webFrame.get());
1816
1817    WebBasePluginPackage *pluginPackage = [webView _pluginForMIMEType:MIMEType];
1818
1819    int errorCode = WebKitErrorJavaUnavailable;
1820
1821    if (pluginPackage) {
1822        if (WKShouldBlockPlugin([pluginPackage bundleIdentifier], [pluginPackage bundleVersion])) {
1823            errorCode = WebKitErrorBlockedPlugInVersion;
1824            if (element->renderer()->isEmbeddedObject())
1825                toRenderEmbeddedObject(element->renderer())->setPluginUnavailabilityReason(RenderEmbeddedObject::InsecurePluginVersion);
1826        } else {
1827    #if ENABLE(NETSCAPE_PLUGIN_API)
1828            if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) {
1829                view = [[[NETSCAPE_PLUGIN_VIEW alloc] initWithFrame:NSMakeRect(0, 0, size.width(), size.height())
1830                    pluginPackage:(WebNetscapePluginPackage *)pluginPackage
1831                    URL:nil
1832                    baseURL:baseURL
1833                    MIMEType:MIMEType
1834                    attributeKeys:kit(paramNames)
1835                    attributeValues:kit(paramValues)
1836                    loadManually:NO
1837                    element:element] autorelease];
1838                if (view)
1839                    return adoptRef(new NetscapePluginWidget(static_cast<WebBaseNetscapePluginView *>(view)));
1840            }
1841    #endif
1842        }
1843    }
1844
1845    if (!view) {
1846        WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(getWebView(m_webFrame.get()));
1847        if (implementations->plugInFailedWithErrorFunc) {
1848            NSString *pluginName = pluginPackage ? (NSString *)[pluginPackage pluginInfo].name : nil;
1849            NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode contentURL:nil pluginPageURL:nil pluginName:pluginName MIMEType:MIMEType];
1850            CallResourceLoadDelegate(implementations->plugInFailedWithErrorFunc, [m_webFrame.get() webView],
1851                                     @selector(webView:plugInFailedWithError:dataSource:), error, [m_webFrame.get() _dataSource]);
1852            [error release];
1853        }
1854    }
1855
1856    END_BLOCK_OBJC_EXCEPTIONS;
1857
1858    return 0;
1859}
1860
1861#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1862PassRefPtr<Widget> WebFrameLoaderClient::createMediaPlayerProxyPlugin(const IntSize& size, HTMLMediaElement* element, const KURL& url,
1863    const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType)
1864{
1865    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1866
1867    ASSERT(paramNames.size() == paramValues.size());
1868    ASSERT(mimeType);
1869
1870    int errorCode = 0;
1871    WebView *webView = getWebView(m_webFrame.get());
1872    NSURL *URL = url;
1873
1874    SEL selector = @selector(webView:plugInViewWithArguments:);
1875
1876    if ([[webView UIDelegate] respondsToSelector:selector]) {
1877        NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:kit(paramValues) forKeys:kit(paramNames)];
1878        NSDictionary *arguments = [[NSDictionary alloc] initWithObjectsAndKeys:
1879            attributes, WebPlugInAttributesKey,
1880            [NSNumber numberWithInt:WebPlugInModeEmbed], WebPlugInModeKey,
1881            [NSNumber numberWithBool:YES], WebPlugInShouldLoadMainResourceKey,
1882            kit(element), WebPlugInContainingElementKey,
1883            URL, WebPlugInBaseURLKey, // URL might be nil, so add it last
1884            nil];
1885
1886        NSView *view = CallUIDelegate(webView, selector, arguments);
1887
1888        [attributes release];
1889        [arguments release];
1890
1891        if (view)
1892            return adoptRef(new PluginWidget(view));
1893    }
1894
1895    WebBasePluginPackage *pluginPackage = [webView _videoProxyPluginForMIMEType:mimeType];
1896    Document* document = core(m_webFrame.get())->document();
1897    NSURL *baseURL = document->baseURL();
1898    NSView *view = nil;
1899
1900    if (pluginPackage) {
1901        if ([pluginPackage isKindOfClass:[WebPluginPackage class]])
1902            view = pluginView(m_webFrame.get(), (WebPluginPackage *)pluginPackage, kit(paramNames), kit(paramValues), baseURL, kit(element), false);
1903    } else
1904        errorCode = WebKitErrorCannotFindPlugIn;
1905
1906    if (!errorCode && !view)
1907        errorCode = WebKitErrorCannotLoadPlugIn;
1908
1909    if (errorCode) {
1910        NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode
1911            contentURL:URL pluginPageURL:nil pluginName:[pluginPackage pluginInfo].name MIMEType:mimeType];
1912        WebNullPluginView *nullView = [[[WebNullPluginView alloc] initWithFrame:NSMakeRect(0, 0, size.width(), size.height())
1913            error:error DOMElement:kit(element)] autorelease];
1914        view = nullView;
1915        [error release];
1916    }
1917
1918    ASSERT(view);
1919    return adoptRef(new PluginWidget(view));
1920
1921    END_BLOCK_OBJC_EXCEPTIONS;
1922
1923    return 0;
1924}
1925
1926void WebFrameLoaderClient::hideMediaPlayerProxyPlugin(Widget* widget)
1927{
1928    [WebPluginController pluginViewHidden:widget->platformWidget()];
1929}
1930
1931void WebFrameLoaderClient::showMediaPlayerProxyPlugin(Widget* widget)
1932{
1933    [WebPluginController addPlugInView:widget->platformWidget()];
1934}
1935
1936#endif  // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1937
1938String WebFrameLoaderClient::overrideMediaType() const
1939{
1940    NSString* overrideType = [getWebView(m_webFrame.get()) mediaStyle];
1941    if (overrideType)
1942        return overrideType;
1943    return String();
1944}
1945
1946void WebFrameLoaderClient::documentElementAvailable() {
1947}
1948
1949void WebFrameLoaderClient::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
1950{
1951    WebView *webView = getWebView(m_webFrame.get());
1952    WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
1953
1954    if (implementations->didClearWindowObjectForFrameInScriptWorldFunc) {
1955        CallFrameLoadDelegate(implementations->didClearWindowObjectForFrameInScriptWorldFunc,
1956            webView, @selector(webView:didClearWindowObjectForFrame:inScriptWorld:), m_webFrame.get(), [WebScriptWorld findOrCreateWorld:world]);
1957        return;
1958    }
1959
1960    if (world != mainThreadNormalWorld())
1961        return;
1962
1963    Frame *frame = core(m_webFrame.get());
1964    ScriptController *script = frame->script();
1965
1966#if JSC_OBJC_API_ENABLED
1967    if (implementations->didCreateJavaScriptContextForFrameFunc) {
1968        CallFrameLoadDelegate(implementations->didCreateJavaScriptContextForFrameFunc, webView, @selector(webView:didCreateJavaScriptContext:forFrame:),
1969            script->javaScriptContext(), m_webFrame.get());
1970    } else if (implementations->didClearWindowObjectForFrameFunc) {
1971#else
1972    if (implementations->didClearWindowObjectForFrameFunc) {
1973#endif
1974        CallFrameLoadDelegate(implementations->didClearWindowObjectForFrameFunc, webView, @selector(webView:didClearWindowObject:forFrame:),
1975            script->windowScriptObject(), m_webFrame.get());
1976    } else if (implementations->windowScriptObjectAvailableFunc) {
1977        CallFrameLoadDelegate(implementations->windowScriptObjectAvailableFunc, webView, @selector(webView:windowScriptObjectAvailable:),
1978            script->windowScriptObject());
1979    }
1980
1981    if ([webView scriptDebugDelegate]) {
1982        [m_webFrame.get() _detachScriptDebugger];
1983        [m_webFrame.get() _attachScriptDebugger];
1984    }
1985}
1986
1987void WebFrameLoaderClient::registerForIconNotification(bool listen)
1988{
1989#if ENABLE(ICONDATABASE)
1990    [[m_webFrame.get() webView] _registerForIconNotification:listen];
1991#endif
1992}
1993
1994void WebFrameLoaderClient::didPerformFirstNavigation() const
1995{
1996    WebPreferences *preferences = [[m_webFrame.get() webView] preferences];
1997    if ([preferences automaticallyDetectsCacheModel] && [preferences cacheModel] < WebCacheModelDocumentBrowser)
1998        [preferences setCacheModel:WebCacheModelDocumentBrowser];
1999}
2000
2001PassRefPtr<FrameNetworkingContext> WebFrameLoaderClient::createNetworkingContext()
2002{
2003    return WebFrameNetworkingContext::create(core(m_webFrame.get()));
2004}
2005
2006@implementation WebFramePolicyListener
2007
2008+ (void)initialize
2009{
2010    JSC::initializeThreading();
2011    WTF::initializeMainThreadToProcessMainThread();
2012    WebCore::RunLoop::initializeMainRunLoop();
2013    WebCoreObjCFinalizeOnMainThread(self);
2014}
2015
2016- (id)initWithFrame:(Frame*)frame policyFunction:(FramePolicyFunction)policyFunction
2017{
2018    self = [self init];
2019    if (!self)
2020        return nil;
2021
2022    _frame = frame;
2023    _policyFunction = policyFunction;
2024
2025    return self;
2026}
2027
2028- (void)invalidate
2029{
2030    _frame = nullptr;
2031}
2032
2033- (void)dealloc
2034{
2035    if (WebCoreObjCScheduleDeallocateOnMainThread([WebFramePolicyListener class], self))
2036        return;
2037
2038    [super dealloc];
2039}
2040
2041- (void)receivedPolicyDecision:(PolicyAction)action
2042{
2043    RefPtr<Frame> frame = _frame.release();
2044    if (!frame)
2045        return;
2046
2047    FramePolicyFunction policyFunction = _policyFunction;
2048    _policyFunction = nullptr;
2049
2050    ASSERT(policyFunction);
2051    (frame->loader()->policyChecker()->*policyFunction)(action);
2052}
2053
2054- (void)ignore
2055{
2056    [self receivedPolicyDecision:PolicyIgnore];
2057}
2058
2059- (void)download
2060{
2061    [self receivedPolicyDecision:PolicyDownload];
2062}
2063
2064- (void)use
2065{
2066    [self receivedPolicyDecision:PolicyUse];
2067}
2068
2069- (void)continue
2070{
2071    [self receivedPolicyDecision:PolicyUse];
2072}
2073
2074@end
2075