Begin deprecating C API
[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     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
518     WKPageSetPagePolicyClient(toAPI(&page), &policyClient.base);
519     ALLOW_DEPRECATED_DECLARATIONS_END
520 }
521
522 - (id <WKBrowsingContextLoadDelegate>)loadDelegate
523 {
524     return _loadDelegate.getAutoreleased();
525 }
526
527 - (void)setLoadDelegate:(id <WKBrowsingContextLoadDelegate>)loadDelegate
528 {
529     _loadDelegate = loadDelegate;
530
531     if (loadDelegate)
532         setUpPageLoaderClient(self, *_page);
533     else
534         WKPageSetPageNavigationClient(toAPI(_page.get()), nullptr);
535 }
536
537 - (id <WKBrowsingContextPolicyDelegate>)policyDelegate
538 {
539     return _policyDelegate.getAutoreleased();
540 }
541
542 - (void)setPolicyDelegate:(id <WKBrowsingContextPolicyDelegate>)policyDelegate
543 {
544     _policyDelegate = policyDelegate;
545
546     if (policyDelegate)
547         setUpPagePolicyClient(self, *_page);
548     else {
549         ALLOW_DEPRECATED_DECLARATIONS_BEGIN
550         WKPageSetPagePolicyClient(toAPI(_page.get()), nullptr);
551         ALLOW_DEPRECATED_DECLARATIONS_END
552     }
553 }
554
555 - (id <WKBrowsingContextHistoryDelegate>)historyDelegate
556 {
557     return _historyDelegate.getAutoreleased();
558 }
559
560 - (void)setHistoryDelegate:(id <WKBrowsingContextHistoryDelegate>)historyDelegate
561 {
562     _historyDelegate = historyDelegate;
563 }
564
565 + (NSMutableSet *)customSchemes
566 {
567     static NSMutableSet *customSchemes = [[NSMutableSet alloc] init];
568     return customSchemes;
569 }
570
571 - (instancetype)_initWithPageRef:(WKPageRef)pageRef
572 {
573     if (!(self = [super init]))
574         return nil;
575
576     _page = WebKit::toImpl(pageRef);
577
578     _pageLoadStateObserver = std::make_unique<WebKit::PageLoadStateObserver>(self);
579     _page->pageLoadState().addObserver(*_pageLoadStateObserver);
580
581     ASSERT(!browsingContextControllerMap().contains(_page.get()));
582     browsingContextControllerMap().set(_page.get(), self);
583
584     return self;
585 }
586
587 + (WKBrowsingContextController *)_browsingContextControllerForPageRef:(WKPageRef)pageRef
588 {
589     return browsingContextControllerMap().get(WebKit::toImpl(pageRef));
590 }
591
592 @end
593
594 @implementation WKBrowsingContextController (Private)
595
596 - (WKPageRef)_pageRef
597 {
598     return WebKit::toAPI(_page.get());
599 }
600
601 - (void)setPaginationMode:(WKBrowsingContextPaginationMode)paginationMode
602 {
603     WebCore::Pagination::Mode mode;
604     switch (paginationMode) {
605     case WKPaginationModeUnpaginated:
606         mode = WebCore::Pagination::Unpaginated;
607         break;
608     case WKPaginationModeLeftToRight:
609         mode = WebCore::Pagination::LeftToRightPaginated;
610         break;
611     case WKPaginationModeRightToLeft:
612         mode = WebCore::Pagination::RightToLeftPaginated;
613         break;
614     case WKPaginationModeTopToBottom:
615         mode = WebCore::Pagination::TopToBottomPaginated;
616         break;
617     case WKPaginationModeBottomToTop:
618         mode = WebCore::Pagination::BottomToTopPaginated;
619         break;
620     default:
621         return;
622     }
623
624     _page->setPaginationMode(mode);
625 }
626
627 - (WKBrowsingContextPaginationMode)paginationMode
628 {
629     switch (_page->paginationMode()) {
630     case WebCore::Pagination::Unpaginated:
631         return WKPaginationModeUnpaginated;
632     case WebCore::Pagination::LeftToRightPaginated:
633         return WKPaginationModeLeftToRight;
634     case WebCore::Pagination::RightToLeftPaginated:
635         return WKPaginationModeRightToLeft;
636     case WebCore::Pagination::TopToBottomPaginated:
637         return WKPaginationModeTopToBottom;
638     case WebCore::Pagination::BottomToTopPaginated:
639         return WKPaginationModeBottomToTop;
640     }
641
642     ASSERT_NOT_REACHED();
643     return WKPaginationModeUnpaginated;
644 }
645
646 - (void)setPaginationBehavesLikeColumns:(BOOL)behavesLikeColumns
647 {
648     _page->setPaginationBehavesLikeColumns(behavesLikeColumns);
649 }
650
651 - (BOOL)paginationBehavesLikeColumns
652 {
653     return _page->paginationBehavesLikeColumns();
654 }
655
656 - (void)setPageLength:(CGFloat)pageLength
657 {
658     _page->setPageLength(pageLength);
659 }
660
661 - (CGFloat)pageLength
662 {
663     return _page->pageLength();
664 }
665
666 - (void)setGapBetweenPages:(CGFloat)gapBetweenPages
667 {
668     _page->setGapBetweenPages(gapBetweenPages);
669 }
670
671 - (CGFloat)gapBetweenPages
672 {
673     return _page->gapBetweenPages();
674 }
675
676 - (void)setPaginationLineGridEnabled:(BOOL)lineGridEnabled
677 {
678     _page->setPaginationLineGridEnabled(lineGridEnabled);
679 }
680
681 - (BOOL)paginationLineGridEnabled
682 {
683     return _page->paginationLineGridEnabled();
684 }
685
686 - (NSUInteger)pageCount
687 {
688     return _page->pageCount();
689 }
690
691 - (WKBrowsingContextHandle *)handle
692 {
693     return [[[WKBrowsingContextHandle alloc] _initWithPageID:_page->pageID()] autorelease];
694 }
695
696 - (_WKRemoteObjectRegistry *)_remoteObjectRegistry
697 {
698 #if WK_API_ENABLED && !TARGET_OS_IPHONE
699     return _page->remoteObjectRegistry();
700 #else
701     return nil;
702 #endif
703 }
704
705 - (pid_t)processIdentifier
706 {
707     return _page->processIdentifier();
708 }
709
710 - (BOOL)_webProcessIsResponsive
711 {
712     return _page->process().isResponsive();
713 }
714
715 @end
716
717 #endif // WK_API_ENABLED