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