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