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