CTTE the responsiveness timer getter
[WebKit-https.git] / Source / WebKit2 / 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 _web_originalDataAsWTFString], [unreachableURL _web_originalDataAsWTFString]);
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     const bool reloadFromOrigin = false;
191     const bool contentBlockersEnabled = true;
192     _page->reload(reloadFromOrigin, contentBlockersEnabled);
193 }
194
195 - (void)reloadFromOrigin
196 {
197     const bool reloadFromOrigin = true;
198     const bool contentBlockersEnabled = true;
199     _page->reload(reloadFromOrigin, contentBlockersEnabled);
200 }
201
202 - (NSString *)applicationNameForUserAgent
203 {
204     const String& applicationName = _page->applicationNameForUserAgent();
205     return !applicationName ? nil : (NSString *)applicationName;
206 }
207
208 - (void)setApplicationNameForUserAgent:(NSString *)applicationNameForUserAgent
209 {
210     _page->setApplicationNameForUserAgent(applicationNameForUserAgent);
211 }
212
213 - (NSString *)customUserAgent
214 {
215     const String& customUserAgent = _page->customUserAgent();
216     return !customUserAgent ? nil : (NSString *)customUserAgent;
217 }
218
219 - (void)setCustomUserAgent:(NSString *)customUserAgent
220 {
221     _page->setCustomUserAgent(customUserAgent);
222 }
223
224 #pragma mark Back/Forward
225
226 - (void)goForward
227 {
228     _page->goForward();
229 }
230
231 - (BOOL)canGoForward
232 {
233     return !!_page->backForwardList().forwardItem();
234 }
235
236 - (void)goBack
237 {
238     _page->goBack();
239 }
240
241 - (BOOL)canGoBack
242 {
243     return !!_page->backForwardList().backItem();
244 }
245
246 - (void)goToBackForwardListItem:(WKBackForwardListItem *)item
247 {
248     _page->goToBackForwardItem(&item._item);
249 }
250
251 - (WKBackForwardList *)backForwardList
252 {
253     return wrapper(_page->backForwardList());
254 }
255
256 #pragma mark Active Load Introspection
257
258 - (BOOL)isLoading
259 {
260     return _page->pageLoadState().isLoading();
261 }
262
263 - (NSURL *)activeURL
264 {
265     return [NSURL _web_URLWithWTFString:_page->pageLoadState().activeURL()];
266 }
267
268 - (NSURL *)provisionalURL
269 {
270     return [NSURL _web_URLWithWTFString:_page->pageLoadState().provisionalURL()];
271 }
272
273 - (NSURL *)committedURL
274 {
275     return [NSURL _web_URLWithWTFString:_page->pageLoadState().url()];
276 }
277
278 - (NSURL *)unreachableURL
279 {
280     return [NSURL _web_URLWithWTFString:_page->pageLoadState().unreachableURL()];
281 }
282
283 - (BOOL)hasOnlySecureContent
284 {
285     return _page->pageLoadState().hasOnlySecureContent();
286 }
287
288 - (double)estimatedProgress
289 {
290     return _page->estimatedProgress();
291 }
292
293 #pragma mark Active Document Introspection
294
295 - (NSString *)title
296 {
297     return _page->pageLoadState().title();
298 }
299
300 - (NSArray *)certificateChain
301 {
302     if (WebFrameProxy* mainFrame = _page->mainFrame())
303         return mainFrame->certificateInfo() ? (NSArray *)mainFrame->certificateInfo()->certificateInfo().certificateChain() : nil;
304
305     return nil;
306 }
307
308 #pragma mark Zoom
309
310 - (CGFloat)textZoom
311 {
312     return _page->textZoomFactor();
313 }
314
315 - (void)setTextZoom:(CGFloat)textZoom
316 {
317     _page->setTextZoomFactor(textZoom);
318 }
319
320 - (CGFloat)pageZoom
321 {
322     return _page->pageZoomFactor();
323 }
324
325 - (void)setPageZoom:(CGFloat)pageZoom
326 {
327     _page->setPageZoomFactor(pageZoom);
328 }
329
330 static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
331 {
332     if (!WKFrameIsMainFrame(frame))
333         return;
334
335     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
336     auto loadDelegate = browsingContext->_loadDelegate.get();
337
338     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidStartProvisionalLoad:)])
339         [loadDelegate browsingContextControllerDidStartProvisionalLoad:browsingContext];
340 }
341
342 static void didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
343 {
344     if (!WKFrameIsMainFrame(frame))
345         return;
346
347     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
348     auto loadDelegate = browsingContext->_loadDelegate.get();
349
350     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidReceiveServerRedirectForProvisionalLoad:)])
351         [loadDelegate browsingContextControllerDidReceiveServerRedirectForProvisionalLoad:browsingContext];
352 }
353
354 static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
355 {
356     if (!WKFrameIsMainFrame(frame))
357         return;
358
359     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
360     auto loadDelegate = browsingContext->_loadDelegate.get();
361
362     if ([loadDelegate respondsToSelector:@selector(browsingContextController:didFailProvisionalLoadWithError:)])
363         [loadDelegate browsingContextController:browsingContext didFailProvisionalLoadWithError:wrapper(*toImpl(error))];
364 }
365
366 static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
367 {
368     if (!WKFrameIsMainFrame(frame))
369         return;
370
371     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
372     auto loadDelegate = browsingContext->_loadDelegate.get();
373
374     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidCommitLoad:)])
375         [loadDelegate browsingContextControllerDidCommitLoad:browsingContext];
376 }
377
378 static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
379 {
380     if (!WKFrameIsMainFrame(frame))
381         return;
382
383     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
384     auto loadDelegate = browsingContext->_loadDelegate.get();
385
386     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidFinishLoad:)])
387         [loadDelegate browsingContextControllerDidFinishLoad:browsingContext];
388 }
389
390 static void didFailLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
391 {
392     if (!WKFrameIsMainFrame(frame))
393         return;
394
395     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
396     auto loadDelegate = browsingContext->_loadDelegate.get();
397
398     if ([loadDelegate respondsToSelector:@selector(browsingContextController:didFailLoadWithError:)])
399         [loadDelegate browsingContextController:browsingContext didFailLoadWithError:wrapper(*toImpl(error))];
400 }
401
402 static bool canAuthenticateAgainstProtectionSpaceInFrame(WKPageRef page, WKFrameRef frame, WKProtectionSpaceRef protectionSpace, const void *clientInfo)
403 {
404     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
405     auto loadDelegate = browsingContext->_loadDelegate.get();
406
407     if ([loadDelegate respondsToSelector:@selector(browsingContextController:canAuthenticateAgainstProtectionSpace:)])
408         return [(id <WKBrowsingContextLoadDelegatePrivate>)loadDelegate browsingContextController:browsingContext canAuthenticateAgainstProtectionSpace:toImpl(protectionSpace)->protectionSpace().nsSpace()];
409
410     return false;
411 }
412
413 static void didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
414 {
415     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
416     auto loadDelegate = browsingContext->_loadDelegate.get();
417
418     if ([loadDelegate respondsToSelector:@selector(browsingContextController:didReceiveAuthenticationChallenge:)])
419         [(id <WKBrowsingContextLoadDelegatePrivate>)loadDelegate browsingContextController:browsingContext didReceiveAuthenticationChallenge:wrapper(*toImpl(authenticationChallenge))];
420 }
421
422 static void didStartProgress(WKPageRef page, const void* clientInfo)
423 {
424     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
425     auto loadDelegate = browsingContext->_loadDelegate.get();
426
427     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidStartProgress:)])
428         [loadDelegate browsingContextControllerDidStartProgress:browsingContext];
429 }
430
431 static void didChangeProgress(WKPageRef page, const void* clientInfo)
432 {
433     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
434     auto loadDelegate = browsingContext->_loadDelegate.get();
435
436     if ([loadDelegate respondsToSelector:@selector(browsingContextController:estimatedProgressChangedTo:)])
437         [loadDelegate browsingContextController:browsingContext estimatedProgressChangedTo:toImpl(page)->estimatedProgress()];
438 }
439
440 static void didFinishProgress(WKPageRef page, const void* clientInfo)
441 {
442     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
443     auto loadDelegate = browsingContext->_loadDelegate.get();
444
445     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerDidFinishProgress:)])
446         [loadDelegate browsingContextControllerDidFinishProgress:browsingContext];
447 }
448
449 static void didChangeBackForwardList(WKPageRef page, WKBackForwardListItemRef addedItem, WKArrayRef removedItems, const void *clientInfo)
450 {
451     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
452     auto loadDelegate = browsingContext->_loadDelegate.get();
453
454     if (![loadDelegate respondsToSelector:@selector(browsingContextControllerDidChangeBackForwardList:addedItem:removedItems:)])
455         return;
456
457     WKBackForwardListItem *added = addedItem ? wrapper(*toImpl(addedItem)) : nil;
458     NSArray *removed = removedItems ? wrapper(*toImpl(removedItems)) : nil;
459     [loadDelegate browsingContextControllerDidChangeBackForwardList:browsingContext addedItem:added removedItems:removed];
460 }
461
462 static void processDidCrash(WKPageRef page, const void* clientInfo)
463 {
464     WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
465     auto loadDelegate = browsingContext->_loadDelegate.get();
466
467     if ([loadDelegate respondsToSelector:@selector(browsingContextControllerWebProcessDidCrash:)])
468         [(id <WKBrowsingContextLoadDelegatePrivate>)loadDelegate browsingContextControllerWebProcessDidCrash:browsingContext];
469 }
470
471 static void setUpPageLoaderClient(WKBrowsingContextController *browsingContext, WebPageProxy& page)
472 {
473     WKPageLoaderClientV4 loaderClient;
474     memset(&loaderClient, 0, sizeof(loaderClient));
475
476     loaderClient.base.version = 4;
477     loaderClient.base.clientInfo = browsingContext;
478     loaderClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
479     loaderClient.didReceiveServerRedirectForProvisionalLoadForFrame = didReceiveServerRedirectForProvisionalLoadForFrame;
480     loaderClient.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrame;
481     loaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
482     loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
483     loaderClient.didFailLoadWithErrorForFrame = didFailLoadWithErrorForFrame;
484
485     loaderClient.canAuthenticateAgainstProtectionSpaceInFrame = canAuthenticateAgainstProtectionSpaceInFrame;
486     loaderClient.didReceiveAuthenticationChallengeInFrame = didReceiveAuthenticationChallengeInFrame;
487
488     loaderClient.didStartProgress = didStartProgress;
489     loaderClient.didChangeProgress = didChangeProgress;
490     loaderClient.didFinishProgress = didFinishProgress;
491     loaderClient.didChangeBackForwardList = didChangeBackForwardList;
492
493     loaderClient.processDidCrash = processDidCrash;
494
495     WKPageSetPageLoaderClient(toAPI(&page), &loaderClient.base);
496 }
497
498 static WKPolicyDecisionHandler makePolicyDecisionBlock(WKFramePolicyListenerRef listener)
499 {
500     WKRetain(listener); // Released in the decision handler below.
501
502     return [[^(WKPolicyDecision decision) {
503         switch (decision) {
504         case WKPolicyDecisionCancel:
505             WKFramePolicyListenerIgnore(listener);                    
506             break;
507         
508         case WKPolicyDecisionAllow:
509             WKFramePolicyListenerUse(listener);
510             break;
511         
512         case WKPolicyDecisionBecomeDownload:
513             WKFramePolicyListenerDownload(listener);
514             break;
515         };
516
517         WKRelease(listener); // Retained in the context above.
518     } copy] autorelease];
519 }
520
521 static void setUpPagePolicyClient(WKBrowsingContextController *browsingContext, WebPageProxy& page)
522 {
523     WKPagePolicyClientInternal policyClient;
524     memset(&policyClient, 0, sizeof(policyClient));
525
526     policyClient.base.version = 2;
527     policyClient.base.clientInfo = browsingContext;
528
529     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)
530     {
531         WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
532         auto policyDelegate = browsingContext->_policyDelegate.get();
533
534         if ([policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForNavigationAction:decisionHandler:)]) {
535             NSDictionary *actionDictionary = @{
536                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
537                 WKActionNavigationTypeKey: @(navigationType),
538                 WKActionModifierFlagsKey: @(modifiers),
539                 WKActionMouseButtonKey: @(mouseButton),
540                 WKActionOriginalURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(originalRequest)).get(),
541                 WKActionURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(request)).get()
542             };
543
544             if (originatingFrame) {
545                 actionDictionary = [[actionDictionary mutableCopy] autorelease];
546                 [(NSMutableDictionary *)actionDictionary setObject:[NSURL _web_URLWithWTFString:toImpl(originatingFrame)->url()] forKey:WKActionOriginatingFrameURLKey];
547             }
548             
549             [policyDelegate browsingContextController:browsingContext decidePolicyForNavigationAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
550         } else
551             WKFramePolicyListenerUse(listener);
552     };
553
554     policyClient.decidePolicyForNewWindowAction = [](WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKStringRef frameName, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
555     {
556         WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
557         auto policyDelegate = browsingContext->_policyDelegate.get();
558
559         if ([policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForNewWindowAction:decisionHandler:)]) {
560             NSDictionary *actionDictionary = @{
561                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
562                 WKActionNavigationTypeKey: @(navigationType),
563                 WKActionModifierFlagsKey: @(modifiers),
564                 WKActionMouseButtonKey: @(mouseButton),
565                 WKActionURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(request)).get(),
566                 WKActionFrameNameKey: toImpl(frameName)->wrapper()
567             };
568             
569             [policyDelegate browsingContextController:browsingContext decidePolicyForNewWindowAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
570         } else
571             WKFramePolicyListenerUse(listener);
572     };
573
574     policyClient.decidePolicyForResponse = [](WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
575     {
576         WKBrowsingContextController *browsingContext = (WKBrowsingContextController *)clientInfo;
577         auto policyDelegate = browsingContext->_policyDelegate.get();
578
579         if ([policyDelegate respondsToSelector:@selector(browsingContextController:decidePolicyForResponseAction:decisionHandler:)]) {
580             NSDictionary *actionDictionary = @{
581                 WKActionIsMainFrameKey: @(WKFrameIsMainFrame(frame)),
582                 WKActionURLRequestKey: adoptNS(WKURLRequestCopyNSURLRequest(request)).get(),
583                 WKActionURLResponseKey: adoptNS(WKURLResponseCopyNSURLResponse(response)).get(),
584                 WKActionCanShowMIMETypeKey: @(canShowMIMEType),
585             };
586
587             [policyDelegate browsingContextController:browsingContext decidePolicyForResponseAction:actionDictionary decisionHandler:makePolicyDecisionBlock(listener)];
588         } else
589             WKFramePolicyListenerUse(listener);
590     };
591
592     WKPageSetPagePolicyClient(toAPI(&page), &policyClient.base);
593 }
594
595 - (id <WKBrowsingContextLoadDelegate>)loadDelegate
596 {
597     return _loadDelegate.getAutoreleased();
598 }
599
600 - (void)setLoadDelegate:(id <WKBrowsingContextLoadDelegate>)loadDelegate
601 {
602     _loadDelegate = loadDelegate;
603
604     if (loadDelegate)
605         setUpPageLoaderClient(self, *_page);
606     else
607         WKPageSetPageLoaderClient(toAPI(_page.get()), nullptr);
608 }
609
610 - (id <WKBrowsingContextPolicyDelegate>)policyDelegate
611 {
612     return _policyDelegate.getAutoreleased();
613 }
614
615 - (void)setPolicyDelegate:(id <WKBrowsingContextPolicyDelegate>)policyDelegate
616 {
617     _policyDelegate = policyDelegate;
618
619     if (policyDelegate)
620         setUpPagePolicyClient(self, *_page);
621     else
622         WKPageSetPagePolicyClient(toAPI(_page.get()), nullptr);
623 }
624
625 - (id <WKBrowsingContextHistoryDelegate>)historyDelegate
626 {
627     return _historyDelegate.getAutoreleased();
628 }
629
630 - (void)setHistoryDelegate:(id <WKBrowsingContextHistoryDelegate>)historyDelegate
631 {
632     _historyDelegate = historyDelegate;
633 }
634
635 + (NSMutableSet *)customSchemes
636 {
637     static NSMutableSet *customSchemes = [[NSMutableSet alloc] init];
638     return customSchemes;
639 }
640
641 - (instancetype)_initWithPageRef:(WKPageRef)pageRef
642 {
643     if (!(self = [super init]))
644         return nil;
645
646     _page = toImpl(pageRef);
647
648     _pageLoadStateObserver = std::make_unique<PageLoadStateObserver>(self);
649     _page->pageLoadState().addObserver(*_pageLoadStateObserver);
650
651     ASSERT(!browsingContextControllerMap().contains(_page.get()));
652     browsingContextControllerMap().set(_page.get(), self);
653
654     return self;
655 }
656
657 + (WKBrowsingContextController *)_browsingContextControllerForPageRef:(WKPageRef)pageRef
658 {
659     return browsingContextControllerMap().get(toImpl(pageRef));
660 }
661
662 @end
663
664 @implementation WKBrowsingContextController (Private)
665
666 - (WKPageRef)_pageRef
667 {
668     return toAPI(_page.get());
669 }
670
671 - (void)setPaginationMode:(WKBrowsingContextPaginationMode)paginationMode
672 {
673     Pagination::Mode mode;
674     switch (paginationMode) {
675     case WKPaginationModeUnpaginated:
676         mode = Pagination::Unpaginated;
677         break;
678     case WKPaginationModeLeftToRight:
679         mode = Pagination::LeftToRightPaginated;
680         break;
681     case WKPaginationModeRightToLeft:
682         mode = Pagination::RightToLeftPaginated;
683         break;
684     case WKPaginationModeTopToBottom:
685         mode = Pagination::TopToBottomPaginated;
686         break;
687     case WKPaginationModeBottomToTop:
688         mode = Pagination::BottomToTopPaginated;
689         break;
690     default:
691         return;
692     }
693
694     _page->setPaginationMode(mode);
695 }
696
697 - (WKBrowsingContextPaginationMode)paginationMode
698 {
699     switch (_page->paginationMode()) {
700     case Pagination::Unpaginated:
701         return WKPaginationModeUnpaginated;
702     case Pagination::LeftToRightPaginated:
703         return WKPaginationModeLeftToRight;
704     case Pagination::RightToLeftPaginated:
705         return WKPaginationModeRightToLeft;
706     case Pagination::TopToBottomPaginated:
707         return WKPaginationModeTopToBottom;
708     case Pagination::BottomToTopPaginated:
709         return WKPaginationModeBottomToTop;
710     }
711
712     ASSERT_NOT_REACHED();
713     return WKPaginationModeUnpaginated;
714 }
715
716 - (void)setPaginationBehavesLikeColumns:(BOOL)behavesLikeColumns
717 {
718     _page->setPaginationBehavesLikeColumns(behavesLikeColumns);
719 }
720
721 - (BOOL)paginationBehavesLikeColumns
722 {
723     return _page->paginationBehavesLikeColumns();
724 }
725
726 - (void)setPageLength:(CGFloat)pageLength
727 {
728     _page->setPageLength(pageLength);
729 }
730
731 - (CGFloat)pageLength
732 {
733     return _page->pageLength();
734 }
735
736 - (void)setGapBetweenPages:(CGFloat)gapBetweenPages
737 {
738     _page->setGapBetweenPages(gapBetweenPages);
739 }
740
741 - (CGFloat)gapBetweenPages
742 {
743     return _page->gapBetweenPages();
744 }
745
746 - (NSUInteger)pageCount
747 {
748     return _page->pageCount();
749 }
750
751 - (WKBrowsingContextHandle *)handle
752 {
753     return [[[WKBrowsingContextHandle alloc] _initWithPageID:_page->pageID()] autorelease];
754 }
755
756 - (_WKRemoteObjectRegistry *)_remoteObjectRegistry
757 {
758 #if WK_API_ENABLED && !TARGET_OS_IPHONE
759     return _page->remoteObjectRegistry();
760 #else
761     return nil;
762 #endif
763 }
764
765 - (pid_t)processIdentifier
766 {
767     return _page->processIdentifier();
768 }
769
770 - (BOOL)_webProcessIsResponsive
771 {
772     return _page->process().responsivenessTimer().isResponsive();
773 }
774
775 @end
776
777 #endif // WK_API_ENABLED