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