[MediaStream, iOS] Don't check authorizationStatusForMediaType when using mock captur...
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / UIDelegate.mm
1 /*
2  * Copyright (C) 2014-2018 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 "APIHitTestResult.h"
33 #import "CompletionHandlerCallChecker.h"
34 #import "NativeWebWheelEvent.h"
35 #import "NavigationActionData.h"
36 #import "UserMediaPermissionCheckProxy.h"
37 #import "UserMediaPermissionRequestProxy.h"
38 #import "WKFrameInfoInternal.h"
39 #import "WKNSData.h"
40 #import "WKNSDictionary.h"
41 #import "WKNavigationActionInternal.h"
42 #import "WKOpenPanelParametersInternal.h"
43 #import "WKSecurityOriginInternal.h"
44 #import "WKUIDelegatePrivate.h"
45 #import "WKWebViewConfigurationInternal.h"
46 #import "WKWebViewInternal.h"
47 #import "WKWindowFeaturesInternal.h"
48 #import "WebOpenPanelResultListenerProxy.h"
49 #import "WebProcessProxy.h"
50 #import "_WKContextMenuElementInfo.h"
51 #import "_WKFrameHandleInternal.h"
52 #import "_WKHitTestResultInternal.h"
53 #import <WebCore/SecurityOriginData.h>
54 #import <WebCore/URL.h>
55 #import <wtf/BlockPtr.h>
56
57 #if PLATFORM(IOS)
58 #import <AVFoundation/AVCaptureDevice.h>
59 #import <AVFoundation/AVMediaFormat.h>
60 #import <wtf/SoftLinking.h>
61
62 SOFT_LINK_FRAMEWORK(AVFoundation);
63 SOFT_LINK_CLASS(AVFoundation, AVCaptureDevice);
64 SOFT_LINK_CONSTANT(AVFoundation, AVMediaTypeAudio, NSString *);
65 SOFT_LINK_CONSTANT(AVFoundation, AVMediaTypeVideo, NSString *);
66 #endif
67
68 namespace WebKit {
69
70 UIDelegate::UIDelegate(WKWebView *webView)
71     : m_webView(webView)
72 {
73 }
74
75 UIDelegate::~UIDelegate()
76 {
77 }
78
79 #if ENABLE(CONTEXT_MENUS)
80 std::unique_ptr<API::ContextMenuClient> UIDelegate::createContextMenuClient()
81 {
82     return std::make_unique<ContextMenuClient>(*this);
83 }
84 #endif
85
86 std::unique_ptr<API::UIClient> UIDelegate::createUIClient()
87 {
88     return std::make_unique<UIClient>(*this);
89 }
90
91 RetainPtr<id <WKUIDelegate> > UIDelegate::delegate()
92 {
93     return m_delegate.get();
94 }
95
96 void UIDelegate::setDelegate(id <WKUIDelegate> delegate)
97 {
98     m_delegate = delegate;
99
100     m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures = [delegate respondsToSelector:@selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)];
101     m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync = [delegate respondsToSelector:@selector(_webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:)];
102     m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)];
103     m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
104     m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)];
105     m_delegateMethods.webViewRequestStorageAccessPanelForTopPrivatelyControlledDomainUnderFirstPartyTopPrivatelyControlledDomainCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:)];
106     m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
107     m_delegateMethods.webViewRequestGeolocationPermissionForFrameDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestGeolocationPermissionForFrame:decisionHandler:)];
108     m_delegateMethods.webViewDidResignInputElementStrongPasswordAppearanceWithUserInfo = [delegate respondsToSelector:@selector(_webView:didResignInputElementStrongPasswordAppearanceWithUserInfo:)];
109
110 #if PLATFORM(MAC)
111     m_delegateMethods.showWebView = [delegate respondsToSelector:@selector(_showWebView:)];
112     m_delegateMethods.focusWebView = [delegate respondsToSelector:@selector(_focusWebView:)];
113     m_delegateMethods.unfocusWebView = [delegate respondsToSelector:@selector(_unfocusWebView:)];
114     m_delegateMethods.webViewTakeFocus = [delegate respondsToSelector:@selector(_webView:takeFocus:)];
115     m_delegateMethods.webViewRunModal = [delegate respondsToSelector:@selector(_webViewRunModal:)];
116     m_delegateMethods.webViewDidScroll = [delegate respondsToSelector:@selector(_webViewDidScroll:)];
117     m_delegateMethods.webViewGetToolbarsAreVisibleWithCompletionHandler = [delegate respondsToSelector:@selector(_webView:getToolbarsAreVisibleWithCompletionHandler:)];
118     m_delegateMethods.webViewDidNotHandleWheelEvent = [delegate respondsToSelector:@selector(_webView:didNotHandleWheelEvent:)];
119     m_delegateMethods.webViewSetResizable = [delegate respondsToSelector:@selector(_webView:setResizable:)];
120     m_delegateMethods.webViewGetWindowFrameWithCompletionHandler = [delegate respondsToSelector:@selector(_webView:getWindowFrameWithCompletionHandler:)];
121     m_delegateMethods.webViewSetWindowFrame = [delegate respondsToSelector:@selector(_webView:setWindowFrame:)];
122     m_delegateMethods.webViewUnavailablePlugInButtonClicked = [delegate respondsToSelector:@selector(_webView:unavailablePlugInButtonClickedWithReason:plugInInfo:)];
123     m_delegateMethods.webViewHandleAutoplayEventWithFlags = [delegate respondsToSelector:@selector(_webView:handleAutoplayEvent:withFlags:)];
124     m_delegateMethods.webViewDidClickAutoFillButtonWithUserInfo = [delegate respondsToSelector:@selector(_webView:didClickAutoFillButtonWithUserInfo:)];
125     m_delegateMethods.webViewDrawHeaderInRectForPageWithTitleURL = [delegate respondsToSelector:@selector(_webView:drawHeaderInRect:forPageWithTitle:URL:)];
126     m_delegateMethods.webViewDrawFooterInRectForPageWithTitleURL = [delegate respondsToSelector:@selector(_webView:drawFooterInRect:forPageWithTitle:URL:)];
127     m_delegateMethods.webViewHeaderHeight = [delegate respondsToSelector:@selector(_webViewHeaderHeight:)];
128     m_delegateMethods.webViewFooterHeight = [delegate respondsToSelector:@selector(_webViewFooterHeight:)];
129     m_delegateMethods.webViewMouseDidMoveOverElementWithFlagsUserInfo = [delegate respondsToSelector:@selector(_webView:mouseDidMoveOverElement:withFlags:userInfo:)];
130     m_delegateMethods.webViewDidExceedBackgroundResourceLimitWhileInForeground = [delegate respondsToSelector:@selector(_webView:didExceedBackgroundResourceLimitWhileInForeground:)];
131     m_delegateMethods.webViewSaveDataToFileSuggestedFilenameMimeTypeOriginatingURL = [delegate respondsToSelector:@selector(_webView:saveDataToFile:suggestedFilename:mimeType:originatingURL:)];
132     m_delegateMethods.webViewRunOpenPanelWithParametersInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:)];
133     m_delegateMethods.webViewRequestNotificationPermissionForSecurityOriginDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestNotificationPermissionForSecurityOrigin:decisionHandler:)];
134 #endif
135     m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler = [delegate respondsToSelector:@selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:)];
136     m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded = [delegate respondsToSelector:@selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:)];
137     m_delegateMethods.webViewPrintFrame = [delegate respondsToSelector:@selector(_webView:printFrame:)];
138     m_delegateMethods.webViewDidClose = [delegate respondsToSelector:@selector(webViewDidClose:)];
139     m_delegateMethods.webViewClose = [delegate respondsToSelector:@selector(_webViewClose:)];
140     m_delegateMethods.webViewFullscreenMayReturnToInline = [delegate respondsToSelector:@selector(_webViewFullscreenMayReturnToInline:)];
141     m_delegateMethods.webViewDidEnterFullscreen = [delegate respondsToSelector:@selector(_webViewDidEnterFullscreen:)];
142     m_delegateMethods.webViewDidExitFullscreen = [delegate respondsToSelector:@selector(_webViewDidExitFullscreen:)];
143 #if PLATFORM(IOS)
144 #if HAVE(APP_LINKS)
145     m_delegateMethods.webViewShouldIncludeAppLinkActionsForElement = [delegate respondsToSelector:@selector(_webView:shouldIncludeAppLinkActionsForElement:)];
146 #endif
147     m_delegateMethods.webViewActionsForElementDefaultActions = [delegate respondsToSelector:@selector(_webView:actionsForElement:defaultActions:)];
148     m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint = [delegate respondsToSelector:@selector(_webView:didNotHandleTapAsClickAtPoint:)];
149     m_delegateMethods.presentingViewControllerForWebView = [delegate respondsToSelector:@selector(_presentingViewControllerForWebView:)];
150 #endif
151     m_delegateMethods.webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestUserMediaAuthorizationForDevices:url:mainFrameURL:decisionHandler:)];
152     m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler = [delegate respondsToSelector:@selector(_webView:checkUserMediaPermissionForURL:mainFrameURL:frameIdentifier:decisionHandler:)];
153     m_delegateMethods.webViewMediaCaptureStateDidChange = [delegate respondsToSelector:@selector(_webView:mediaCaptureStateDidChange:)];
154     m_delegateMethods.dataDetectionContextForWebView = [delegate respondsToSelector:@selector(_dataDetectionContextForWebView:)];
155     m_delegateMethods.webViewImageOrMediaDocumentSizeChanged = [delegate respondsToSelector:@selector(_webView:imageOrMediaDocumentSizeChanged:)];
156
157 #if ENABLE(POINTER_LOCK)
158     m_delegateMethods.webViewRequestPointerLock = [delegate respondsToSelector:@selector(_webViewRequestPointerLock:)];
159     m_delegateMethods.webViewDidLosePointerLock = [delegate respondsToSelector:@selector(_webViewDidLosePointerLock:)];
160 #endif
161 #if ENABLE(CONTEXT_MENUS)
162     m_delegateMethods.webViewContextMenuForElement = [delegate respondsToSelector:@selector(_webView:contextMenu:forElement:)];
163     m_delegateMethods.webViewContextMenuForElementUserInfo = [delegate respondsToSelector:@selector(_webView:contextMenu:forElement:userInfo:)];
164     m_delegateMethods.webViewGetContextMenuFromProposedMenuForElementUserInfoCompletionHandler = [delegate respondsToSelector:@selector(_webView:getContextMenuFromProposedMenu:forElement:userInfo:completionHandler:)];
165 #endif
166     
167     m_delegateMethods.webViewHasVideoInPictureInPictureDidChange = [delegate respondsToSelector:@selector(_webView:hasVideoInPictureInPictureDidChange:)];
168 }
169
170 #if ENABLE(CONTEXT_MENUS)
171 UIDelegate::ContextMenuClient::ContextMenuClient(UIDelegate& uiDelegate)
172     : m_uiDelegate(uiDelegate)
173 {
174 }
175
176 UIDelegate::ContextMenuClient::~ContextMenuClient()
177 {
178 }
179
180 void UIDelegate::ContextMenuClient::menuFromProposedMenu(WebPageProxy&, NSMenu *menu, const WebHitTestResultData&, API::Object* userInfo, CompletionHandler<void(RetainPtr<NSMenu>&&)>&& completionHandler)
181 {
182     if (!m_uiDelegate.m_delegateMethods.webViewContextMenuForElement
183         && !m_uiDelegate.m_delegateMethods.webViewContextMenuForElementUserInfo
184         && !m_uiDelegate.m_delegateMethods.webViewGetContextMenuFromProposedMenuForElementUserInfoCompletionHandler)
185         return completionHandler(menu);
186
187     auto delegate = m_uiDelegate.m_delegate.get();
188     if (!delegate)
189         return completionHandler(menu);
190
191     auto contextMenuElementInfo = adoptNS([[_WKContextMenuElementInfo alloc] init]);
192
193     if (m_uiDelegate.m_delegateMethods.webViewGetContextMenuFromProposedMenuForElementUserInfoCompletionHandler) {
194         auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:getContextMenuFromProposedMenu:forElement:userInfo:completionHandler:));
195         [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView getContextMenuFromProposedMenu:menu forElement:contextMenuElementInfo.get() userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil completionHandler:BlockPtr<void(NSMenu *)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)] (NSMenu *menu) {
196             if (checker->completionHandlerHasBeenCalled())
197                 return;
198             checker->didCallCompletionHandler();
199             completionHandler(menu);
200         }).get()];
201         return;
202     }
203     
204     if (m_uiDelegate.m_delegateMethods.webViewContextMenuForElement)
205         return completionHandler([(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView contextMenu:menu forElement:contextMenuElementInfo.get()]);
206
207     completionHandler([(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView contextMenu:menu forElement:contextMenuElementInfo.get() userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil]);
208 }
209 #endif
210
211 UIDelegate::UIClient::UIClient(UIDelegate& uiDelegate)
212     : m_uiDelegate(uiDelegate)
213 {
214 }
215
216 UIDelegate::UIClient::~UIClient()
217 {
218 }
219
220 void UIDelegate::UIClient::createNewPage(WebPageProxy& page, Ref<API::FrameInfo>&& sourceFrameInfo, WebCore::ResourceRequest&& request, WebCore::WindowFeatures&& windowFeatures, NavigationActionData&& navigationActionData, CompletionHandler<void(RefPtr<WebPageProxy>&&)>&& completionHandler)
221 {
222     auto delegate = m_uiDelegate.m_delegate.get();
223     ASSERT(delegate);
224
225     auto configuration = adoptNS([m_uiDelegate.m_webView->_configuration copy]);
226     [configuration _setRelatedWebView:m_uiDelegate.m_webView];
227
228     auto userInitiatedActivity = page.process().userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
229     bool shouldOpenAppLinks = !hostsAreEqual(sourceFrameInfo->request().url(), request.url());
230     auto apiNavigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.ptr(), nullptr, std::nullopt, WTFMove(request), WebCore::URL(), shouldOpenAppLinks, WTFMove(userInitiatedActivity));
231
232     auto apiWindowFeatures = API::WindowFeatures::create(windowFeatures);
233
234     if (m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeaturesAsync) {
235         auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:completionHandler:));
236
237         [(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) {
238             if (checker->completionHandlerHasBeenCalled())
239                 return;
240             checker->didCallCompletionHandler();
241
242             if (!webView) {
243                 completionHandler(nullptr);
244                 return;
245             }
246
247             if ([webView->_configuration _relatedWebView] != relatedWebView.get())
248                 [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."];
249
250             completionHandler(webView->_page.get());
251         }).get()];
252         return;
253     }
254     if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures)
255         return completionHandler(nullptr);
256
257     RetainPtr<WKWebView> webView = [delegate webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:wrapper(apiNavigationAction) windowFeatures:wrapper(apiWindowFeatures)];
258     if (!webView)
259         return completionHandler(nullptr);
260
261     if ([webView->_configuration _relatedWebView] != m_uiDelegate.m_webView)
262         [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."];
263     completionHandler(webView->_page.get());
264 }
265
266 void UIDelegate::UIClient::runJavaScriptAlert(WebPageProxy*, const WTF::String& message, WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void()>&& completionHandler)
267 {
268     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler) {
269         completionHandler();
270         return;
271     }
272
273     auto delegate = m_uiDelegate.m_delegate.get();
274     if (!delegate) {
275         completionHandler();
276         return;
277     }
278
279     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:));
280     [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)] {
281         if (checker->completionHandlerHasBeenCalled())
282             return;
283         completionHandler();
284         checker->didCallCompletionHandler();
285     }).get()];
286 }
287
288 void UIDelegate::UIClient::runJavaScriptConfirm(WebPageProxy*, const WTF::String& message, WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void(bool)>&& completionHandler)
289 {
290     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler) {
291         completionHandler(false);
292         return;
293     }
294
295     auto delegate = m_uiDelegate.m_delegate.get();
296     if (!delegate) {
297         completionHandler(false);
298         return;
299     }
300
301     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
302     [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) {
303         if (checker->completionHandlerHasBeenCalled())
304             return;
305         completionHandler(result);
306         checker->didCallCompletionHandler();
307     }).get()];
308 }
309
310 void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy*, const WTF::String& message, const WTF::String& defaultValue, WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void(const WTF::String&)>&& completionHandler)
311 {
312     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler) {
313         completionHandler(String());
314         return;
315     }
316
317     auto delegate = m_uiDelegate.m_delegate.get();
318     if (!delegate) {
319         completionHandler(String());
320         return;
321     }
322
323     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:));
324     [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) {
325         if (checker->completionHandlerHasBeenCalled())
326             return;
327         completionHandler(result);
328         checker->didCallCompletionHandler();
329     }).get()];
330 }
331
332 void UIDelegate::UIClient::requestStorageAccessConfirm(WebPageProxy&, WebFrameProxy*, const WTF::String& requestingDomain, const WTF::String& currentDomain, CompletionHandler<void(bool)>&& completionHandler)
333 {
334     if (!m_uiDelegate.m_delegateMethods.webViewRequestStorageAccessPanelForTopPrivatelyControlledDomainUnderFirstPartyTopPrivatelyControlledDomainCompletionHandler) {
335         completionHandler(true);
336         return;
337     }
338
339     auto delegate = m_uiDelegate.m_delegate.get();
340     if (!delegate) {
341         completionHandler(true);
342         return;
343     }
344     
345     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:));
346     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView requestStorageAccessPanelForDomain:requestingDomain underCurrentDomain:currentDomain completionHandler:BlockPtr<void(BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
347         if (checker->completionHandlerHasBeenCalled())
348             return;
349         completionHandler(result);
350         checker->didCallCompletionHandler();
351     }).get()];
352 }
353
354 void UIDelegate::UIClient::decidePolicyForGeolocationPermissionRequest(WebKit::WebPageProxy&, WebKit::WebFrameProxy& frame, API::SecurityOrigin& securityOrigin, Function<void(bool)>& completionHandler)
355 {
356     if (!m_uiDelegate.m_delegateMethods.webViewRequestGeolocationPermissionForFrameDecisionHandler)
357         return;
358     
359     auto delegate = m_uiDelegate.m_delegate.get();
360     if (!delegate)
361         return;
362
363     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:requestGeolocationPermissionForFrame:decisionHandler:));
364     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView requestGeolocationPermissionForFrame:wrapper(API::FrameInfo::create(frame, securityOrigin.securityOrigin())) decisionHandler:BlockPtr<void(BOOL)>::fromCallable([completionHandler = std::exchange(completionHandler, nullptr), checker = WTFMove(checker)](BOOL result) {
365         if (checker->completionHandlerHasBeenCalled())
366             return;
367         checker->didCallCompletionHandler();
368         completionHandler(result);
369     }).get()];
370 }
371
372 void UIDelegate::UIClient::didResignInputElementStrongPasswordAppearance(WebPageProxy&, API::Object* userInfo)
373 {
374     if (!m_uiDelegate.m_delegateMethods.webViewDidResignInputElementStrongPasswordAppearanceWithUserInfo)
375         return;
376
377     auto delegate = m_uiDelegate.m_delegate.get();
378     if (!delegate)
379         return;
380
381     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView didResignInputElementStrongPasswordAppearanceWithUserInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
382 }
383
384 bool UIDelegate::UIClient::canRunBeforeUnloadConfirmPanel() const
385 {
386     return m_uiDelegate.m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler;
387 }
388
389 void UIDelegate::UIClient::runBeforeUnloadConfirmPanel(WebPageProxy*, const WTF::String& message, WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, Function<void(bool)>&& completionHandler)
390 {
391     if (!m_uiDelegate.m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler) {
392         completionHandler(false);
393         return;
394     }
395
396     auto delegate = m_uiDelegate.m_delegate.get();
397     if (!delegate) {
398         completionHandler(false);
399         return;
400     }
401
402     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
403     [(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) {
404         if (checker->completionHandlerHasBeenCalled())
405             return;
406         completionHandler(result);
407         checker->didCallCompletionHandler();
408     }).get()];
409 }
410
411 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)
412 {
413     if (!m_uiDelegate.m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler) {
414
415         // Use 50 MB as the default database quota.
416         unsigned long long defaultPerOriginDatabaseQuota = 50 * 1024 * 1024;
417
418         completionHandler(defaultPerOriginDatabaseQuota);
419         return;
420     }
421
422     auto delegate = m_uiDelegate.m_delegate.get();
423     if (!delegate) {
424         completionHandler(currentQuota);
425         return;
426     }
427
428     ASSERT(securityOrigin);
429     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:));
430     [(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) {
431         if (checker->completionHandlerHasBeenCalled())
432             return;
433         checker->didCallCompletionHandler();
434         completionHandler(newQuota);
435     }).get()];
436 }
437
438 #if PLATFORM(MAC)
439 static inline _WKFocusDirection toWKFocusDirection(WKFocusDirection direction)
440 {
441     switch (direction) {
442     case kWKFocusDirectionBackward:
443         return _WKFocusDirectionBackward;
444     case kWKFocusDirectionForward:
445         return _WKFocusDirectionForward;
446     }
447     ASSERT_NOT_REACHED();
448     return _WKFocusDirectionForward;
449 }
450
451 void UIDelegate::UIClient::takeFocus(WebPageProxy*, WKFocusDirection direction)
452 {
453     if (!m_uiDelegate.m_delegateMethods.webViewTakeFocus)
454         return;
455     
456     auto delegate = m_uiDelegate.m_delegate.get();
457     if (!delegate)
458         return;
459     
460     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView takeFocus:toWKFocusDirection(direction)];
461 }
462
463 bool UIDelegate::UIClient::canRunModal() const
464 {
465     return m_uiDelegate.m_delegateMethods.webViewRunModal;
466 }
467
468 void UIDelegate::UIClient::runModal(WebPageProxy&)
469 {
470     if (!m_uiDelegate.m_delegateMethods.webViewRunModal)
471         return;
472     
473     auto delegate = m_uiDelegate.m_delegate.get();
474     if (!delegate)
475         return;
476
477     [(id <WKUIDelegatePrivate>)delegate _webViewRunModal:m_uiDelegate.m_webView];
478 }
479
480 float UIDelegate::UIClient::headerHeight(WebPageProxy&, WebFrameProxy& webFrameProxy)
481 {
482     if (!m_uiDelegate.m_delegateMethods.webViewHeaderHeight)
483         return 0;
484     
485     auto delegate = m_uiDelegate.m_delegate.get();
486     if (!delegate)
487         return 0;
488     
489     return [(id <WKUIDelegatePrivate>)delegate _webViewHeaderHeight:m_uiDelegate.m_webView];
490 }
491
492 float UIDelegate::UIClient::footerHeight(WebPageProxy&, WebFrameProxy&)
493 {
494     if (!m_uiDelegate.m_delegateMethods.webViewFooterHeight)
495         return 0;
496     
497     auto delegate = m_uiDelegate.m_delegate.get();
498     if (!delegate)
499         return 0;
500     
501     return [(id <WKUIDelegatePrivate>)delegate _webViewFooterHeight:m_uiDelegate.m_webView];
502 }
503
504 void UIDelegate::UIClient::drawHeader(WebPageProxy&, WebFrameProxy& frame, WebCore::FloatRect&& rect)
505 {
506     if (!m_uiDelegate.m_delegateMethods.webViewDrawHeaderInRectForPageWithTitleURL)
507         return;
508     
509     auto delegate = m_uiDelegate.m_delegate.get();
510     if (!delegate)
511         return;
512     
513     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView drawHeaderInRect:rect forPageWithTitle:frame.title() URL:frame.url()];
514 }
515
516 void UIDelegate::UIClient::drawFooter(WebPageProxy&, WebFrameProxy& frame, WebCore::FloatRect&& rect)
517 {
518     if (!m_uiDelegate.m_delegateMethods.webViewDrawFooterInRectForPageWithTitleURL)
519         return;
520     
521     auto delegate = m_uiDelegate.m_delegate.get();
522     if (!delegate)
523         return;
524     
525     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView drawFooterInRect:rect forPageWithTitle:frame.title() URL:frame.url()];
526 }
527
528 void UIDelegate::UIClient::pageDidScroll(WebPageProxy*)
529 {
530     if (!m_uiDelegate.m_delegateMethods.webViewDidScroll)
531         return;
532     
533     auto delegate = m_uiDelegate.m_delegate.get();
534     if (!delegate)
535         return;
536     
537     [(id <WKUIDelegatePrivate>)delegate _webViewDidScroll:m_uiDelegate.m_webView];
538 }
539
540 void UIDelegate::UIClient::focus(WebPageProxy*)
541 {
542     if (!m_uiDelegate.m_delegateMethods.focusWebView)
543         return;
544     
545     auto delegate = m_uiDelegate.m_delegate.get();
546     if (!delegate)
547         return;
548     
549     [(id <WKUIDelegatePrivate>)delegate _focusWebView:m_uiDelegate.m_webView];
550 }
551
552 void UIDelegate::UIClient::unfocus(WebPageProxy*)
553 {
554     if (!m_uiDelegate.m_delegateMethods.unfocusWebView)
555         return;
556     
557     auto delegate = m_uiDelegate.m_delegate.get();
558     if (!delegate)
559         return;
560     
561     [(id <WKUIDelegatePrivate>)delegate _unfocusWebView:m_uiDelegate.m_webView];
562 }
563
564 static _WKPlugInUnavailabilityReason toWKPlugInUnavailabilityReason(WKPluginUnavailabilityReason reason)
565 {
566     switch (reason) {
567     case kWKPluginUnavailabilityReasonPluginMissing:
568         return _WKPlugInUnavailabilityReasonPluginMissing;
569     case kWKPluginUnavailabilityReasonPluginCrashed:
570         return _WKPlugInUnavailabilityReasonPluginCrashed;
571     case kWKPluginUnavailabilityReasonInsecurePluginVersion:
572         return _WKPlugInUnavailabilityReasonInsecurePluginVersion;
573     }
574     ASSERT_NOT_REACHED();
575     return _WKPlugInUnavailabilityReasonPluginMissing;
576 }
577     
578 void UIDelegate::UIClient::unavailablePluginButtonClicked(WebPageProxy&, WKPluginUnavailabilityReason reason, API::Dictionary& plugInInfo)
579 {
580     if (!m_uiDelegate.m_delegateMethods.webViewUnavailablePlugInButtonClicked)
581         return;
582     
583     auto delegate = m_uiDelegate.m_delegate.get();
584     if (!delegate)
585         return;
586
587     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView unavailablePlugInButtonClickedWithReason:toWKPlugInUnavailabilityReason(reason) plugInInfo:wrapper(plugInInfo)];
588 }
589     
590 static _WKResourceLimit toWKResourceLimit(WKResourceLimit limit)
591 {
592     switch (limit) {
593     case kWKResourceLimitMemory:
594         return _WKResourceLimitMemory;
595     case kWKResourceLimitCPU:
596         return _WKResourceLimitCPU;
597     }
598     ASSERT_NOT_REACHED();
599     return _WKResourceLimitMemory;
600 }
601
602 void UIDelegate::UIClient::didExceedBackgroundResourceLimitWhileInForeground(WebPageProxy&, WKResourceLimit limit)
603 {
604     if (!m_uiDelegate.m_delegateMethods.webViewDidExceedBackgroundResourceLimitWhileInForeground)
605         return;
606     
607     auto delegate = m_uiDelegate.m_delegate.get();
608     if (!delegate)
609         return;
610     
611     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView didExceedBackgroundResourceLimitWhileInForeground:toWKResourceLimit(limit)];
612 }
613
614 void UIDelegate::UIClient::didNotHandleWheelEvent(WebPageProxy*, const NativeWebWheelEvent& event)
615 {
616     if (!m_uiDelegate.m_delegateMethods.webViewDidNotHandleWheelEvent)
617         return;
618     
619     auto delegate = m_uiDelegate.m_delegate.get();
620     if (!delegate)
621         return;
622     
623     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView didNotHandleWheelEvent:event.nativeEvent()];
624 }
625
626 void UIDelegate::UIClient::setIsResizable(WebKit::WebPageProxy&, bool resizable)
627 {
628     if (!m_uiDelegate.m_delegateMethods.webViewSetResizable)
629         return;
630     
631     auto delegate = m_uiDelegate.m_delegate.get();
632     if (!delegate)
633         return;
634     
635     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView setResizable:resizable];
636 }
637
638 void UIDelegate::UIClient::setWindowFrame(WebKit::WebPageProxy&, const WebCore::FloatRect& frame)
639 {
640     if (!m_uiDelegate.m_delegateMethods.webViewSetWindowFrame)
641         return;
642     
643     auto delegate = m_uiDelegate.m_delegate.get();
644     if (!delegate)
645         return;
646     
647     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView setWindowFrame:frame];
648 }
649
650 void UIDelegate::UIClient::windowFrame(WebKit::WebPageProxy&, Function<void(WebCore::FloatRect)>&& completionHandler)
651 {
652     if (!m_uiDelegate.m_delegateMethods.webViewGetWindowFrameWithCompletionHandler)
653         return completionHandler({ });
654     
655     auto delegate = m_uiDelegate.m_delegate.get();
656     if (!delegate)
657         return completionHandler({ });
658     
659     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView getWindowFrameWithCompletionHandler:BlockPtr<void(CGRect)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:getWindowFrameWithCompletionHandler:))](CGRect frame) {
660         if (checker->completionHandlerHasBeenCalled())
661             return;
662         checker->didCallCompletionHandler();
663         completionHandler(frame);
664     }).get()];
665 }
666
667 static NSEventModifierFlags toNSEventModifierFlags(WebEvent::Modifiers modifiers)
668 {
669     NSEventModifierFlags flags = 0;
670     if (modifiers & WebEvent::ShiftKey)
671         flags |= NSEventModifierFlagShift;
672     if (modifiers & WebEvent::ControlKey)
673         flags |= NSEventModifierFlagControl;
674     if (modifiers & WebEvent::AltKey)
675         flags |= NSEventModifierFlagOption;
676     if (modifiers & WebEvent::MetaKey)
677         flags |= NSEventModifierFlagCommand;
678     if (modifiers & WebEvent::CapsLockKey)
679         flags |= NSEventModifierFlagCapsLock;
680     return flags;
681 }
682
683 void UIDelegate::UIClient::mouseDidMoveOverElement(WebPageProxy&, const WebHitTestResultData& data, WebEvent::Modifiers modifiers, API::Object* userInfo)
684 {
685     if (!m_uiDelegate.m_delegateMethods.webViewMouseDidMoveOverElementWithFlagsUserInfo)
686         return;
687
688     auto delegate = m_uiDelegate.m_delegate.get();
689     if (!delegate)
690         return;
691
692     auto apiHitTestResult = API::HitTestResult::create(data);
693     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView mouseDidMoveOverElement:wrapper(apiHitTestResult.get()) withFlags:toNSEventModifierFlags(modifiers) userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
694 }
695
696 static _WKAutoplayEventFlags toWKAutoplayEventFlags(OptionSet<WebCore::AutoplayEventFlags> flags)
697 {
698     _WKAutoplayEventFlags wkFlags = _WKAutoplayEventFlagsNone;
699     if (flags.contains(WebCore::AutoplayEventFlags::HasAudio))
700         wkFlags |= _WKAutoplayEventFlagsHasAudio;
701     
702     return wkFlags;
703 }
704
705 static _WKAutoplayEvent toWKAutoplayEvent(WebCore::AutoplayEvent event)
706 {
707     switch (event) {
708     case WebCore::AutoplayEvent::DidPreventMediaFromPlaying:
709         return _WKAutoplayEventDidPreventFromAutoplaying;
710     case WebCore::AutoplayEvent::DidPlayMediaPreventedFromPlaying:
711         return _WKAutoplayEventDidPlayMediaPreventedFromAutoplaying;
712     case WebCore::AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference:
713         return _WKAutoplayEventDidAutoplayMediaPastThresholdWithoutUserInterference;
714     case WebCore::AutoplayEvent::UserDidInterfereWithPlayback:
715         return _WKAutoplayEventUserDidInterfereWithPlayback;
716     }
717     ASSERT_NOT_REACHED();
718     return _WKAutoplayEventDidPlayMediaPreventedFromAutoplaying;
719 }
720
721 void UIDelegate::UIClient::toolbarsAreVisible(WebPageProxy&, Function<void(bool)>&& completionHandler)
722 {
723     if (!m_uiDelegate.m_delegateMethods.webViewGetToolbarsAreVisibleWithCompletionHandler)
724         return completionHandler(true);
725     
726     auto delegate = m_uiDelegate.m_delegate.get();
727     if (!delegate)
728         return completionHandler(true);
729     
730     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView getToolbarsAreVisibleWithCompletionHandler:BlockPtr<void(BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:getToolbarsAreVisibleWithCompletionHandler:))](BOOL visible) {
731         if (checker->completionHandlerHasBeenCalled())
732             return;
733         checker->didCallCompletionHandler();
734         completionHandler(visible);
735     }).get()];
736 }
737
738 void UIDelegate::UIClient::didClickAutoFillButton(WebPageProxy&, API::Object* userInfo)
739 {
740     if (!m_uiDelegate.m_delegateMethods.webViewDidClickAutoFillButtonWithUserInfo)
741         return;
742     
743     auto delegate = m_uiDelegate.m_delegate.get();
744     if (!delegate)
745         return;
746     
747     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView didClickAutoFillButtonWithUserInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
748 }
749
750 void UIDelegate::UIClient::handleAutoplayEvent(WebPageProxy&, WebCore::AutoplayEvent event, OptionSet<WebCore::AutoplayEventFlags> flags)
751 {
752     if (!m_uiDelegate.m_delegateMethods.webViewHandleAutoplayEventWithFlags)
753         return;
754     
755     auto delegate = m_uiDelegate.m_delegate.get();
756     if (!delegate)
757         return;
758     
759     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView handleAutoplayEvent:toWKAutoplayEvent(event) withFlags:toWKAutoplayEventFlags(flags)];
760 }
761
762 void UIDelegate::UIClient::showPage(WebPageProxy*)
763 {
764     if (!m_uiDelegate.m_delegateMethods.showWebView)
765         return;
766
767     auto delegate = m_uiDelegate.m_delegate.get();
768     if (!delegate)
769         return;
770     
771     [(id <WKUIDelegatePrivate>)delegate _showWebView:m_uiDelegate.m_webView];
772 }
773     
774 void UIDelegate::UIClient::saveDataToFileInDownloadsFolder(WebPageProxy*, const WTF::String& suggestedFilename, const WTF::String& mimeType, const WebCore::URL& originatingURL, API::Data& data)
775 {
776     if (!m_uiDelegate.m_delegateMethods.webViewSaveDataToFileSuggestedFilenameMimeTypeOriginatingURL)
777         return;
778     
779     auto delegate = m_uiDelegate.m_delegate.get();
780     if (!delegate)
781         return;
782
783     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView saveDataToFile:wrapper(data) suggestedFilename:suggestedFilename mimeType:mimeType originatingURL:originatingURL];
784 }
785
786 void UIDelegate::UIClient::decidePolicyForNotificationPermissionRequest(WebKit::WebPageProxy&, API::SecurityOrigin& securityOrigin, WTF::Function<void(bool)>&& completionHandler)
787 {
788     if (!m_uiDelegate.m_delegateMethods.webViewRequestNotificationPermissionForSecurityOriginDecisionHandler)
789         return completionHandler(false);
790     
791     auto delegate = m_uiDelegate.m_delegate.get();
792     if (!delegate)
793         return completionHandler(false);
794
795     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:requestNotificationPermissionForSecurityOrigin:decisionHandler:));
796     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView requestNotificationPermissionForSecurityOrigin:wrapper(securityOrigin) decisionHandler:BlockPtr<void(BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
797         if (checker->completionHandlerHasBeenCalled())
798             return;
799         checker->didCallCompletionHandler();
800         completionHandler(result);
801     }).get()];
802 }
803
804 bool UIDelegate::UIClient::runOpenPanel(WebPageProxy*, WebFrameProxy* webFrameProxy, const WebCore::SecurityOriginData& securityOriginData, API::OpenPanelParameters* openPanelParameters, WebOpenPanelResultListenerProxy* listener)
805 {
806     if (!m_uiDelegate.m_delegateMethods.webViewRunOpenPanelWithParametersInitiatedByFrameCompletionHandler)
807         return false;
808
809     auto delegate = m_uiDelegate.m_delegate.get();
810     if (!delegate)
811         return false;
812
813     auto frame = API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin());
814     RefPtr<WebOpenPanelResultListenerProxy> resultListener = listener;
815
816     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:));
817
818     [delegate webView:m_uiDelegate.m_webView runOpenPanelWithParameters:wrapper(*openPanelParameters) initiatedByFrame:wrapper(frame) completionHandler:[checker, resultListener](NSArray *URLs) {
819         if (checker->completionHandlerHasBeenCalled())
820             return;
821         checker->didCallCompletionHandler();
822
823         if (!URLs) {
824             resultListener->cancel();
825             return;
826         }
827
828         Vector<String> filenames;
829         for (NSURL *url in URLs)
830             filenames.append(url.path);
831
832         resultListener->chooseFiles(filenames);
833     }];
834
835     return true;
836 }
837 #endif
838
839 #if ENABLE(MEDIA_STREAM)
840 static void requestUserMediaAuthorizationForDevices(const WebFrameProxy& frame, UserMediaPermissionRequestProxy& request, id <WKUIDelegatePrivate> delegate, WKWebView& webView)
841 {
842     auto decisionHandler = BlockPtr<void(BOOL)>::fromCallable([protectedRequest = makeRef(request)](BOOL authorized) {
843         if (!authorized) {
844             protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
845             return;
846         }
847         const String& videoDeviceUID = (protectedRequest->requiresVideoCapture() || protectedRequest->requiresDisplayCapture()) ? protectedRequest->videoDeviceUIDs().first() : String();
848         const String& audioDeviceUID = protectedRequest->requiresAudioCapture() ? protectedRequest->audioDeviceUIDs().first() : String();
849         protectedRequest->allow(audioDeviceUID, videoDeviceUID);
850     });
851
852     const WebFrameProxy* mainFrame = frame.page()->mainFrame();
853     WebCore::URL requestFrameURL(WebCore::URL(), frame.url());
854     WebCore::URL mainFrameURL(WebCore::URL(), mainFrame->url());
855
856     _WKCaptureDevices devices = 0;
857     if (request.requiresAudioCapture())
858         devices |= _WKCaptureDeviceMicrophone;
859     if (request.requiresVideoCapture())
860         devices |= _WKCaptureDeviceCamera;
861     if (request.requiresDisplayCapture()) {
862         devices |= _WKCaptureDeviceDisplay;
863         ASSERT(!(devices & _WKCaptureDeviceCamera));
864     }
865
866     auto protectedWebView = RetainPtr<WKWebView>(&webView);
867     [delegate _webView:protectedWebView.get() requestUserMediaAuthorizationForDevices:devices url:requestFrameURL mainFrameURL:mainFrameURL decisionHandler:decisionHandler.get()];
868 }
869 #endif
870
871 bool UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest(WebPageProxy& page, WebFrameProxy& frame, API::SecurityOrigin& userMediaOrigin, API::SecurityOrigin& topLevelOrigin, UserMediaPermissionRequestProxy& request)
872 {
873 #if ENABLE(MEDIA_STREAM)
874     auto delegate = m_uiDelegate.m_delegate.get();
875     if (!delegate || !m_uiDelegate.m_delegateMethods.webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler) {
876         request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::UserMediaDisabled);
877         return true;
878     }
879
880     bool requiresAudioCapture = request.requiresAudioCapture();
881     bool requiresVideoCapture = request.requiresVideoCapture();
882     bool requiresDisplayCapture = request.requiresDisplayCapture();
883     if (!requiresAudioCapture && !requiresVideoCapture && !requiresDisplayCapture) {
884         request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints);
885         return true;
886     }
887
888 #if PLATFORM(IOS)
889     bool usingMockCaptureDevices = page.preferences().mockCaptureDevicesEnabled();
890     auto requestCameraAuthorization = BlockPtr<void()>::fromCallable([this, &frame, protectedRequest = makeRef(request), webView = RetainPtr<WKWebView>(m_uiDelegate.m_webView), usingMockCaptureDevices]() {
891
892         if (!protectedRequest->requiresVideoCapture()) {
893             requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
894             return;
895         }
896         AVAuthorizationStatus cameraAuthorizationStatus = usingMockCaptureDevices ? AVAuthorizationStatusAuthorized : [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeVideo()];
897         switch (cameraAuthorizationStatus) {
898         case AVAuthorizationStatusAuthorized:
899             requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
900             break;
901         case AVAuthorizationStatusDenied:
902         case AVAuthorizationStatusRestricted:
903             protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
904             return;
905         case AVAuthorizationStatusNotDetermined:
906             auto decisionHandler = BlockPtr<void(BOOL)>::fromCallable([this, &frame, protectedRequest = makeRef(protectedRequest.get()), webView = RetainPtr<WKWebView>(m_uiDelegate.m_webView)](BOOL authorized) {
907                 if (!authorized) {
908                     protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
909                     return;
910                 }
911                 requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
912             });
913
914             [getAVCaptureDeviceClass() requestAccessForMediaType:getAVMediaTypeVideo() completionHandler:decisionHandler.get()];
915             break;
916         }
917     });
918
919     if (requiresAudioCapture) {
920         AVAuthorizationStatus microphoneAuthorizationStatus = usingMockCaptureDevices ? AVAuthorizationStatusAuthorized : [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeAudio()];
921         switch (microphoneAuthorizationStatus) {
922         case AVAuthorizationStatusAuthorized:
923             requestCameraAuthorization();
924             break;
925         case AVAuthorizationStatusDenied:
926         case AVAuthorizationStatusRestricted:
927             request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
928             return true;
929         case AVAuthorizationStatusNotDetermined:
930             auto decisionHandler = BlockPtr<void(BOOL)>::fromCallable([protectedRequest = makeRef(request), requestCameraAuthorization](BOOL authorized) {
931                 if (!authorized) {
932                     protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
933                     return;
934                 }
935                 requestCameraAuthorization();
936             });
937
938             [getAVCaptureDeviceClass() requestAccessForMediaType:getAVMediaTypeAudio() completionHandler:decisionHandler.get()];
939             break;
940         }
941     } else
942         requestCameraAuthorization();
943 #else
944     requestUserMediaAuthorizationForDevices(frame, request, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *m_uiDelegate.m_webView);
945 #endif
946 #endif
947
948     return true;
949 }
950
951 bool UIDelegate::UIClient::checkUserMediaPermissionForOrigin(WebPageProxy& page, WebFrameProxy& frame, API::SecurityOrigin& userMediaOrigin, API::SecurityOrigin& topLevelOrigin, UserMediaPermissionCheckProxy& request)
952 {
953     auto delegate = m_uiDelegate.m_delegate.get();
954     if (!delegate || !m_uiDelegate.m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler) {
955         request.setUserMediaAccessInfo(String(), false);
956         return true;
957     }
958
959     WKWebView *webView = m_uiDelegate.m_webView;
960     const WebFrameProxy* mainFrame = frame.page()->mainFrame();
961     WebCore::URL requestFrameURL(WebCore::URL(), frame.url());
962     WebCore::URL mainFrameURL(WebCore::URL(), mainFrame->url());
963
964     auto decisionHandler = BlockPtr<void(NSString *, BOOL)>::fromCallable([protectedRequest = makeRef(request)](NSString *salt, BOOL authorized) {
965         protectedRequest->setUserMediaAccessInfo(String(salt), authorized);
966     });
967
968     [(id <WKUIDelegatePrivate>)delegate _webView:webView checkUserMediaPermissionForURL:requestFrameURL mainFrameURL:mainFrameURL frameIdentifier:frame.frameID() decisionHandler:decisionHandler.get()];
969
970     return true;
971 }
972
973 void UIDelegate::UIClient::mediaCaptureStateDidChange(WebCore::MediaProducer::MediaStateFlags state)
974 {
975     WKWebView *webView = m_uiDelegate.m_webView;
976     auto delegate = m_uiDelegate.m_delegate.get();
977     if (!delegate || !m_uiDelegate.m_delegateMethods.webViewMediaCaptureStateDidChange)
978         return;
979
980     _WKMediaCaptureState mediaCaptureState = _WKMediaCaptureStateNone;
981     if (state & WebCore::MediaProducer::HasActiveAudioCaptureDevice)
982         mediaCaptureState |= _WKMediaCaptureStateActiveMicrophone;
983     if (state & WebCore::MediaProducer::HasActiveVideoCaptureDevice)
984         mediaCaptureState |= _WKMediaCaptureStateActiveCamera;
985     if (state & WebCore::MediaProducer::HasMutedAudioCaptureDevice)
986         mediaCaptureState |= _WKMediaCaptureStateMutedMicrophone;
987     if (state & WebCore::MediaProducer::HasMutedVideoCaptureDevice)
988         mediaCaptureState |= _WKMediaCaptureStateMutedCamera;
989
990     [(id <WKUIDelegatePrivate>)delegate _webView:webView mediaCaptureStateDidChange:mediaCaptureState];
991 }
992
993 void UIDelegate::UIClient::reachedApplicationCacheOriginQuota(WebPageProxy*, const WebCore::SecurityOrigin& securityOrigin, uint64_t currentQuota, uint64_t totalBytesNeeded, Function<void (unsigned long long)>&& completionHandler)
994 {
995     if (!m_uiDelegate.m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded) {
996         completionHandler(currentQuota);
997         return;
998     }
999
1000     auto delegate = m_uiDelegate.m_delegate.get();
1001     if (!delegate) {
1002         completionHandler(currentQuota);
1003         return;
1004     }
1005
1006     auto checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:));
1007     auto apiOrigin = API::SecurityOrigin::create(securityOrigin);
1008     
1009     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideWebApplicationCacheQuotaForSecurityOrigin:wrapper(apiOrigin.get()) currentQuota:currentQuota totalBytesNeeded:totalBytesNeeded decisionHandler:BlockPtr<void(unsigned long long)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
1010         if (checker->completionHandlerHasBeenCalled())
1011             return;
1012         checker->didCallCompletionHandler();
1013         completionHandler(newQuota);
1014     }).get()];
1015 }
1016
1017 void UIDelegate::UIClient::printFrame(WebPageProxy&, WebFrameProxy& webFrameProxy)
1018 {
1019     if (!m_uiDelegate.m_delegateMethods.webViewPrintFrame)
1020         return;
1021
1022     auto delegate = m_uiDelegate.m_delegate.get();
1023     if (!delegate)
1024         return;
1025
1026     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView printFrame:wrapper(API::FrameHandle::create(webFrameProxy.frameID()))];
1027 }
1028
1029 void UIDelegate::UIClient::close(WebPageProxy*)
1030 {
1031     if (m_uiDelegate.m_delegateMethods.webViewClose) {
1032         auto delegate = m_uiDelegate.m_delegate.get();
1033         if (!delegate)
1034             return;
1035
1036         [(id <WKUIDelegatePrivate>)delegate _webViewClose:m_uiDelegate.m_webView];
1037         return;
1038     }
1039
1040     if (!m_uiDelegate.m_delegateMethods.webViewDidClose)
1041         return;
1042
1043     auto delegate = m_uiDelegate.m_delegate.get();
1044     if (!delegate)
1045         return;
1046
1047     [delegate webViewDidClose:m_uiDelegate.m_webView];
1048 }
1049
1050 void UIDelegate::UIClient::fullscreenMayReturnToInline(WebPageProxy*)
1051 {
1052     if (!m_uiDelegate.m_delegateMethods.webViewFullscreenMayReturnToInline)
1053         return;
1054     
1055     auto delegate = m_uiDelegate.m_delegate.get();
1056     if (!delegate)
1057         return;
1058     
1059     [(id <WKUIDelegatePrivate>)delegate _webViewFullscreenMayReturnToInline:m_uiDelegate.m_webView];
1060 }
1061
1062 void UIDelegate::UIClient::didEnterFullscreen(WebPageProxy*)
1063 {
1064     if (!m_uiDelegate.m_delegateMethods.webViewDidEnterFullscreen)
1065         return;
1066
1067     auto delegate = m_uiDelegate.m_delegate.get();
1068     if (!delegate)
1069         return;
1070
1071     [(id <WKUIDelegatePrivate>)delegate _webViewDidEnterFullscreen:m_uiDelegate.m_webView];
1072 }
1073
1074 void UIDelegate::UIClient::didExitFullscreen(WebPageProxy*)
1075 {
1076     if (!m_uiDelegate.m_delegateMethods.webViewDidExitFullscreen)
1077         return;
1078
1079     auto delegate = m_uiDelegate.m_delegate.get();
1080     if (!delegate)
1081         return;
1082
1083     [(id <WKUIDelegatePrivate>)delegate _webViewDidExitFullscreen:m_uiDelegate.m_webView];
1084 }
1085     
1086 #if PLATFORM(IOS)
1087 #if HAVE(APP_LINKS)
1088 bool UIDelegate::UIClient::shouldIncludeAppLinkActionsForElement(_WKActivatedElementInfo *elementInfo)
1089 {
1090     if (!m_uiDelegate.m_delegateMethods.webViewShouldIncludeAppLinkActionsForElement)
1091         return true;
1092
1093     auto delegate = m_uiDelegate.m_delegate.get();
1094     if (!delegate)
1095         return true;
1096
1097     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView shouldIncludeAppLinkActionsForElement:elementInfo];
1098 }
1099 #endif
1100
1101 RetainPtr<NSArray> UIDelegate::UIClient::actionsForElement(_WKActivatedElementInfo *elementInfo, RetainPtr<NSArray> defaultActions)
1102 {
1103     if (!m_uiDelegate.m_delegateMethods.webViewActionsForElementDefaultActions)
1104         return defaultActions;
1105
1106     auto delegate = m_uiDelegate.m_delegate.get();
1107     if (!delegate)
1108         return defaultActions;
1109
1110     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView actionsForElement:elementInfo defaultActions:defaultActions.get()];
1111 }
1112
1113 void UIDelegate::UIClient::didNotHandleTapAsClick(const WebCore::IntPoint& point)
1114 {
1115     if (!m_uiDelegate.m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint)
1116         return;
1117
1118     auto delegate = m_uiDelegate.m_delegate.get();
1119     if (!delegate)
1120         return;
1121
1122     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView didNotHandleTapAsClickAtPoint:point];
1123 }
1124
1125 UIViewController *UIDelegate::UIClient::presentingViewController()
1126 {
1127     if (!m_uiDelegate.m_delegateMethods.presentingViewControllerForWebView)
1128         return nullptr;
1129
1130     auto delegate = m_uiDelegate.m_delegate.get();
1131     if (!delegate)
1132         return nullptr;
1133
1134     return [static_cast<id <WKUIDelegatePrivate>>(delegate) _presentingViewControllerForWebView:m_uiDelegate.m_webView];
1135 }
1136
1137 #endif
1138
1139 NSDictionary *UIDelegate::UIClient::dataDetectionContext()
1140 {
1141     if (!m_uiDelegate.m_delegateMethods.dataDetectionContextForWebView)
1142         return nullptr;
1143
1144     auto delegate = m_uiDelegate.m_delegate.get();
1145     if (!delegate)
1146         return nullptr;
1147
1148     return [static_cast<id <WKUIDelegatePrivate>>(delegate) _dataDetectionContextForWebView:m_uiDelegate.m_webView];
1149 }
1150
1151 #if ENABLE(POINTER_LOCK)
1152
1153 void UIDelegate::UIClient::requestPointerLock(WebPageProxy*)
1154 {
1155     if (!m_uiDelegate.m_delegateMethods.webViewRequestPointerLock)
1156         return;
1157
1158     auto delegate = m_uiDelegate.m_delegate.get();
1159     if (!delegate)
1160         return;
1161
1162     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webViewRequestPointerLock:m_uiDelegate.m_webView];
1163 }
1164
1165 void UIDelegate::UIClient::didLosePointerLock(WebPageProxy*)
1166 {
1167     if (!m_uiDelegate.m_delegateMethods.webViewDidLosePointerLock)
1168         return;
1169
1170     auto delegate = m_uiDelegate.m_delegate.get();
1171     if (!delegate)
1172         return;
1173
1174     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webViewDidLosePointerLock:m_uiDelegate.m_webView];
1175 }
1176
1177 #endif
1178     
1179 void UIDelegate::UIClient::hasVideoInPictureInPictureDidChange(WebPageProxy*, bool hasVideoInPictureInPicture)
1180 {
1181     if (!m_uiDelegate.m_delegateMethods.webViewHasVideoInPictureInPictureDidChange)
1182         return;
1183     
1184     auto delegate = m_uiDelegate.m_delegate.get();
1185     if (!delegate)
1186         return;
1187     
1188     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView hasVideoInPictureInPictureDidChange:hasVideoInPictureInPicture];
1189 }
1190
1191 void UIDelegate::UIClient::imageOrMediaDocumentSizeChanged(const WebCore::IntSize& newSize)
1192 {
1193     if (!m_uiDelegate.m_delegateMethods.webViewImageOrMediaDocumentSizeChanged)
1194         return;
1195
1196     auto delegate = m_uiDelegate.m_delegate.get();
1197     if (!delegate)
1198         return;
1199
1200     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView imageOrMediaDocumentSizeChanged:newSize];
1201 }
1202
1203 } // namespace WebKit
1204
1205 #endif // WK_API_ENABLED