Add UIDelegatePrivate SPI corresponding to WKPageUIClient.showPage
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / UIDelegate.mm
1 /*
2  * Copyright (C) 2014-2016 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 "UIDelegate.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIFrameInfo.h"
32 #import "CompletionHandlerCallChecker.h"
33 #import "NavigationActionData.h"
34 #import "UserMediaPermissionCheckProxy.h"
35 #import "UserMediaPermissionRequestProxy.h"
36 #import "WKFrameInfoInternal.h"
37 #import "WKNavigationActionInternal.h"
38 #import "WKOpenPanelParametersInternal.h"
39 #import "WKSecurityOriginInternal.h"
40 #import "WKUIDelegatePrivate.h"
41 #import "WKWebViewConfigurationInternal.h"
42 #import "WKWebViewInternal.h"
43 #import "WKWindowFeaturesInternal.h"
44 #import "WebOpenPanelResultListenerProxy.h"
45 #import "WebProcessProxy.h"
46 #import "_WKContextMenuElementInfo.h"
47 #import "_WKFrameHandleInternal.h"
48 #import <WebCore/SecurityOriginData.h>
49 #import <WebCore/URL.h>
50 #import <wtf/BlockPtr.h>
51
52 #if PLATFORM(IOS)
53 #import <AVFoundation/AVCaptureDevice.h>
54 #import <AVFoundation/AVMediaFormat.h>
55 #import <wtf/SoftLinking.h>
56
57 SOFT_LINK_FRAMEWORK(AVFoundation);
58 SOFT_LINK_CLASS(AVFoundation, AVCaptureDevice);
59 SOFT_LINK_CONSTANT(AVFoundation, AVMediaTypeAudio, NSString *);
60 SOFT_LINK_CONSTANT(AVFoundation, AVMediaTypeVideo, NSString *);
61 #endif
62
63 namespace WebKit {
64
65 UIDelegate::UIDelegate(WKWebView *webView)
66     : m_webView(webView)
67 {
68 }
69
70 UIDelegate::~UIDelegate()
71 {
72 }
73
74 #if ENABLE(CONTEXT_MENUS)
75 std::unique_ptr<API::ContextMenuClient> UIDelegate::createContextMenuClient()
76 {
77     return std::make_unique<ContextMenuClient>(*this);
78 }
79 #endif
80
81 std::unique_ptr<API::UIClient> UIDelegate::createUIClient()
82 {
83     return std::make_unique<UIClient>(*this);
84 }
85
86 RetainPtr<id <WKUIDelegate> > UIDelegate::delegate()
87 {
88     return m_delegate.get();
89 }
90
91 void UIDelegate::setDelegate(id <WKUIDelegate> delegate)
92 {
93     m_delegate = delegate;
94
95     m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures = [delegate respondsToSelector:@selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)];
96     m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync = [delegate respondsToSelector:@selector(_webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:)];
97     m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)];
98     m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
99     m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)];
100     m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
101
102 #if PLATFORM(MAC)
103     m_delegateMethods.webViewShow = [delegate respondsToSelector:@selector(_webViewShow:)];
104     m_delegateMethods.webViewRunOpenPanelWithParametersInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:)];
105 #endif
106
107     m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler = [delegate respondsToSelector:@selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:)];
108     m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded = [delegate respondsToSelector:@selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:)];
109     m_delegateMethods.webViewPrintFrame = [delegate respondsToSelector:@selector(_webView:printFrame:)];
110     m_delegateMethods.webViewDidClose = [delegate respondsToSelector:@selector(webViewDidClose:)];
111     m_delegateMethods.webViewClose = [delegate respondsToSelector:@selector(_webViewClose:)];
112     m_delegateMethods.webViewFullscreenMayReturnToInline = [delegate respondsToSelector:@selector(_webViewFullscreenMayReturnToInline:)];
113     m_delegateMethods.webViewDidEnterFullscreen = [delegate respondsToSelector:@selector(_webViewDidEnterFullscreen:)];
114     m_delegateMethods.webViewDidExitFullscreen = [delegate respondsToSelector:@selector(_webViewDidExitFullscreen:)];
115 #if PLATFORM(IOS)
116 #if HAVE(APP_LINKS)
117     m_delegateMethods.webViewShouldIncludeAppLinkActionsForElement = [delegate respondsToSelector:@selector(_webView:shouldIncludeAppLinkActionsForElement:)];
118 #endif
119     m_delegateMethods.webViewActionsForElementDefaultActions = [delegate respondsToSelector:@selector(_webView:actionsForElement:defaultActions:)];
120     m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint = [delegate respondsToSelector:@selector(_webView:didNotHandleTapAsClickAtPoint:)];
121     m_delegateMethods.presentingViewControllerForWebView = [delegate respondsToSelector:@selector(_presentingViewControllerForWebView:)];
122 #endif
123     m_delegateMethods.webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestUserMediaAuthorizationForDevices:url:mainFrameURL:decisionHandler:)];
124     m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler = [delegate respondsToSelector:@selector(_webView:checkUserMediaPermissionForURL:mainFrameURL:frameIdentifier:decisionHandler:)];
125     m_delegateMethods.webViewMediaCaptureStateDidChange = [delegate respondsToSelector:@selector(_webView:mediaCaptureStateDidChange:)];
126     m_delegateMethods.dataDetectionContextForWebView = [delegate respondsToSelector:@selector(_dataDetectionContextForWebView:)];
127     m_delegateMethods.webViewImageOrMediaDocumentSizeChanged = [delegate respondsToSelector:@selector(_webView:imageOrMediaDocumentSizeChanged:)];
128
129 #if ENABLE(POINTER_LOCK)
130     m_delegateMethods.webViewRequestPointerLock = [delegate respondsToSelector:@selector(_webViewRequestPointerLock:)];
131     m_delegateMethods.webViewDidLosePointerLock = [delegate respondsToSelector:@selector(_webViewDidLosePointerLock:)];
132 #endif
133 #if ENABLE(CONTEXT_MENUS)
134     m_delegateMethods.webViewContextMenuForElement = [delegate respondsToSelector:@selector(_webView:contextMenu:forElement:)];
135     m_delegateMethods.webViewContextMenuForElementUserInfo = [delegate respondsToSelector:@selector(_webView:contextMenu:forElement:userInfo:)];
136 #endif
137     
138     m_delegateMethods.webViewHasVideoInPictureInPictureDidChange = [delegate respondsToSelector:@selector(_webView:hasVideoInPictureInPictureDidChange:)];
139 }
140
141 #if ENABLE(CONTEXT_MENUS)
142 UIDelegate::ContextMenuClient::ContextMenuClient(UIDelegate& uiDelegate)
143     : m_uiDelegate(uiDelegate)
144 {
145 }
146
147 UIDelegate::ContextMenuClient::~ContextMenuClient()
148 {
149 }
150
151 RetainPtr<NSMenu> UIDelegate::ContextMenuClient::menuFromProposedMenu(WebKit::WebPageProxy&, NSMenu *menu, const WebKit::WebHitTestResultData&, API::Object* userInfo)
152 {
153     if (!m_uiDelegate.m_delegateMethods.webViewContextMenuForElement && !m_uiDelegate.m_delegateMethods.webViewContextMenuForElementUserInfo)
154         return menu;
155
156     auto delegate = m_uiDelegate.m_delegate.get();
157     if (!delegate)
158         return menu;
159
160     auto contextMenuElementInfo = adoptNS([[_WKContextMenuElementInfo alloc] init]);
161
162     if (m_uiDelegate.m_delegateMethods.webViewContextMenuForElement)
163         return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView contextMenu:menu forElement:contextMenuElementInfo.get()];
164
165     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView contextMenu:menu forElement:contextMenuElementInfo.get() userInfo:static_cast<id <NSSecureCoding>>(userInfo->wrapper())];
166 }
167 #endif
168
169 UIDelegate::UIClient::UIClient(UIDelegate& uiDelegate)
170     : m_uiDelegate(uiDelegate)
171 {
172 }
173
174 UIDelegate::UIClient::~UIClient()
175 {
176 }
177
178 RefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPageCommon(WebKit::WebPageProxy* page, API::FrameInfo& sourceFrameInfo, WebCore::ResourceRequest&& request, const WebCore::WindowFeatures& windowFeatures, WebKit::NavigationActionData&& navigationActionData, WTF::Function<void(RefPtr<WebKit::WebPageProxy>&&)>&& completionHandler)
179 {
180     auto delegate = m_uiDelegate.m_delegate.get();
181     ASSERT(delegate);
182
183     auto configuration = adoptNS([m_uiDelegate.m_webView->_configuration copy]);
184     [configuration _setRelatedWebView:m_uiDelegate.m_webView];
185
186     auto userInitiatedActivity = page->process().userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
187     bool shouldOpenAppLinks = !hostsAreEqual(sourceFrameInfo.request().url(), request.url());
188     auto apiNavigationAction = API::NavigationAction::create(WTFMove(navigationActionData), &sourceFrameInfo, nullptr, WTFMove(request), WebCore::URL(), shouldOpenAppLinks, WTFMove(userInitiatedActivity));
189
190     auto apiWindowFeatures = API::WindowFeatures::create(windowFeatures);
191
192     if (completionHandler) {
193         RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:));
194
195         [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:wrapper(apiNavigationAction) windowFeatures:wrapper(apiWindowFeatures) completionHandler:BlockPtr<void (WKWebView *)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker), relatedWebView = RetainPtr<WKWebView>(m_uiDelegate.m_webView)](WKWebView *webView) {
196             if (checker->completionHandlerHasBeenCalled())
197                 return;
198             checker->didCallCompletionHandler();
199
200             if (!webView) {
201                 completionHandler(nullptr);
202                 return;
203             }
204
205             if ([webView->_configuration _relatedWebView] != relatedWebView.get())
206                 [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."];
207
208             completionHandler(webView->_page.get());
209         }).get()];
210
211         return nullptr;
212     }
213
214     RetainPtr<WKWebView> webView = [delegate webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:wrapper(apiNavigationAction) windowFeatures:wrapper(apiWindowFeatures)];
215
216     if (!webView)
217         return nullptr;
218
219     if ([webView->_configuration _relatedWebView] != m_uiDelegate.m_webView)
220         [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."];
221
222     return webView->_page.get();
223 }
224
225 RefPtr<WebPageProxy> UIDelegate::UIClient::createNewPage(WebPageProxy* page, API::FrameInfo& originatingFrameInfo, WebCore::ResourceRequest&& request, const WebCore::WindowFeatures& windowFeatures, NavigationActionData&& navigationActionData)
226 {
227     if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures)
228         return nullptr;
229
230     auto delegate = m_uiDelegate.m_delegate.get();
231     if (!delegate)
232         return nullptr;
233
234     return createNewPageCommon(page, originatingFrameInfo, WTFMove(request), windowFeatures, WTFMove(navigationActionData), nullptr);
235 }
236
237 bool UIDelegate::UIClient::canCreateNewPageAsync()
238 {
239     return m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync
240         && m_uiDelegate.m_delegate.get();
241 }
242
243 void UIDelegate::UIClient::createNewPageAsync(WebPageProxy* page, API::FrameInfo& originatingFrameInfo, WebCore::ResourceRequest&& request, const WebCore::WindowFeatures& windowFeatures, NavigationActionData&& navigationActionData, WTF::Function<void(RefPtr<WebPageProxy>&&)>&& completionHandler)
244 {
245     ASSERT(canCreateNewPageAsync());
246     ASSERT(m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync);
247
248     auto delegate = m_uiDelegate.m_delegate.get();
249     ASSERT(delegate);
250
251     createNewPageCommon(page, originatingFrameInfo, WTFMove(request), windowFeatures, WTFMove(navigationActionData), WTFMove(completionHandler));
252 }
253
254 void UIDelegate::UIClient::runJavaScriptAlert(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void ()>&& completionHandler)
255 {
256     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler) {
257         completionHandler();
258         return;
259     }
260
261     auto delegate = m_uiDelegate.m_delegate.get();
262     if (!delegate) {
263         completionHandler();
264         return;
265     }
266
267     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:));
268     [delegate webView:m_uiDelegate.m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void ()>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)] {
269         if (checker->completionHandlerHasBeenCalled())
270             return;
271         completionHandler();
272         checker->didCallCompletionHandler();
273     }).get()];
274 }
275
276 void UIDelegate::UIClient::runJavaScriptConfirm(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void (bool)>&& completionHandler)
277 {
278     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler) {
279         completionHandler(false);
280         return;
281     }
282
283     auto delegate = m_uiDelegate.m_delegate.get();
284     if (!delegate) {
285         completionHandler(false);
286         return;
287     }
288
289     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
290     [delegate webView:m_uiDelegate.m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
291         if (checker->completionHandlerHasBeenCalled())
292             return;
293         completionHandler(result);
294         checker->didCallCompletionHandler();
295     }).get()];
296 }
297
298 void UIDelegate::UIClient::runJavaScriptPrompt(WebKit::WebPageProxy*, const WTF::String& message, const WTF::String& defaultValue, WebKit::WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void (const WTF::String&)>&& completionHandler)
299 {
300     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler) {
301         completionHandler(String());
302         return;
303     }
304
305     auto delegate = m_uiDelegate.m_delegate.get();
306     if (!delegate) {
307         completionHandler(String());
308         return;
309     }
310
311     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:));
312     [delegate webView:m_uiDelegate.m_webView runJavaScriptTextInputPanelWithPrompt:message defaultText:defaultValue initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (NSString *)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](NSString *result) {
313         if (checker->completionHandlerHasBeenCalled())
314             return;
315         completionHandler(result);
316         checker->didCallCompletionHandler();
317     }).get()];
318 }
319
320 bool UIDelegate::UIClient::canRunBeforeUnloadConfirmPanel() const
321 {
322     return m_uiDelegate.m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler;
323 }
324
325 void UIDelegate::UIClient::runBeforeUnloadConfirmPanel(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void (bool)>&& completionHandler)
326 {
327     if (!m_uiDelegate.m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler) {
328         completionHandler(false);
329         return;
330     }
331
332     auto delegate = m_uiDelegate.m_delegate.get();
333     if (!delegate) {
334         completionHandler(false);
335         return;
336     }
337
338     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
339     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView runBeforeUnloadConfirmPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
340         if (checker->completionHandlerHasBeenCalled())
341             return;
342         completionHandler(result);
343         checker->didCallCompletionHandler();
344     }).get()];
345 }
346
347 void UIDelegate::UIClient::exceededDatabaseQuota(WebPageProxy*, WebFrameProxy*, API::SecurityOrigin* securityOrigin, const WTF::String& databaseName, const WTF::String& displayName, unsigned long long currentQuota, unsigned long long currentOriginUsage, unsigned long long currentUsage, unsigned long long expectedUsage, Function<void (unsigned long long)>&& completionHandler)
348 {
349     if (!m_uiDelegate.m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler) {
350
351         // Use 50 MB as the default database quota.
352         unsigned long long defaultPerOriginDatabaseQuota = 50 * 1024 * 1024;
353
354         completionHandler(defaultPerOriginDatabaseQuota);
355         return;
356     }
357
358     auto delegate = m_uiDelegate.m_delegate.get();
359     if (!delegate) {
360         completionHandler(currentQuota);
361         return;
362     }
363
364     ASSERT(securityOrigin);
365     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:));
366     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideDatabaseQuotaForSecurityOrigin:wrapper(*securityOrigin) currentQuota:currentQuota currentOriginUsage:currentOriginUsage currentDatabaseUsage:currentUsage expectedUsage:expectedUsage decisionHandler:BlockPtr<void (unsigned long long newQuota)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
367         if (checker->completionHandlerHasBeenCalled())
368             return;
369         checker->didCallCompletionHandler();
370         completionHandler(newQuota);
371     }).get()];
372 }
373
374 #if PLATFORM(MAC)
375 void UIDelegate::UIClient::showPage(WebPageProxy*)
376 {
377     if (!m_uiDelegate.m_delegateMethods.webViewShow)
378         return;
379
380     auto delegate = m_uiDelegate.m_delegate.get();
381     if (!delegate)
382         return;
383     
384     [(id <WKUIDelegatePrivate>)delegate _webViewShow:m_uiDelegate.m_webView];
385 }
386
387 bool UIDelegate::UIClient::runOpenPanel(WebPageProxy*, WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, API::OpenPanelParameters* openPanelParameters, WebOpenPanelResultListenerProxy* listener)
388 {
389     if (!m_uiDelegate.m_delegateMethods.webViewRunOpenPanelWithParametersInitiatedByFrameCompletionHandler)
390         return false;
391
392     auto delegate = m_uiDelegate.m_delegate.get();
393     if (!delegate)
394         return false;
395
396     auto frame = API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin());
397     RefPtr<WebOpenPanelResultListenerProxy> resultListener = listener;
398
399     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:));
400
401     [delegate webView:m_uiDelegate.m_webView runOpenPanelWithParameters:wrapper(*openPanelParameters) initiatedByFrame:wrapper(frame) completionHandler:[checker, resultListener](NSArray *URLs) {
402         if (checker->completionHandlerHasBeenCalled())
403             return;
404         checker->didCallCompletionHandler();
405
406         if (!URLs) {
407             resultListener->cancel();
408             return;
409         }
410
411         Vector<String> filenames;
412         for (NSURL *url in URLs)
413             filenames.append(url.path);
414
415         resultListener->chooseFiles(filenames);
416     }];
417
418     return true;
419 }
420 #endif
421
422 static void requestUserMediaAuthorizationForDevices(const WebKit::WebFrameProxy& frame, WebKit::UserMediaPermissionRequestProxy& request, id <WKUIDelegatePrivate> delegate, WKWebView& webView)
423 {
424     auto decisionHandler = BlockPtr<void(BOOL)>::fromCallable([protectedRequest = makeRef(request)](BOOL authorized) {
425         if (!authorized) {
426             protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
427             return;
428         }
429         const String& videoDeviceUID = protectedRequest->requiresVideo() ? protectedRequest->videoDeviceUIDs().first() : String();
430         const String& audioDeviceUID = protectedRequest->requiresAudio() ? protectedRequest->audioDeviceUIDs().first() : String();
431         protectedRequest->allow(audioDeviceUID, videoDeviceUID);
432     });
433
434     const WebFrameProxy* mainFrame = frame.page()->mainFrame();
435     WebCore::URL requestFrameURL(WebCore::URL(), frame.url());
436     WebCore::URL mainFrameURL(WebCore::URL(), mainFrame->url());
437
438     _WKCaptureDevices devices = 0;
439     if (request.requiresAudio())
440         devices |= _WKCaptureDeviceMicrophone;
441     if (request.requiresVideo())
442         devices |= _WKCaptureDeviceCamera;
443
444     auto protectedWebView = RetainPtr<WKWebView>(&webView);
445     [delegate _webView:protectedWebView.get() requestUserMediaAuthorizationForDevices:devices url:requestFrameURL mainFrameURL:mainFrameURL decisionHandler:decisionHandler.get()];
446 }
447
448 bool UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest(WebKit::WebPageProxy& page, WebKit::WebFrameProxy& frame, API::SecurityOrigin& userMediaOrigin, API::SecurityOrigin& topLevelOrigin, WebKit::UserMediaPermissionRequestProxy& request)
449 {
450     auto delegate = m_uiDelegate.m_delegate.get();
451     if (!delegate || !m_uiDelegate.m_delegateMethods.webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler) {
452         request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::UserMediaDisabled);
453         return true;
454     }
455
456     bool requiresAudio = request.requiresAudio();
457     bool requiresVideo = request.requiresVideo();
458     if (!requiresAudio && !requiresVideo) {
459         request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints);
460         return true;
461     }
462
463 #if PLATFORM(IOS)
464     auto requestCameraAuthorization = BlockPtr<void()>::fromCallable([this, &frame, protectedRequest = makeRef(request), webView = RetainPtr<WKWebView>(m_uiDelegate.m_webView)]() {
465
466         if (!protectedRequest->requiresVideo()) {
467             requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
468             return;
469         }
470         AVAuthorizationStatus cameraAuthorizationStatus = [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeVideo()];
471         switch (cameraAuthorizationStatus) {
472         case AVAuthorizationStatusAuthorized:
473             requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
474             break;
475         case AVAuthorizationStatusDenied:
476         case AVAuthorizationStatusRestricted:
477             protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
478             return;
479         case AVAuthorizationStatusNotDetermined:
480             auto decisionHandler = BlockPtr<void(BOOL)>::fromCallable([this, &frame, protectedRequest = makeRef(protectedRequest.get()), webView = RetainPtr<WKWebView>(m_uiDelegate.m_webView)](BOOL authorized) {
481                 if (!authorized) {
482                     protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
483                     return;
484                 }
485                 requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
486             });
487
488             [getAVCaptureDeviceClass() requestAccessForMediaType:getAVMediaTypeVideo() completionHandler:decisionHandler.get()];
489             break;
490         }
491     });
492
493     if (requiresAudio) {
494         AVAuthorizationStatus microphoneAuthorizationStatus = [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeAudio()];
495         switch (microphoneAuthorizationStatus) {
496         case AVAuthorizationStatusAuthorized:
497             requestCameraAuthorization();
498             break;
499         case AVAuthorizationStatusDenied:
500         case AVAuthorizationStatusRestricted:
501             request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
502             return true;
503         case AVAuthorizationStatusNotDetermined:
504             auto decisionHandler = BlockPtr<void(BOOL)>::fromCallable([protectedRequest = makeRef(request), requestCameraAuthorization](BOOL authorized) {
505                 if (!authorized) {
506                     protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
507                     return;
508                 }
509                 requestCameraAuthorization();
510             });
511
512             [getAVCaptureDeviceClass() requestAccessForMediaType:getAVMediaTypeAudio() completionHandler:decisionHandler.get()];
513             break;
514         }
515     } else
516         requestCameraAuthorization();
517 #else
518     requestUserMediaAuthorizationForDevices(frame, request, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *m_uiDelegate.m_webView);
519 #endif
520
521     return true;
522 }
523
524 bool UIDelegate::UIClient::checkUserMediaPermissionForOrigin(WebKit::WebPageProxy& page, WebKit::WebFrameProxy& frame, API::SecurityOrigin& userMediaOrigin, API::SecurityOrigin& topLevelOrigin, WebKit::UserMediaPermissionCheckProxy& request)
525 {
526     auto delegate = m_uiDelegate.m_delegate.get();
527     if (!delegate || !m_uiDelegate.m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler) {
528         request.setUserMediaAccessInfo(String(), false);
529         return true;
530     }
531
532     WKWebView *webView = m_uiDelegate.m_webView;
533     const WebFrameProxy* mainFrame = frame.page()->mainFrame();
534     WebCore::URL requestFrameURL(WebCore::URL(), frame.url());
535     WebCore::URL mainFrameURL(WebCore::URL(), mainFrame->url());
536
537     auto decisionHandler = BlockPtr<void(NSString *, BOOL)>::fromCallable([protectedRequest = makeRef(request)](NSString *salt, BOOL authorized) {
538         protectedRequest->setUserMediaAccessInfo(String(salt), authorized);
539     });
540
541     [(id <WKUIDelegatePrivate>)delegate _webView:webView checkUserMediaPermissionForURL:requestFrameURL mainFrameURL:mainFrameURL frameIdentifier:frame.frameID() decisionHandler:decisionHandler.get()];
542
543     return true;
544 }
545
546 void UIDelegate::UIClient::mediaCaptureStateDidChange(WebCore::MediaProducer::MediaStateFlags state)
547 {
548     WKWebView *webView = m_uiDelegate.m_webView;
549     auto delegate = m_uiDelegate.m_delegate.get();
550     if (!delegate || !m_uiDelegate.m_delegateMethods.webViewMediaCaptureStateDidChange)
551         return;
552
553     _WKMediaCaptureState mediaCaptureState = _WKMediaCaptureStateNone;
554     if (state & WebCore::MediaProducer::HasActiveAudioCaptureDevice)
555         mediaCaptureState |= _WKMediaCaptureStateActiveMicrophone;
556     if (state & WebCore::MediaProducer::HasActiveVideoCaptureDevice)
557         mediaCaptureState |= _WKMediaCaptureStateActiveCamera;
558     if (state & WebCore::MediaProducer::HasMutedAudioCaptureDevice)
559         mediaCaptureState |= _WKMediaCaptureStateMutedMicrophone;
560     if (state & WebCore::MediaProducer::HasMutedVideoCaptureDevice)
561         mediaCaptureState |= _WKMediaCaptureStateMutedCamera;
562
563     [(id <WKUIDelegatePrivate>)delegate _webView:webView mediaCaptureStateDidChange:mediaCaptureState];
564 }
565
566 void UIDelegate::UIClient::reachedApplicationCacheOriginQuota(WebPageProxy*, const WebCore::SecurityOrigin& securityOrigin, uint64_t currentQuota, uint64_t totalBytesNeeded, Function<void (unsigned long long)>&& completionHandler)
567 {
568     if (!m_uiDelegate.m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded) {
569         completionHandler(currentQuota);
570         return;
571     }
572
573     auto delegate = m_uiDelegate.m_delegate.get();
574     if (!delegate) {
575         completionHandler(currentQuota);
576         return;
577     }
578
579     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:));
580     RefPtr<API::SecurityOrigin> apiOrigin = API::SecurityOrigin::create(securityOrigin);
581     
582     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideWebApplicationCacheQuotaForSecurityOrigin:wrapper(*apiOrigin) currentQuota:currentQuota totalBytesNeeded:totalBytesNeeded decisionHandler:BlockPtr<void (unsigned long long)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
583         if (checker->completionHandlerHasBeenCalled())
584             return;
585         checker->didCallCompletionHandler();
586         completionHandler(newQuota);
587     }).get()];
588 }
589
590 void UIDelegate::UIClient::printFrame(WebKit::WebPageProxy*, WebKit::WebFrameProxy* webFrameProxy)
591 {
592     ASSERT_ARG(webFrameProxy, webFrameProxy);
593
594     if (!m_uiDelegate.m_delegateMethods.webViewPrintFrame)
595         return;
596
597     auto delegate = m_uiDelegate.m_delegate.get();
598     if (!delegate)
599         return;
600
601     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView printFrame:wrapper(API::FrameHandle::create(webFrameProxy->frameID()))];
602 }
603
604 void UIDelegate::UIClient::close(WebKit::WebPageProxy*)
605 {
606     if (m_uiDelegate.m_delegateMethods.webViewClose) {
607         auto delegate = m_uiDelegate.m_delegate.get();
608         if (!delegate)
609             return;
610
611         [(id <WKUIDelegatePrivate>)delegate _webViewClose:m_uiDelegate.m_webView];
612         return;
613     }
614
615     if (!m_uiDelegate.m_delegateMethods.webViewDidClose)
616         return;
617
618     auto delegate = m_uiDelegate.m_delegate.get();
619     if (!delegate)
620         return;
621
622     [delegate webViewDidClose:m_uiDelegate.m_webView];
623 }
624
625 void UIDelegate::UIClient::fullscreenMayReturnToInline(WebKit::WebPageProxy*)
626 {
627     if (!m_uiDelegate.m_delegateMethods.webViewFullscreenMayReturnToInline)
628         return;
629     
630     auto delegate = m_uiDelegate.m_delegate.get();
631     if (!delegate)
632         return;
633     
634     [(id <WKUIDelegatePrivate>)delegate _webViewFullscreenMayReturnToInline:m_uiDelegate.m_webView];
635 }
636
637 void UIDelegate::UIClient::didEnterFullscreen(WebKit::WebPageProxy*)
638 {
639     if (!m_uiDelegate.m_delegateMethods.webViewDidEnterFullscreen)
640         return;
641
642     auto delegate = m_uiDelegate.m_delegate.get();
643     if (!delegate)
644         return;
645
646     [(id <WKUIDelegatePrivate>)delegate _webViewDidEnterFullscreen:m_uiDelegate.m_webView];
647 }
648
649 void UIDelegate::UIClient::didExitFullscreen(WebKit::WebPageProxy*)
650 {
651     if (!m_uiDelegate.m_delegateMethods.webViewDidExitFullscreen)
652         return;
653
654     auto delegate = m_uiDelegate.m_delegate.get();
655     if (!delegate)
656         return;
657
658     [(id <WKUIDelegatePrivate>)delegate _webViewDidExitFullscreen:m_uiDelegate.m_webView];
659 }
660     
661 #if PLATFORM(IOS)
662 #if HAVE(APP_LINKS)
663 bool UIDelegate::UIClient::shouldIncludeAppLinkActionsForElement(_WKActivatedElementInfo *elementInfo)
664 {
665     if (!m_uiDelegate.m_delegateMethods.webViewShouldIncludeAppLinkActionsForElement)
666         return true;
667
668     auto delegate = m_uiDelegate.m_delegate.get();
669     if (!delegate)
670         return true;
671
672     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView shouldIncludeAppLinkActionsForElement:elementInfo];
673 }
674 #endif
675
676 RetainPtr<NSArray> UIDelegate::UIClient::actionsForElement(_WKActivatedElementInfo *elementInfo, RetainPtr<NSArray> defaultActions)
677 {
678     if (!m_uiDelegate.m_delegateMethods.webViewActionsForElementDefaultActions)
679         return defaultActions;
680
681     auto delegate = m_uiDelegate.m_delegate.get();
682     if (!delegate)
683         return defaultActions;
684
685     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView actionsForElement:elementInfo defaultActions:defaultActions.get()];
686 }
687
688 void UIDelegate::UIClient::didNotHandleTapAsClick(const WebCore::IntPoint& point)
689 {
690     if (!m_uiDelegate.m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint)
691         return;
692
693     auto delegate = m_uiDelegate.m_delegate.get();
694     if (!delegate)
695         return;
696
697     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView didNotHandleTapAsClickAtPoint:point];
698 }
699
700 UIViewController *UIDelegate::UIClient::presentingViewController()
701 {
702     if (!m_uiDelegate.m_delegateMethods.presentingViewControllerForWebView)
703         return nullptr;
704
705     auto delegate = m_uiDelegate.m_delegate.get();
706     if (!delegate)
707         return nullptr;
708
709     return [static_cast<id <WKUIDelegatePrivate>>(delegate) _presentingViewControllerForWebView:m_uiDelegate.m_webView];
710 }
711
712 #endif
713
714 NSDictionary *UIDelegate::UIClient::dataDetectionContext()
715 {
716     if (!m_uiDelegate.m_delegateMethods.dataDetectionContextForWebView)
717         return nullptr;
718
719     auto delegate = m_uiDelegate.m_delegate.get();
720     if (!delegate)
721         return nullptr;
722
723     return [static_cast<id <WKUIDelegatePrivate>>(delegate) _dataDetectionContextForWebView:m_uiDelegate.m_webView];
724 }
725
726 #if ENABLE(POINTER_LOCK)
727
728 void UIDelegate::UIClient::requestPointerLock(WebKit::WebPageProxy*)
729 {
730     if (!m_uiDelegate.m_delegateMethods.webViewRequestPointerLock)
731         return;
732
733     auto delegate = m_uiDelegate.m_delegate.get();
734     if (!delegate)
735         return;
736
737     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webViewRequestPointerLock:m_uiDelegate.m_webView];
738 }
739
740 void UIDelegate::UIClient::didLosePointerLock(WebKit::WebPageProxy*)
741 {
742     if (!m_uiDelegate.m_delegateMethods.webViewDidLosePointerLock)
743         return;
744
745     auto delegate = m_uiDelegate.m_delegate.get();
746     if (!delegate)
747         return;
748
749     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webViewDidLosePointerLock:m_uiDelegate.m_webView];
750 }
751
752 #endif
753     
754 void UIDelegate::UIClient::hasVideoInPictureInPictureDidChange(WebKit::WebPageProxy*, bool hasVideoInPictureInPicture)
755 {
756     if (!m_uiDelegate.m_delegateMethods.webViewHasVideoInPictureInPictureDidChange)
757         return;
758     
759     auto delegate = m_uiDelegate.m_delegate.get();
760     if (!delegate)
761         return;
762     
763     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView hasVideoInPictureInPictureDidChange:hasVideoInPictureInPicture];
764 }
765
766 void UIDelegate::UIClient::imageOrMediaDocumentSizeChanged(const WebCore::IntSize& newSize)
767 {
768     if (!m_uiDelegate.m_delegateMethods.webViewImageOrMediaDocumentSizeChanged)
769         return;
770
771     auto delegate = m_uiDelegate.m_delegate.get();
772     if (!delegate)
773         return;
774
775     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView imageOrMediaDocumentSizeChanged:newSize];
776 }
777
778 } // namespace WebKit
779
780 #endif // WK_API_ENABLED