Unify most of the WebKit Objective-C API sources
[WebKit-https.git] / Source / WebKit / UIProcess / API / Cocoa / WKBrowsingContextController.mm
1 /*
2  * Copyright (C) 2011, 2012, 2013 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 #if WK_API_ENABLED
30
31 #import "APIData.h"
32 #import "APINavigation.h"
33 #import "ObjCObjectGraph.h"
34 #import "PageLoadStateObserver.h"
35 #import "RemoteObjectRegistry.h"
36 #import "RemoteObjectRegistryMessages.h"
37 #import "WKBackForwardListInternal.h"
38 #import "WKBackForwardListItemInternal.h"
39 #import "WKBrowsingContextGroupInternal.h"
40 #import "WKBrowsingContextHandleInternal.h"
41 #import "WKBrowsingContextLoadDelegatePrivate.h"
42 #import "WKBrowsingContextPolicyDelegate.h"
43 #import "WKFrame.h"
44 #import "WKFramePolicyListener.h"
45 #import "WKNSArray.h"
46 #import "WKNSData.h"
47 #import "WKNSError.h"
48 #import "WKNSURLAuthenticationChallenge.h"
49 #import "WKNSURLExtras.h"
50 #import "WKPagePolicyClientInternal.h"
51 #import "WKProcessGroupPrivate.h"
52 #import "WKRetainPtr.h"
53 #import "WKURLRequestNS.h"
54 #import "WKURLResponseNS.h"
55 #import "WKViewInternal.h"
56 #import "WebCertificateInfo.h"
57 #import "WebPageProxy.h"
58 #import "WebProcessPool.h"
59 #import "WebProtectionSpace.h"
60 #import "_WKRemoteObjectRegistryInternal.h"
61 #import <wtf/NeverDestroyed.h>
62 #import <wtf/WeakObjCPtr.h>
63
64 NSString * const WKActionIsMainFrameKey = @"WKActionIsMainFrameKey";
65 NSString * const WKActionNavigationTypeKey = @"WKActionNavigationTypeKey";
66 NSString * const WKActionMouseButtonKey = @"WKActionMouseButtonKey";
67 NSString * const WKActionModifierFlagsKey = @"WKActionModifierFlagsKey";
68 NSString * const WKActionOriginalURLRequestKey = @"WKActionOriginalURLRequestKey";
69 NSString * const WKActionURLRequestKey = @"WKActionURLRequestKey";
70 NSString * const WKActionURLResponseKey = @"WKActionURLResponseKey";
71 NSString * const WKActionFrameNameKey = @"WKActionFrameNameKey";
72 NSString * const WKActionOriginatingFrameURLKey = @"WKActionOriginatingFrameURLKey";
73 NSString * const WKActionCanShowMIMETypeKey = @"WKActionCanShowMIMETypeKey";
74
75 @implementation WKBrowsingContextController {
76     RefPtr<WebKit::WebPageProxy> _page;
77     std::unique_ptr<WebKit::PageLoadStateObserver> _pageLoadStateObserver;
78
79     WeakObjCPtr<id <WKBrowsingContextLoadDelegate>> _loadDelegate;
80     WeakObjCPtr<id <WKBrowsingContextPolicyDelegate>> _policyDelegate;
81 }
82
83 static HashMap<WebKit::WebPageProxy*, __unsafe_unretained WKBrowsingContextController *>& browsingContextControllerMap()
84 {
85     static NeverDestroyed<HashMap<WebKit::WebPageProxy*, __unsafe_unretained WKBrowsingContextController *>> browsingContextControllerMap;
86     return browsingContextControllerMap;
87 }
88
89 - (void)dealloc
90 {
91     ASSERT(browsingContextControllerMap().get(_page.get()) == self);
92     browsingContextControllerMap().remove(_page.get());
93
94     _page->pageLoadState().removeObserver(*_pageLoadStateObserver);
95
96     [super dealloc];
97 }
98
99 #pragma mark Loading
100
101 + (void)registerSchemeForCustomProtocol:(NSString *)scheme
102 {
103     WebKit::WebProcessPool::registerGlobalURLSchemeAsHavingCustomProtocolHandlers(scheme);
104 }
105
106 + (void)unregisterSchemeForCustomProtocol:(NSString *)scheme
107 {
108     WebKit::WebProcessPool::unregisterGlobalURLSchemeAsHavingCustomProtocolHandlers(scheme);
109 }
110
111 - (void)loadRequest:(NSURLRequest *)request
112 {
113     [self loadRequest:request userData:nil];
114 }
115
116 - (void)loadRequest:(NSURLRequest *)request userData:(id)userData
117 {
118     RefPtr<WebKit::ObjCObjectGraph> wkUserData;
119     if (userData)
120         wkUserData = WebKit::ObjCObjectGraph::create(userData);
121
122     _page->loadRequest(request, WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow, wkUserData.get());
123 }
124
125 - (void)loadFileURL:(NSURL *)URL restrictToFilesWithin:(NSURL *)allowedDirectory
126 {
127     [self loadFileURL:URL restrictToFilesWithin:allowedDirectory userData:nil];
128 }
129
130 - (void)loadFileURL:(NSURL *)URL restrictToFilesWithin:(NSURL *)allowedDirectory userData:(id)userData
131 {
132     if (![URL isFileURL] || (allowedDirectory && ![allowedDirectory isFileURL]))
133         [NSException raise:NSInvalidArgumentException format:@"Attempted to load a non-file URL"];
134
135     RefPtr<WebKit::ObjCObjectGraph> wkUserData;
136     if (userData)
137         wkUserData = WebKit::ObjCObjectGraph::create(userData);
138
139     _page->loadFile([URL _web_originalDataAsWTFString], [allowedDirectory _web_originalDataAsWTFString], wkUserData.get());
140 }
141
142 - (void)loadHTMLString:(NSString *)HTMLString baseURL:(NSURL *)baseURL
143 {
144     [self loadHTMLString:HTMLString baseURL:baseURL userData:nil];
145 }
146
147 - (void)loadHTMLString:(NSString *)HTMLString baseURL:(NSURL *)baseURL userData:(id)userData
148 {
149     RefPtr<WebKit::ObjCObjectGraph> wkUserData;
150     if (userData)
151         wkUserData = WebKit::ObjCObjectGraph::create(userData);
152
153     NSData *data = [HTMLString dataUsingEncoding:NSUTF8StringEncoding];
154     _page->loadData({ static_cast<const uint8_t*>(data.bytes), data.length }, "text/html"_s, "UTF-8"_s, [baseURL _web_originalDataAsWTFString], wkUserData.get());
155 }
156
157 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
158 {
159     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
160     _page->loadAlternateHTML({ static_cast<const uint8_t*>(data.bytes), data.length }, "UTF-8"_s, baseURL, unreachableURL);
161 }
162
163 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
164 {
165     [self loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL userData:nil];
166 }
167
168 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL userData:(id)userData
169 {
170     RefPtr<WebKit::ObjCObjectGraph> wkUserData;
171     if (userData)
172         wkUserData = WebKit::ObjCObjectGraph::create(userData);
173
174     _page->loadData({ static_cast<const uint8_t*>(data.bytes), data.length }, MIMEType, encodingName, [baseURL _web_originalDataAsWTFString], wkUserData.get());
175 }
176
177 - (void)stopLoading
178 {
179     _page->stopLoading();
180 }
181
182 - (void)reload
183 {
184     _page->reload({ });
185 }
186
187 - (void)reloadFromOrigin
188 {
189     _page->reload(WebCore::ReloadOption::FromOrigin);
190 }
191
192 - (NSString *)applicationNameForUserAgent
193 {
194     const String& applicationName = _page->applicationNameForUserAgent();
195     return !applicationName ? nil : (NSString *)applicationName;
196 }
197
198 - (void)setApplicationNameForUserAgent:(NSString *)applicationNameForUserAgent
199 {
200     _page->setApplicationNameForUserAgent(applicationNameForUserAgent);
201 }
202
203 - (NSString *)customUserAgent
204 {
205     const String& customUserAgent = _page->customUserAgent();
206     return !customUserAgent ? nil : (NSString *)customUserAgent;
207 }
208
209 - (void)setCustomUserAgent:(NSString *)customUserAgent
210 {
211     _page->setCustomUserAgent(customUserAgent);
212 }
213
214 #pragma mark Back/Forward
215
216 - (void)goForward
217 {
218     _page->goForward();
219 }
220
221 - (BOOL)canGoForward
222 {
223     return !!_page->backForwardList().forwardItem();
224 }
225
226 - (void)goBack
227 {
228     _page->goBack();
229 }
230
231 - (BOOL)canGoBack
232 {
233     return !!_page->backForwardList().backItem();
234 }
235
236 - (void)goToBackForwardListItem:(WKBackForwardListItem *)item
237 {
238     _page->goToBackForwardItem(item._item);
239 }
240
241 - (WKBackForwardList *)backForwardList
242 {
243     return wrapper(_page->backForwardList());
244 }
245
246 #pragma mark Active Load Introspection
247
248 - (BOOL)isLoading
249 {
250     return _page->pageLoadState().isLoading();
251 }
252
253 - (NSURL *)activeURL
254 {
255     return [NSURL _web_URLWithWTFString:_page->pageLoadState().activeURL()];
256 }
257
258 - (NSURL *)provisionalURL
259 {
260     return [NSURL _web_URLWithWTFString:_page->pageLoadState().provisionalURL()];
261 }
262
263 - (NSURL *)committedURL
264 {
265     return [NSURL _web_URLWithWTFString:_page->pageLoadState().url()];
266 }
267
268 - (NSURL *)unreachableURL
269 {
270     return [NSURL _web_URLWithWTFString:_page->pageLoadState().unreachableURL()];
271 }
272
273 - (BOOL)hasOnlySecureContent
274 {
275     return _page->pageLoadState().hasOnlySecureContent();
276 }
277
278 - (double)estimatedProgress
279 {
280     return _page->estimatedProgress();
281 }
282
283 #pragma mark Active Document Introspection
284
285 - (NSString *)title
286 {
287     return _page->pageLoadState().title();
288 }
289
290 - (NSArray *)certificateChain
291 {
292     if (WebKit::WebFrameProxy* mainFrame = _page->mainFrame())
293         return mainFrame->certificateInfo() ? (__bridge NSArray *)mainFrame->certificateInfo()->certificateInfo().certificateChain() : nil;
294
295     return nil;
296 }
297
298 #pragma mark Zoom
299
300 - (CGFloat)textZoom
301 {
302     return _page->textZoomFactor();
303 }
304
305 - (void)setTextZoom:(CGFloat)textZoom
306 {
307     _page->setTextZoomFactor(textZoom);
308 }
309
310 - (CGFloat)pageZoom
311 {
312     return _page->pageZoomFactor();
313 }
314
315 - (void)setPageZoom:(CGFloat)pageZoom
316 {
317     _page->setPageZoomFactor(pageZoom);
318 }
319
320 static void didStartProvisionalNavigation(WKPageRef page, WKNavigationRef, WKTypeRef userData, const void* clientInfo)
321 {
322     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
323     auto loadDelegate = browsingContext->_loadDelegate.get();
324
325     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidStartProvisionalLoad:)])
326         [loadDelegate browsingContextControllerDidStartProvisionalLoad:browsingContext];
327 }
328
329 static void didReceiveServerRedirectForProvisionalNavigation(WKPageRef page, WKNavigationRef, WKTypeRef userData, const void* clientInfo)
330 {
331     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
332     auto loadDelegate = browsingContext->_loadDelegate.get();
333
334     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidReceiveServerRedirectForProvisionalLoad:)])
335         [loadDelegate browsingContextControllerDidReceiveServerRedirectForProvisionalLoad:browsingContext];
336 }
337
338 static void didFailProvisionalNavigation(WKPageRef page, WKNavigationRef, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
339 {
340     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
341     auto loadDelegate = browsingContext->_loadDelegate.get();
342
343     if ([loadDelegate respondsToSelector:@selector(browsingContextController:didFailProvisionalLoadWithError:)])
344         [loadDelegate browsingContextController:browsingContext didFailProvisionalLoadWithError:wrapper(*WebKit::toImpl(error))];
345 }
346
347 static void didCommitNavigation(WKPageRef page, WKNavigationRef, WKTypeRef userData, const void* clientInfo)
348 {
349     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
350     auto loadDelegate = browsingContext->_loadDelegate.get();
351
352     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidCommitLoad:)])
353         [loadDelegate browsingContextControllerDidCommitLoad:browsingContext];
354 }
355
356 static void didFinishNavigation(WKPageRef page, WKNavigationRef, WKTypeRef userData, const void* clientInfo)
357 {
358     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
359     auto loadDelegate = browsingContext->_loadDelegate.get();
360
361     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidFinishLoad:)])
362         [loadDelegate browsingContextControllerDidFinishLoad:browsingContext];
363 }
364
365 static void didFailNavigation(WKPageRef page, WKNavigationRef, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
366 {
367     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
368     auto loadDelegate = browsingContext->_loadDelegate.get();
369
370     if ([loadDelegate respondsToSelector:@selector(browsingContextController:didFailLoadWithError:)])
371         [loadDelegate browsingContextController:browsingContext didFailLoadWithError:wrapper(*WebKit::toImpl(error))];
372 }
373
374 static bool canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace, const void *clientInfo)
375 {
376     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
377     auto loadDelegate = browsingContext->_loadDelegate.get();
378
379     if ([loadDelegate respondsToSelector:@selector(browsingContextController:canAuthenticateAgainstProtectionSpace:)])
380         return [(id <WKBrowsingContextLoadDelegatePrivate>)loadDelegate browsingContextController:browsingContext canAuthenticateAgainstProtectionSpace:WebKit::toImpl(protectionSpace)->protectionSpace().nsSpace()];
381
382     return false;
383 }
384
385 static void didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
386 {
387     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
388     auto loadDelegate = browsingContext->_loadDelegate.get();
389
390     if ([loadDelegate respondsToSelector:@selector(browsingContextController:didReceiveAuthenticationChallenge:)])
391         [(id <WKBrowsingContextLoadDelegatePrivate>)loadDelegate browsingContextController:browsingContext didReceiveAuthenticationChallenge:wrapper(*WebKit::toImpl(authenticationChallenge))];
392 }
393
394 static void processDidCrash(WKPageRef page, const void* clientInfo)
395 {
396     auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
397     auto loadDelegate = browsingContext->_loadDelegate.get();
398
399     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerWebProcessDidCrash:)])
400         [(id <WKBrowsingContextLoadDelegatePrivate>)loadDelegate browsingContextControllerWebProcessDidCrash:browsingContext];
401 }
402
403 static void setUpPageLoaderClient(WKBrowsingContextController *browsingContext, WebKit::WebPageProxy& page)
404 {
405     WKPageNavigationClientV0 loaderClient;
406     memset(&loaderClient, 0, sizeof(loaderClient));
407
408     loaderClient.base.version = 0;
409     loaderClient.base.clientInfo = (__bridge void*)browsingContext;
410     loaderClient.didStartProvisionalNavigation = didStartProvisionalNavigation;
411     loaderClient.didReceiveServerRedirectForProvisionalNavigation = didReceiveServerRedirectForProvisionalNavigation;
412     loaderClient.didFailProvisionalNavigation = didFailProvisionalNavigation;
413     loaderClient.didCommitNavigation = didCommitNavigation;
414     loaderClient.didFinishNavigation = didFinishNavigation;
415     loaderClient.didFailNavigation = didFailNavigation;
416     loaderClient.canAuthenticateAgainstProtectionSpace = canAuthenticateAgainstProtectionSpace;
417     loaderClient.didReceiveAuthenticationChallenge = didReceiveAuthenticationChallenge;
418     loaderClient.webProcessDidCrash = processDidCrash;
419
420     WKPageSetPageNavigationClient(toAPI(&page), &loaderClient.base);
421 }
422
423 static WKPolicyDecisionHandler makePolicyDecisionBlock(WKFramePolicyListenerRef listener)
424 {
425     WKRetain(listener); // Released in the decision handler below.
426
427     return [[^(WKPolicyDecision decision) {
428         switch (decision) {
429         case WKPolicyDecisionCancel:
430             WKFramePolicyListenerIgnore(listener);                    
431             break;
432         
433         case WKPolicyDecisionAllow:
434             WKFramePolicyListenerUse(listener);
435             break;
436         
437         case WKPolicyDecisionBecomeDownload:
438             WKFramePolicyListenerDownload(listener);
439             break;
440         };
441
442         WKRelease(listener); // Retained in the context above.
443     } copy] autorelease];
444 }
445
446 static void setUpPagePolicyClient(WKBrowsingContextController *browsingContext, WebKit::WebPageProxy& page)
447 {
448     WKPagePolicyClientInternal policyClient;
449     memset(&policyClient, 0, sizeof(policyClient));
450
451     policyClient.base.version = 2;
452     policyClient.base.clientInfo = (__bridge void*)browsingContext;
453
454     policyClient.decidePolicyForNavigationAction = [](WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKFrameRef originatingFrame, WKURLRequestRef originalRequest, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
455     {
456         auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
457         auto policyDelegate = browsingContext->_policyDelegate.get();
458
459         if ([policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForNavigationAction:decisionHandler:)]) {
460             NSDictionary *actionDictionary = @{
461                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
462                 WKActionNavigationTypeKey: @(navigationType),
463                 WKActionModifierFlagsKey: @(modifiers),
464                 WKActionMouseButtonKey: @(mouseButton),
465                 WKActionOriginalURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(originalRequest)).get(),
466                 WKActionURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(request)).get()
467             };
468
469             if (originatingFrame) {
470                 actionDictionary = [[actionDictionary mutableCopy] autorelease];
471                 [(NSMutableDictionary *)actionDictionary setObject:[NSURL _web_URLWithWTFString:WebKit::toImpl(originatingFrame)->url()] forKey:WKActionOriginatingFrameURLKey];
472             }
473             
474             [policyDelegate browsingContextController:browsingContext decidePolicyForNavigationAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
475         } else
476             WKFramePolicyListenerUse(listener);
477     };
478
479     policyClient.decidePolicyForNewWindowAction = [](WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKStringRef frameName, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
480     {
481         auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
482         auto policyDelegate = browsingContext->_policyDelegate.get();
483
484         if ([policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForNewWindowAction:decisionHandler:)]) {
485             NSDictionary *actionDictionary = @{
486                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
487                 WKActionNavigationTypeKey: @(navigationType),
488                 WKActionModifierFlagsKey: @(modifiers),
489                 WKActionMouseButtonKey: @(mouseButton),
490                 WKActionURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(request)).get(),
491                 WKActionFrameNameKey: WebKit::toImpl(frameName)->wrapper()
492             };
493             
494             [policyDelegate browsingContextController:browsingContext decidePolicyForNewWindowAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
495         } else
496             WKFramePolicyListenerUse(listener);
497     };
498
499     policyClient.decidePolicyForResponse = [](WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
500     {
501         auto browsingContext = (__bridge WKBrowsingContextController *)clientInfo;
502         auto policyDelegate = browsingContext->_policyDelegate.get();
503
504         if ([policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForResponseAction:decisionHandler:)]) {
505             NSDictionary *actionDictionary = @{
506                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
507                 WKActionURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(request)).get(),
508                 WKActionURLResponseKey: adoptNS(WKURLResponseCopyNSURLResponse(response)).get(),
509                 WKActionCanShowMIMETypeKey: @(canShowMIMEType),
510             };
511
512             [policyDelegate browsingContextController:browsingContext decidePolicyForResponseAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
513         } else
514             WKFramePolicyListenerUse(listener);
515     };
516
517     WKPageSetPagePolicyClient(toAPI(&page), &policyClient.base);
518 }
519
520 - (id <WKBrowsingContextLoadDelegate>)loadDelegate
521 {
522     return _loadDelegate.getAutoreleased();
523 }
524
525 - (void)setLoadDelegate:(id <WKBrowsingContextLoadDelegate>)loadDelegate
526 {
527     _loadDelegate = loadDelegate;
528
529     if (loadDelegate)
530         setUpPageLoaderClient(self, *_page);
531     else
532         WKPageSetPageNavigationClient(toAPI(_page.get()), nullptr);
533 }
534
535 - (id <WKBrowsingContextPolicyDelegate>)policyDelegate
536 {
537     return _policyDelegate.getAutoreleased();
538 }
539
540 - (void)setPolicyDelegate:(id <WKBrowsingContextPolicyDelegate>)policyDelegate
541 {
542     _policyDelegate = policyDelegate;
543
544     if (policyDelegate)
545         setUpPagePolicyClient(self, *_page);
546     else
547         WKPageSetPagePolicyClient(toAPI(_page.get()), nullptr);
548 }
549
550 - (id <WKBrowsingContextHistoryDelegate>)historyDelegate
551 {
552     return _historyDelegate.getAutoreleased();
553 }
554
555 - (void)setHistoryDelegate:(id <WKBrowsingContextHistoryDelegate>)historyDelegate
556 {
557     _historyDelegate = historyDelegate;
558 }
559
560 + (NSMutableSet *)customSchemes
561 {
562     static NSMutableSet *customSchemes = [[NSMutableSet alloc] init];
563     return customSchemes;
564 }
565
566 - (instancetype)_initWithPageRef:(WKPageRef)pageRef
567 {
568     if (!(self = [super init]))
569         return nil;
570
571     _page = WebKit::toImpl(pageRef);
572
573     _pageLoadStateObserver = std::make_unique<WebKit::PageLoadStateObserver>(self);
574     _page->pageLoadState().addObserver(*_pageLoadStateObserver);
575
576     ASSERT(!browsingContextControllerMap().contains(_page.get()));
577     browsingContextControllerMap().set(_page.get(), self);
578
579     return self;
580 }
581
582 + (WKBrowsingContextController *)_browsingContextControllerForPageRef:(WKPageRef)pageRef
583 {
584     return browsingContextControllerMap().get(WebKit::toImpl(pageRef));
585 }
586
587 @end
588
589 @implementation WKBrowsingContextController (Private)
590
591 - (WKPageRef)_pageRef
592 {
593     return WebKit::toAPI(_page.get());
594 }
595
596 - (void)setPaginationMode:(WKBrowsingContextPaginationMode)paginationMode
597 {
598     WebCore::Pagination::Mode mode;
599     switch (paginationMode) {
600     case WKPaginationModeUnpaginated:
601         mode = WebCore::Pagination::Unpaginated;
602         break;
603     case WKPaginationModeLeftToRight:
604         mode = WebCore::Pagination::LeftToRightPaginated;
605         break;
606     case WKPaginationModeRightToLeft:
607         mode = WebCore::Pagination::RightToLeftPaginated;
608         break;
609     case WKPaginationModeTopToBottom:
610         mode = WebCore::Pagination::TopToBottomPaginated;
611         break;
612     case WKPaginationModeBottomToTop:
613         mode = WebCore::Pagination::BottomToTopPaginated;
614         break;
615     default:
616         return;
617     }
618
619     _page->setPaginationMode(mode);
620 }
621
622 - (WKBrowsingContextPaginationMode)paginationMode
623 {
624     switch (_page->paginationMode()) {
625     case WebCore::Pagination::Unpaginated:
626         return WKPaginationModeUnpaginated;
627     case WebCore::Pagination::LeftToRightPaginated:
628         return WKPaginationModeLeftToRight;
629     case WebCore::Pagination::RightToLeftPaginated:
630         return WKPaginationModeRightToLeft;
631     case WebCore::Pagination::TopToBottomPaginated:
632         return WKPaginationModeTopToBottom;
633     case WebCore::Pagination::BottomToTopPaginated:
634         return WKPaginationModeBottomToTop;
635     }
636
637     ASSERT_NOT_REACHED();
638     return WKPaginationModeUnpaginated;
639 }
640
641 - (void)setPaginationBehavesLikeColumns:(BOOL)behavesLikeColumns
642 {
643     _page->setPaginationBehavesLikeColumns(behavesLikeColumns);
644 }
645
646 - (BOOL)paginationBehavesLikeColumns
647 {
648     return _page->paginationBehavesLikeColumns();
649 }
650
651 - (void)setPageLength:(CGFloat)pageLength
652 {
653     _page->setPageLength(pageLength);
654 }
655
656 - (CGFloat)pageLength
657 {
658     return _page->pageLength();
659 }
660
661 - (void)setGapBetweenPages:(CGFloat)gapBetweenPages
662 {
663     _page->setGapBetweenPages(gapBetweenPages);
664 }
665
666 - (CGFloat)gapBetweenPages
667 {
668     return _page->gapBetweenPages();
669 }
670
671 - (void)setPaginationLineGridEnabled:(BOOL)lineGridEnabled
672 {
673     _page->setPaginationLineGridEnabled(lineGridEnabled);
674 }
675
676 - (BOOL)paginationLineGridEnabled
677 {
678     return _page->paginationLineGridEnabled();
679 }
680
681 - (NSUInteger)pageCount
682 {
683     return _page->pageCount();
684 }
685
686 - (WKBrowsingContextHandle *)handle
687 {
688     return [[[WKBrowsingContextHandle alloc] _initWithPageID:_page->pageID()] autorelease];
689 }
690
691 - (_WKRemoteObjectRegistry *)_remoteObjectRegistry
692 {
693 #if WK_API_ENABLED && !TARGET_OS_IPHONE
694     return _page->remoteObjectRegistry();
695 #else
696     return nil;
697 #endif
698 }
699
700 - (pid_t)processIdentifier
701 {
702     return _page->processIdentifier();
703 }
704
705 - (BOOL)_webProcessIsResponsive
706 {
707     return _page->process().isResponsive();
708 }
709
710 @end
711
712 #endif // WK_API_ENABLED