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