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