Use createCFURLFromBuffer when converting a String to a CFURL
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / mac / WKBrowsingContextController.mm
1 /*
2  * Copyright (C) 2011 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WKBrowsingContextControllerInternal.h"
28
29 #import "ObjCObjectGraph.h"
30 #import "WKBackForwardListInternal.h"
31 #import "WKBackForwardListItemInternal.h"
32 #import "WKErrorCF.h"
33 #import "WKFrame.h"
34 #import "WKFramePolicyListener.h"
35 #import "WKNSArray.h"
36 #import "WKNSURLExtras.h"
37 #import "WKPagePrivate.h"
38 #import "WKRetainPtr.h"
39 #import "WKStringCF.h"
40 #import "WKURLCF.h"
41 #import "WKURLRequest.h"
42 #import "WKURLRequestNS.h"
43 #import "WKURLResponse.h"
44 #import "WKURLResponseNS.h"
45 #import "WebContext.h"
46 #import "WebData.h"
47 #import "WebPageProxy.h"
48 #import <wtf/ObjcRuntimeExtras.h>
49 #import <wtf/RetainPtr.h>
50
51 #import "WKBrowsingContextHandleInternal.h"
52 #import "WKBrowsingContextLoadDelegate.h"
53 #import "WKBrowsingContextPolicyDelegate.h"
54
55 using namespace WebKit;
56
57 static inline NSString *autoreleased(WKStringRef string)
58 {
59     return string ? CFBridgingRelease(WKStringCopyCFString(kCFAllocatorDefault, adoptWK(string).get())) : nil;
60 }
61
62 static inline NSURL *autoreleased(WKURLRef url)
63 {
64     return url ? CFBridgingRelease(WKURLCopyCFURL(kCFAllocatorDefault, adoptWK(url).get())) : nil;
65 }
66
67 static inline NSURLRequest *autoreleased(WKURLRequestRef urlRequest)
68 {
69     return urlRequest ? CFBridgingRelease(WKURLRequestCopyNSURLRequest(adoptWK(urlRequest).get())) : nil;
70 }
71
72 static inline NSURLResponse *autoreleased(WKURLResponseRef urlResponse)
73 {
74     return urlResponse ? CFBridgingRelease(WKURLResponseCopyNSURLResponse(adoptWK(urlResponse).get())) : nil;
75 }
76
77 NSString *WKActionIsMainFrameKey = @"WKActionIsMainFrameKey";
78 NSString *WKActionNavigationTypeKey = @"WKActionNavigationTypeKey";
79 NSString *WKActionMouseButtonKey = @"WKActionMouseButtonKey";
80 NSString *WKActionModifierFlagsKey = @"WKActionModifierFlagsKey";
81 NSString *WKActionURLRequestKey = @"WKActionURLRequestKey";
82 NSString *WKActionURLResponseKey = @"WKActionURLResponseKey";
83 NSString *WKActionFrameNameKey = @"WKActionFrameNameKey";
84
85 @interface WKBrowsingContextControllerData : NSObject {
86 @public
87     // Underlying WKPageRef.
88     WKRetainPtr<WKPageRef> _pageRef;
89     
90     // Delegate for load callbacks.
91     id<WKBrowsingContextLoadDelegate> _loadDelegate;
92
93 #if WK_API_ENABLED
94     // Delegate for policy callbacks.
95     id<WKBrowsingContextPolicyDelegate> _policyDelegate;
96 #endif
97 }
98 @end
99
100 @implementation WKBrowsingContextControllerData
101 @end
102
103
104 @implementation WKBrowsingContextController
105
106 - (void)dealloc
107 {
108     WKPageSetPageLoaderClient(_data->_pageRef.get(), nullptr);
109
110 #if WK_API_ENABLED
111     WKPageSetPagePolicyClient(_data->_pageRef.get(), nullptr);
112 #endif
113
114     [_data release];
115     [super dealloc];
116 }
117
118 - (WKPageRef)_pageRef
119 {
120     return _data->_pageRef.get();
121 }
122
123 #pragma mark Delegates
124
125 - (id<WKBrowsingContextLoadDelegate>)loadDelegate
126 {
127     return _data->_loadDelegate;
128 }
129
130 - (void)setLoadDelegate:(id<WKBrowsingContextLoadDelegate>)loadDelegate
131 {
132     _data->_loadDelegate = loadDelegate;
133 }
134
135 #if WK_API_ENABLED
136 - (id<WKBrowsingContextPolicyDelegate>)policyDelegate
137 {
138     return _data->_policyDelegate;
139 }
140
141 - (void)setPolicyDelegate:(id<WKBrowsingContextPolicyDelegate>)policyDelegate
142 {
143     _data->_policyDelegate = policyDelegate;
144 }
145 #endif
146
147 #pragma mark Loading
148
149 + (void)registerSchemeForCustomProtocol:(NSString *)scheme
150 {
151     if (!scheme)
152         return;
153
154     NSString *lowercaseScheme = [scheme lowercaseString];
155     [[WKBrowsingContextController customSchemes] addObject:lowercaseScheme];
156     [[NSNotificationCenter defaultCenter] postNotificationName:SchemeForCustomProtocolRegisteredNotificationName object:lowercaseScheme];
157 }
158
159 + (void)unregisterSchemeForCustomProtocol:(NSString *)scheme
160 {
161     if (!scheme)
162         return;
163
164     NSString *lowercaseScheme = [scheme lowercaseString];
165     [[WKBrowsingContextController customSchemes] removeObject:lowercaseScheme];
166     [[NSNotificationCenter defaultCenter] postNotificationName:SchemeForCustomProtocolUnregisteredNotificationName object:lowercaseScheme];
167 }
168
169 - (void)loadRequest:(NSURLRequest *)request
170 {
171     [self loadRequest:request userData:nil];
172 }
173
174 - (void)loadRequest:(NSURLRequest *)request userData:(id)userData
175 {
176     WKRetainPtr<WKURLRequestRef> wkRequest = adoptWK(WKURLRequestCreateWithNSURLRequest(request));
177
178     RefPtr<ObjCObjectGraph> wkUserData;
179     if (userData)
180         wkUserData = ObjCObjectGraph::create(userData);
181
182     WKPageLoadURLRequestWithUserData(self._pageRef, wkRequest.get(), (WKTypeRef)wkUserData.get());
183 }
184
185 - (void)loadFileURL:(NSURL *)URL restrictToFilesWithin:(NSURL *)allowedDirectory
186 {
187     [self loadFileURL:URL restrictToFilesWithin:allowedDirectory userData:nil];
188 }
189
190 - (void)loadFileURL:(NSURL *)URL restrictToFilesWithin:(NSURL *)allowedDirectory userData:(id)userData
191 {
192     if (![URL isFileURL] || (allowedDirectory && ![allowedDirectory isFileURL]))
193         [NSException raise:NSInvalidArgumentException format:@"Attempted to load a non-file URL"];
194
195     WKRetainPtr<WKURLRef> wkURL = adoptWK(WKURLCreateWithCFURL((CFURLRef)URL));
196     WKRetainPtr<WKURLRef> wkAllowedDirectory = adoptWK(WKURLCreateWithCFURL((CFURLRef)allowedDirectory));
197     
198     RefPtr<ObjCObjectGraph> wkUserData;
199     if (userData)
200         wkUserData = ObjCObjectGraph::create(userData);
201
202     WKPageLoadFileWithUserData(self._pageRef, wkURL.get(), wkAllowedDirectory.get(), (WKTypeRef)wkUserData.get());
203 }
204
205 - (void)loadHTMLString:(NSString *)HTMLString baseURL:(NSURL *)baseURL
206 {
207     [self loadHTMLString:HTMLString baseURL:baseURL userData:nil];
208 }
209
210 - (void)loadHTMLString:(NSString *)HTMLString baseURL:(NSURL *)baseURL userData:(id)userData
211 {
212     WKRetainPtr<WKStringRef> wkHTMLString;
213     if (HTMLString)
214         wkHTMLString = adoptWK(WKStringCreateWithCFString((CFStringRef)HTMLString));
215
216     WKRetainPtr<WKURLRef> wkBaseURL;
217     if (baseURL)
218         wkBaseURL = adoptWK(WKURLCreateWithCFURL((CFURLRef)baseURL));
219
220     RefPtr<ObjCObjectGraph> wkUserData;
221     if (userData)
222         wkUserData = ObjCObjectGraph::create(userData);
223
224     WKPageLoadHTMLStringWithUserData(self._pageRef, wkHTMLString.get(), wkBaseURL.get(), (WKTypeRef)wkUserData.get());
225 }
226
227 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
228 {
229     [self loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL userData:nil];
230 }
231
232 static void releaseNSData(unsigned char*, const void* data)
233 {
234     [(NSData *)data release];
235 }
236
237 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL userData:(id)userData
238 {
239     RefPtr<WebData> wkData;
240     if (data) {
241         [data retain];
242         wkData = WebData::createWithoutCopying((const unsigned char*)[data bytes], [data length], releaseNSData, data);
243     }
244
245     WKRetainPtr<WKStringRef> wkMIMEType;
246     if (MIMEType)
247         wkMIMEType = adoptWK(WKStringCreateWithCFString((CFStringRef)MIMEType));
248
249     WKRetainPtr<WKStringRef> wkEncodingName;
250     if (encodingName)
251         wkEncodingName = adoptWK(WKStringCreateWithCFString((CFStringRef)encodingName));
252
253     WKRetainPtr<WKURLRef> wkBaseURL;
254     if (baseURL)
255         wkBaseURL = adoptWK(WKURLCreateWithCFURL((CFURLRef)baseURL));
256
257     RefPtr<ObjCObjectGraph> wkUserData;
258     if (userData)
259         wkUserData = ObjCObjectGraph::create(userData);
260
261     WKPageLoadDataWithUserData(self._pageRef, toAPI(wkData.get()), wkMIMEType.get(), wkEncodingName.get(), wkBaseURL.get(), (WKTypeRef)wkUserData.get());
262 }
263
264 - (void)stopLoading
265 {
266     WKPageStopLoading(self._pageRef);
267 }
268
269 - (void)reload
270 {
271     WKPageReload(self._pageRef);
272 }
273
274 - (void)reloadFromOrigin
275 {
276     WKPageReloadFromOrigin(self._pageRef);
277 }
278
279 #pragma mark Back/Forward
280
281 - (void)goForward
282 {
283     WKPageGoForward(self._pageRef);
284 }
285
286 - (BOOL)canGoForward
287 {
288     return WKPageCanGoForward(self._pageRef);
289 }
290
291 - (void)goBack
292 {
293     WKPageGoBack(self._pageRef);
294 }
295
296 - (BOOL)canGoBack
297 {
298     return WKPageCanGoBack(self._pageRef);
299 }
300
301 #if WK_API_ENABLED
302 - (void)goToBackForwardListItem:(WKBackForwardListItem *)item
303 {
304     toImpl(self._pageRef)->goToBackForwardItem(&item._item);
305 }
306
307 - (WKBackForwardList *)backForwardList
308 {
309     WebBackForwardList* list = toImpl(self._pageRef)->backForwardList();
310     if (!list)
311         return nil;
312
313     return wrapper(*list);
314 }
315 #endif // WK_API_ENABLED
316
317 #pragma mark Active Load Introspection
318
319 - (NSURL *)activeURL
320 {
321     return autoreleased(WKPageCopyActiveURL(self._pageRef));
322 }
323
324 - (NSURL *)provisionalURL
325 {
326     return autoreleased(WKPageCopyProvisionalURL(self._pageRef));
327 }
328
329 - (NSURL *)committedURL
330 {
331     return autoreleased(WKPageCopyCommittedURL(self._pageRef));
332 }
333
334 - (NSURL *)unreachableURL
335 {
336     return [NSURL _web_URLWithWTFString:toImpl(_data->_pageRef.get())->unreachableURL() relativeToURL:nil];
337 }
338
339 - (double)estimatedProgress
340 {
341     return toImpl(self._pageRef)->estimatedProgress();
342 }
343
344 #pragma mark Active Document Introspection
345
346 - (NSString *)title
347 {
348     return autoreleased(WKPageCopyTitle(self._pageRef));
349 }
350
351 #pragma mark Zoom
352
353 - (CGFloat)textZoom
354 {
355     return WKPageGetTextZoomFactor(self._pageRef);
356 }
357
358 - (void)setTextZoom:(CGFloat)textZoom
359 {
360     return WKPageSetTextZoomFactor(self._pageRef, textZoom);
361 }
362
363 - (CGFloat)pageZoom
364 {
365     return WKPageGetPageZoomFactor(self._pageRef);
366 }
367
368 - (void)setPageZoom:(CGFloat)pageZoom
369 {
370     return WKPageSetPageZoomFactor(self._pageRef, pageZoom);
371 }
372
373 @end
374
375 @implementation WKBrowsingContextController (Private)
376
377 - (void)setPaginationMode:(WKBrowsingContextPaginationMode)paginationMode
378 {
379     WKPaginationMode mode;
380     switch (paginationMode) {
381     case WKPaginationModeUnpaginated:
382         mode = kWKPaginationModeUnpaginated;
383         break;
384     case WKPaginationModeLeftToRight:
385         mode = kWKPaginationModeLeftToRight;
386         break;
387     case WKPaginationModeRightToLeft:
388         mode = kWKPaginationModeRightToLeft;
389         break;
390     case WKPaginationModeTopToBottom:
391         mode = kWKPaginationModeTopToBottom;
392         break;
393     case WKPaginationModeBottomToTop:
394         mode = kWKPaginationModeBottomToTop;
395         break;
396     default:
397         return;
398     }
399
400     WKPageSetPaginationMode(self._pageRef, mode);
401 }
402
403 - (WKBrowsingContextPaginationMode)paginationMode
404 {
405     switch (WKPageGetPaginationMode(self._pageRef)) {
406     case kWKPaginationModeUnpaginated:
407         return WKPaginationModeUnpaginated;
408     case kWKPaginationModeLeftToRight:
409         return WKPaginationModeLeftToRight;
410     case kWKPaginationModeRightToLeft:
411         return WKPaginationModeRightToLeft;
412     case kWKPaginationModeTopToBottom:
413         return WKPaginationModeTopToBottom;
414     case kWKPaginationModeBottomToTop:
415         return WKPaginationModeBottomToTop;
416     }
417
418     ASSERT_NOT_REACHED();
419     return WKPaginationModeUnpaginated;
420 }
421
422 - (void)setPaginationBehavesLikeColumns:(BOOL)behavesLikeColumns
423 {
424     WKPageSetPaginationBehavesLikeColumns(self._pageRef, behavesLikeColumns);
425 }
426
427 - (BOOL)paginationBehavesLikeColumns
428 {
429     return WKPageGetPaginationBehavesLikeColumns(self._pageRef);
430 }
431
432 - (void)setPageLength:(CGFloat)pageLength
433 {
434     WKPageSetPageLength(self._pageRef, pageLength);
435 }
436
437 - (CGFloat)pageLength
438 {
439     return WKPageGetPageLength(self._pageRef);
440 }
441
442 - (void)setGapBetweenPages:(CGFloat)gapBetweenPages
443 {
444     WKPageSetGapBetweenPages(self._pageRef, gapBetweenPages);
445 }
446
447 - (CGFloat)gapBetweenPages
448 {
449     return WKPageGetGapBetweenPages(self._pageRef);
450 }
451
452 - (NSUInteger)pageCount
453 {
454     return WKPageGetPageCount(self._pageRef);
455 }
456
457 #if WK_API_ENABLED
458
459 - (WKBrowsingContextHandle *)handle
460 {
461     return [[[WKBrowsingContextHandle alloc] _initWithPageID:toImpl(self._pageRef)->pageID()] autorelease];
462 }
463
464 #endif
465
466 @end
467
468 @implementation WKBrowsingContextController (Internal)
469
470 static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
471 {
472     if (!WKFrameIsMainFrame(frame))
473         return;
474
475     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
476     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidStartProvisionalLoad:)])
477         [browsingContext.loadDelegate browsingContextControllerDidStartProvisionalLoad:browsingContext];
478 }
479
480 static void didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
481 {
482     if (!WKFrameIsMainFrame(frame))
483         return;
484
485     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
486     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidReceiveServerRedirectForProvisionalLoad:)])
487         [browsingContext.loadDelegate browsingContextControllerDidReceiveServerRedirectForProvisionalLoad:browsingContext];
488 }
489
490 static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
491 {
492     if (!WKFrameIsMainFrame(frame))
493         return;
494
495     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
496     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidFailProvisionalLoad:withError:)]) {
497         RetainPtr<CFErrorRef> cfError = adoptCF(WKErrorCopyCFError(kCFAllocatorDefault, error));
498         [browsingContext.loadDelegate browsingContextControllerDidFailProvisionalLoad:browsingContext withError:(NSError *)cfError.get()];
499     }
500 }
501
502 static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
503 {
504     if (!WKFrameIsMainFrame(frame))
505         return;
506
507     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
508     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidCommitLoad:)])
509         [browsingContext.loadDelegate browsingContextControllerDidCommitLoad:browsingContext];
510 }
511
512 static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
513 {
514     if (!WKFrameIsMainFrame(frame))
515         return;
516
517     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
518     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidFinishLoad:)])
519         [browsingContext.loadDelegate browsingContextControllerDidFinishLoad:browsingContext];
520 }
521
522 static void didFailLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
523 {
524     if (!WKFrameIsMainFrame(frame))
525         return;
526
527     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
528     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidFailLoad:withError:)]) {
529         RetainPtr<CFErrorRef> cfError = adoptCF(WKErrorCopyCFError(kCFAllocatorDefault, error));
530         [browsingContext.loadDelegate browsingContextControllerDidFailLoad:browsingContext withError:(NSError *)cfError.get()];
531     }
532 }
533
534 static void didStartProgress(WKPageRef page, const void* clientInfo)
535 {
536     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
537     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidStartProgress:)])
538         [browsingContext.loadDelegate browsingContextControllerDidStartProgress:browsingContext];
539 }
540
541 static void didChangeProgress(WKPageRef page, const void* clientInfo)
542 {
543     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
544     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextController:estimatedProgressChangedTo:)])
545         [browsingContext.loadDelegate browsingContextController:browsingContext estimatedProgressChangedTo:toImpl(page)->estimatedProgress()];
546 }
547
548 static void didFinishProgress(WKPageRef page, const void* clientInfo)
549 {
550     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
551     if ([browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidFinishProgress:)])
552         [browsingContext.loadDelegate browsingContextControllerDidFinishProgress:browsingContext];
553 }
554
555 #if WK_API_ENABLED
556 static void didChangeBackForwardList(WKPageRef page, WKBackForwardListItemRef addedItem, WKArrayRef removedItems, const void *clientInfo)
557 {
558     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
559     if (![browsingContext.loadDelegate respondsToSelector:@selector(browsingContextControllerDidChangeBackForwardList:addedItem:removedItems:)])
560         return;
561
562     WKBackForwardListItem *added = addedItem ? wrapper(*toImpl(addedItem)) : nil;
563     NSArray *removed = removedItems ? wrapper(*toImpl(removedItems)) : nil;
564     [browsingContext.loadDelegate browsingContextControllerDidChangeBackForwardList:browsingContext addedItem:added removedItems:removed];
565 }
566 #endif // WK_API_ENABLED
567
568 static void setUpPageLoaderClient(WKBrowsingContextController *browsingContext, WKPageRef pageRef)
569 {
570     WKPageLoaderClient loaderClient;
571     memset(&loaderClient, 0, sizeof(loaderClient));
572
573     loaderClient.version = kWKPageLoaderClientCurrentVersion;
574     loaderClient.clientInfo = browsingContext;
575     loaderClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
576     loaderClient.didReceiveServerRedirectForProvisionalLoadForFrame = didReceiveServerRedirectForProvisionalLoadForFrame;
577     loaderClient.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrame;
578     loaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
579     loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
580     loaderClient.didFailLoadWithErrorForFrame = didFailLoadWithErrorForFrame;
581
582     loaderClient.didStartProgress = didStartProgress;
583     loaderClient.didChangeProgress = didChangeProgress;
584     loaderClient.didFinishProgress = didFinishProgress;
585
586 #if WK_API_ENABLED
587     loaderClient.didChangeBackForwardList = didChangeBackForwardList;
588 #endif
589
590     WKPageSetPageLoaderClient(pageRef, &loaderClient);
591 }
592
593 #if WK_API_ENABLED
594 static WKPolicyDecisionHandler makePolicyDecisionBlock(WKFramePolicyListenerRef listener)
595 {
596     WKRetain(listener); // Released in the decision handler below.
597
598     return [[^(WKPolicyDecision decision) {
599         switch (decision) {
600         case WKPolicyDecisionCancel:
601             WKFramePolicyListenerIgnore(listener);                    
602             break;
603         
604         case WKPolicyDecisionAllow:
605             WKFramePolicyListenerUse(listener);
606             break;
607         
608         case WKPolicyDecisionBecomeDownload:
609             WKFramePolicyListenerDownload(listener);
610             break;
611         };
612
613         WKRelease(listener); // Retained in the context above.
614     } copy] autorelease];
615 }
616
617 static void setUpPagePolicyClient(WKBrowsingContextController *browsingContext, WKPageRef pageRef)
618 {
619     WKPagePolicyClient policyClient;
620     memset(&policyClient, 0, sizeof(policyClient));
621
622     policyClient.version = kWKPagePolicyClientCurrentVersion;
623     policyClient.clientInfo = browsingContext;
624
625     policyClient.decidePolicyForNavigationAction = [](WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
626     {
627         WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
628         if ([browsingContext.policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForNavigationAction:decisionHandler:)]) {
629             NSDictionary *actionDictionary = @{
630                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
631                 WKActionNavigationTypeKey: @(navigationType),
632                 WKActionModifierFlagsKey: @(modifiers),
633                 WKActionMouseButtonKey: @(mouseButton),
634                 WKActionURLRequestKey: autoreleased(request)
635             };
636             
637             [browsingContext.policyDelegate browsingContextController:browsingContext decidePolicyForNavigationAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
638         } else
639             WKFramePolicyListenerUse(listener);
640     };
641
642     policyClient.decidePolicyForNewWindowAction = [](WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKStringRef frameName, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
643     {
644         WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
645         if ([browsingContext.policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForNewWindowAction:decisionHandler:)]) {
646             NSDictionary *actionDictionary = @{
647                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
648                 WKActionNavigationTypeKey: @(navigationType),
649                 WKActionModifierFlagsKey: @(modifiers),
650                 WKActionMouseButtonKey: @(mouseButton),
651                 WKActionURLRequestKey: autoreleased(request),
652                 WKActionFrameNameKey: toImpl(frameName)->wrapper()
653             };
654             
655             [browsingContext.policyDelegate browsingContextController:browsingContext decidePolicyForNewWindowAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
656         } else
657             WKFramePolicyListenerUse(listener);
658     };
659
660     policyClient.decidePolicyForResponse = [](WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
661     {
662         WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
663         if ([browsingContext.policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForResponseAction:decisionHandler:)]) {
664             NSDictionary *actionDictionary = @{
665                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
666                 WKActionURLRequestKey: autoreleased(request),
667                 WKActionURLResponseKey: autoreleased(response)
668             };
669
670             [browsingContext.policyDelegate browsingContextController:browsingContext decidePolicyForResponseAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
671         } else
672             WKFramePolicyListenerUse(listener);
673     };
674
675     WKPageSetPagePolicyClient(pageRef, &policyClient);
676 }
677 #endif
678
679 /* This should only be called from associate view. */
680
681 - (id)_initWithPageRef:(WKPageRef)pageRef
682 {
683     self = [super init];
684     if (!self)
685         return nil;
686
687     _data = [[WKBrowsingContextControllerData alloc] init];
688     _data->_pageRef = pageRef;
689
690     setUpPageLoaderClient(self, pageRef);
691
692 #if WK_API_ENABLED
693     setUpPagePolicyClient(self, pageRef);
694 #endif
695
696     return self;
697 }
698
699 + (WKBrowsingContextController *)_browsingContextControllerForPageRef:(WKPageRef)pageRef
700 {
701     return (WKBrowsingContextController *)WebKit::toImpl(pageRef)->loaderClient().client().clientInfo;
702 }
703
704 + (NSMutableSet *)customSchemes
705 {
706     static NSMutableSet *customSchemes = [[NSMutableSet alloc] init];
707     return customSchemes;
708 }
709  
710 @end