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