Notify the UI delegate when a MediaDocument's natural size changes
[WebKit-https.git] / Source / WebKit2 / UIProcess / Cocoa / UIDelegate.mm
1 /*
2  * Copyright (C) 2014 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 "CompletionHandlerCallChecker.h"
32 #import "NavigationActionData.h"
33 #import "SecurityOriginData.h"
34 #import "WKFrameInfoInternal.h"
35 #import "WKNavigationActionInternal.h"
36 #import "WKSecurityOriginInternal.h"
37 #import "WKWebViewConfigurationInternal.h"
38 #import "WKWebViewInternal.h"
39 #import "WKWindowFeaturesInternal.h"
40 #import "WKUIDelegatePrivate.h"
41 #import "_WKFrameHandleInternal.h"
42 #import <WebCore/URL.h>
43
44 namespace WebKit {
45
46 UIDelegate::UIDelegate(WKWebView *webView)
47     : m_webView(webView)
48 {
49 }
50
51 UIDelegate::~UIDelegate()
52 {
53 }
54
55 std::unique_ptr<API::UIClient> UIDelegate::createUIClient()
56 {
57     return std::make_unique<UIClient>(*this);
58 }
59
60 RetainPtr<id <WKUIDelegate> > UIDelegate::delegate()
61 {
62     return m_delegate.get();
63 }
64
65 void UIDelegate::setDelegate(id <WKUIDelegate> delegate)
66 {
67     m_delegate = delegate;
68
69     m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures = [delegate respondsToSelector:@selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)];
70     m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)];
71     m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
72     m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)];
73     m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler = [delegate respondsToSelector:@selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:)];
74     m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded = [delegate respondsToSelector:@selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:)];
75     m_delegateMethods.webViewPrintFrame = [delegate respondsToSelector:@selector(_webView:printFrame:)];
76     m_delegateMethods.webViewDidClose = [delegate respondsToSelector:@selector(webViewDidClose:)];
77     m_delegateMethods.webViewClose = [delegate respondsToSelector:@selector(_webViewClose:)];
78     m_delegateMethods.webViewFullscreenMayReturnToInline = [delegate respondsToSelector:@selector(_webViewFullscreenMayReturnToInline:)];
79     m_delegateMethods.webViewDidEnterFullscreen = [delegate respondsToSelector:@selector(_webViewDidEnterFullscreen:)];
80     m_delegateMethods.webViewDidExitFullscreen = [delegate respondsToSelector:@selector(_webViewDidExitFullscreen:)];
81 #if PLATFORM(IOS)
82 #if HAVE(APP_LINKS)
83     m_delegateMethods.webViewShouldIncludeAppLinkActionsForElement = [delegate respondsToSelector:@selector(_webView:shouldIncludeAppLinkActionsForElement:)];
84 #endif
85     m_delegateMethods.webViewActionsForElementDefaultActions = [delegate respondsToSelector:@selector(_webView:actionsForElement:defaultActions:)];
86     m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint = [delegate respondsToSelector:@selector(_webView:didNotHandleTapAsClickAtPoint:)];
87 #endif
88 #if ENABLE(VIDEO)
89     m_delegateMethods.webViewMediaDocumentNaturalSizeChanged = [delegate respondsToSelector:@selector(_webView:mediaDocumentNaturalSizeChanged:)];
90 #endif
91 }
92
93 UIDelegate::UIClient::UIClient(UIDelegate& uiDelegate)
94     : m_uiDelegate(uiDelegate)
95 {
96 }
97
98 UIDelegate::UIClient::~UIClient()
99 {
100 }
101
102 PassRefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPage(WebKit::WebPageProxy*, WebKit::WebFrameProxy* initiatingFrame, const WebKit::SecurityOriginData& securityOriginData, const WebCore::ResourceRequest& request, const WebCore::WindowFeatures& windowFeatures, const WebKit::NavigationActionData& navigationActionData)
103 {
104     if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures)
105         return nullptr;
106
107     auto delegate = m_uiDelegate.m_delegate.get();
108     if (!delegate)
109         return nullptr;
110
111     auto configuration = adoptNS([m_uiDelegate.m_webView->_configuration copy]);
112     [configuration _setRelatedWebView:m_uiDelegate.m_webView];
113
114     auto sourceFrameInfo = API::FrameInfo::create(*initiatingFrame, securityOriginData.securityOrigin());
115
116     bool shouldOpenAppLinks = !protocolHostAndPortAreEqual(WebCore::URL(WebCore::ParsedURLString, initiatingFrame->url()), request.url());
117     auto navigationAction = API::NavigationAction::create(navigationActionData, sourceFrameInfo.ptr(), nullptr, request, WebCore::URL(), shouldOpenAppLinks);
118
119     RetainPtr<WKWebView> webView = [delegate.get() webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:wrapper(navigationAction) windowFeatures:adoptNS([[WKWindowFeatures alloc] _initWithWindowFeatures:windowFeatures]).get()];
120
121     if (!webView)
122         return nullptr;
123
124     if ([webView->_configuration _relatedWebView] != m_uiDelegate.m_webView)
125         [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."];
126
127     return webView->_page.get();
128 }
129
130 void UIDelegate::UIClient::runJavaScriptAlert(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebKit::SecurityOriginData& securityOriginData, std::function<void ()> completionHandler)
131 {
132     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler) {
133         completionHandler();
134         return;
135     }
136
137     auto delegate = m_uiDelegate.m_delegate.get();
138     if (!delegate) {
139         completionHandler();
140         return;
141     }
142
143     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:));
144     [delegate webView:m_uiDelegate.m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:[completionHandler, checker] {
145         completionHandler();
146         checker->didCallCompletionHandler();
147     }];
148 }
149
150 void UIDelegate::UIClient::runJavaScriptConfirm(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, const WebKit::SecurityOriginData& securityOriginData, std::function<void (bool)> completionHandler)
151 {
152     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler) {
153         completionHandler(false);
154         return;
155     }
156
157     auto delegate = m_uiDelegate.m_delegate.get();
158     if (!delegate) {
159         completionHandler(false);
160         return;
161     }
162
163     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
164     [delegate webView:m_uiDelegate.m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:[completionHandler, checker](BOOL result) {
165         completionHandler(result);
166         checker->didCallCompletionHandler();
167     }];
168 }
169
170 void UIDelegate::UIClient::runJavaScriptPrompt(WebKit::WebPageProxy*, const WTF::String& message, const WTF::String& defaultValue, WebKit::WebFrameProxy* webFrameProxy, const WebKit::SecurityOriginData& securityOriginData, std::function<void (const WTF::String&)> completionHandler)
171 {
172     if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler) {
173         completionHandler(String());
174         return;
175     }
176
177     auto delegate = m_uiDelegate.m_delegate.get();
178     if (!delegate) {
179         completionHandler(String());
180         return;
181     }
182
183     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:));
184     [delegate webView:m_uiDelegate.m_webView runJavaScriptTextInputPanelWithPrompt:message defaultText:defaultValue initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:[completionHandler, checker](NSString *result) {
185         completionHandler(result);
186         checker->didCallCompletionHandler();
187     }];
188 }
189
190 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, std::function<void (unsigned long long)> completionHandler)
191 {
192     if (!m_uiDelegate.m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler) {
193         completionHandler(currentQuota);
194         return;
195     }
196
197     auto delegate = m_uiDelegate.m_delegate.get();
198     if (!delegate) {
199         completionHandler(currentQuota);
200         return;
201     }
202
203     ASSERT(securityOrigin);
204     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:));
205     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideDatabaseQuotaForSecurityOrigin:wrapper(*securityOrigin) currentQuota:currentQuota currentOriginUsage:currentOriginUsage currentDatabaseUsage:currentUsage expectedUsage:expectedUsage decisionHandler:[completionHandler, checker](unsigned long long newQuota) {
206         checker->didCallCompletionHandler();
207         completionHandler(newQuota);
208     }];
209 }
210
211 void UIDelegate::UIClient::reachedApplicationCacheOriginQuota(WebPageProxy*, const WebCore::SecurityOrigin& securityOrigin, uint64_t currentQuota, uint64_t totalBytesNeeded, std::function<void (unsigned long long)> completionHandler)
212 {
213     if (!m_uiDelegate.m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded) {
214         completionHandler(currentQuota);
215         return;
216     }
217
218     auto delegate = m_uiDelegate.m_delegate.get();
219     if (!delegate) {
220         completionHandler(currentQuota);
221         return;
222     }
223
224     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:));
225     RefPtr<API::SecurityOrigin> apiOrigin = API::SecurityOrigin::create(securityOrigin);
226     
227     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideWebApplicationCacheQuotaForSecurityOrigin:wrapper(*apiOrigin) currentQuota:currentQuota totalBytesNeeded:totalBytesNeeded decisionHandler:[completionHandler, checker](unsigned long long newQuota) {
228         checker->didCallCompletionHandler();
229         completionHandler(newQuota);
230     }];
231 }
232
233 void UIDelegate::UIClient::printFrame(WebKit::WebPageProxy*, WebKit::WebFrameProxy* webFrameProxy)
234 {
235     ASSERT_ARG(webFrameProxy, webFrameProxy);
236
237     if (!m_uiDelegate.m_delegateMethods.webViewPrintFrame)
238         return;
239
240     auto delegate = m_uiDelegate.m_delegate.get();
241     if (!delegate)
242         return;
243
244     [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView printFrame:wrapper(API::FrameHandle::create(webFrameProxy->frameID()))];
245 }
246
247 void UIDelegate::UIClient::close(WebKit::WebPageProxy*)
248 {
249     if (m_uiDelegate.m_delegateMethods.webViewClose) {
250         auto delegate = m_uiDelegate.m_delegate.get();
251         if (!delegate)
252             return;
253
254         [(id <WKUIDelegatePrivate>)delegate _webViewClose:m_uiDelegate.m_webView];
255         return;
256     }
257
258     if (!m_uiDelegate.m_delegateMethods.webViewDidClose)
259         return;
260
261     auto delegate = m_uiDelegate.m_delegate.get();
262     if (!delegate)
263         return;
264
265     [delegate webViewDidClose:m_uiDelegate.m_webView];
266 }
267
268 void UIDelegate::UIClient::fullscreenMayReturnToInline(WebKit::WebPageProxy*)
269 {
270     if (!m_uiDelegate.m_delegateMethods.webViewFullscreenMayReturnToInline)
271         return;
272     
273     auto delegate = m_uiDelegate.m_delegate.get();
274     if (!delegate)
275         return;
276     
277     [(id <WKUIDelegatePrivate>)delegate _webViewFullscreenMayReturnToInline:m_uiDelegate.m_webView];
278 }
279
280 void UIDelegate::UIClient::didEnterFullscreen(WebKit::WebPageProxy*)
281 {
282     if (!m_uiDelegate.m_delegateMethods.webViewDidEnterFullscreen)
283         return;
284
285     auto delegate = m_uiDelegate.m_delegate.get();
286     if (!delegate)
287         return;
288
289     [(id <WKUIDelegatePrivate>)delegate _webViewDidEnterFullscreen:m_uiDelegate.m_webView];
290 }
291
292 void UIDelegate::UIClient::didExitFullscreen(WebKit::WebPageProxy*)
293 {
294     if (!m_uiDelegate.m_delegateMethods.webViewDidExitFullscreen)
295         return;
296
297     auto delegate = m_uiDelegate.m_delegate.get();
298     if (!delegate)
299         return;
300
301     [(id <WKUIDelegatePrivate>)delegate _webViewDidExitFullscreen:m_uiDelegate.m_webView];
302 }
303     
304 #if PLATFORM(IOS)
305 #if HAVE(APP_LINKS)
306 bool UIDelegate::UIClient::shouldIncludeAppLinkActionsForElement(_WKActivatedElementInfo *elementInfo)
307 {
308     if (!m_uiDelegate.m_delegateMethods.webViewShouldIncludeAppLinkActionsForElement)
309         return true;
310
311     auto delegate = m_uiDelegate.m_delegate.get();
312     if (!delegate)
313         return true;
314
315     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView shouldIncludeAppLinkActionsForElement:elementInfo];
316 }
317 #endif
318
319 RetainPtr<NSArray> UIDelegate::UIClient::actionsForElement(_WKActivatedElementInfo *elementInfo, RetainPtr<NSArray> defaultActions)
320 {
321     if (!m_uiDelegate.m_delegateMethods.webViewActionsForElementDefaultActions)
322         return WTF::move(defaultActions);
323
324     auto delegate = m_uiDelegate.m_delegate.get();
325     if (!delegate)
326         return defaultActions;
327
328     return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView actionsForElement:elementInfo defaultActions:defaultActions.get()];
329 }
330
331 void UIDelegate::UIClient::didNotHandleTapAsClick(const WebCore::IntPoint& point)
332 {
333     if (!m_uiDelegate.m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint)
334         return;
335
336     auto delegate = m_uiDelegate.m_delegate.get();
337     if (!delegate)
338         return;
339
340     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView didNotHandleTapAsClickAtPoint:point];
341 }
342 #endif
343
344 #if ENABLE(VIDEO)
345 void UIDelegate::UIClient::mediaDocumentNaturalSizeChanged(const WebCore::IntSize& newSize)
346 {
347     if (!m_uiDelegate.m_delegateMethods.webViewMediaDocumentNaturalSizeChanged)
348         return;
349
350     auto delegate = m_uiDelegate.m_delegate.get();
351     if (!delegate)
352         return;
353
354     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView mediaDocumentNaturalSizeChanged:newSize];
355 }
356 #endif
357
358 } // namespace WebKit
359
360 #endif // WK_API_ENABLED