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