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 "WKFrameInfoInternal.h" 34#import "WKNavigationActionInternal.h" 35#import "WKWebViewConfigurationInternal.h" 36#import "WKWebViewInternal.h" 37#import "WKWindowFeaturesInternal.h" 38#import "WKUIDelegatePrivate.h" 39#import "_WKFrameHandleInternal.h" 40#import "_WKSecurityOriginInternal.h" 41 42namespace WebKit { 43 44UIDelegate::UIDelegate(WKWebView *webView) 45 : m_webView(webView) 46{ 47} 48 49UIDelegate::~UIDelegate() 50{ 51} 52 53std::unique_ptr<API::UIClient> UIDelegate::createUIClient() 54{ 55 return std::make_unique<UIClient>(*this); 56} 57 58RetainPtr<id <WKUIDelegate> > UIDelegate::delegate() 59{ 60 return m_delegate.get(); 61} 62 63void UIDelegate::setDelegate(id <WKUIDelegate> delegate) 64{ 65 m_delegate = delegate; 66 67 m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures = [delegate respondsToSelector:@selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)]; 68 m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)]; 69 m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; 70 m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)]; 71 m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler = [delegate respondsToSelector:@selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:)]; 72 m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded = [delegate respondsToSelector:@selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:)]; 73 m_delegateMethods.webViewPrintFrame = [delegate respondsToSelector:@selector(_webView:printFrame:)]; 74#if PLATFORM(IOS) 75 m_delegateMethods.webViewActionsForElementDefaultActions = [delegate respondsToSelector:@selector(_webView:actionsForElement:defaultActions:)]; 76 m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint = [delegate respondsToSelector:@selector(_webView:didNotHandleTapAsClickAtPoint:)]; 77#endif 78} 79 80UIDelegate::UIClient::UIClient(UIDelegate& uiDelegate) 81 : m_uiDelegate(uiDelegate) 82{ 83} 84 85UIDelegate::UIClient::~UIClient() 86{ 87} 88 89PassRefPtr<WebKit::WebPageProxy> UIDelegate::UIClient::createNewPage(WebKit::WebPageProxy*, WebKit::WebFrameProxy* initiatingFrame, const WebCore::ResourceRequest& request, const WebCore::WindowFeatures& windowFeatures, const WebKit::NavigationActionData& navigationActionData) 90{ 91 if (!m_uiDelegate.m_delegateMethods.webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures) 92 return nullptr; 93 94 auto delegate = m_uiDelegate.m_delegate.get(); 95 if (!delegate) 96 return nullptr; 97 98 auto configuration = adoptNS([m_uiDelegate.m_webView->_configuration copy]); 99 [configuration _setRelatedWebView:m_uiDelegate.m_webView]; 100 101 auto navigationAction = adoptNS([[WKNavigationAction alloc] _initWithNavigationActionData:navigationActionData]); 102 103 [navigationAction setSourceFrame:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*initiatingFrame]).get()]; 104 [navigationAction setRequest:request.nsURLRequest(WebCore::DoNotUpdateHTTPBody)]; 105 106 RetainPtr<WKWebView> webView = [delegate.get() webView:m_uiDelegate.m_webView createWebViewWithConfiguration:configuration.get() forNavigationAction:navigationAction.get() windowFeatures:adoptNS([[WKWindowFeatures alloc] _initWithWindowFeatures:windowFeatures]).get()]; 107 108 if (!webView) 109 return nullptr; 110 111 if ([webView->_configuration _relatedWebView] != m_uiDelegate.m_webView) 112 [NSException raise:NSInternalInconsistencyException format:@"Returned WKWebView was not created with the given configuration."]; 113 114 return webView->_page.get(); 115} 116 117void UIDelegate::UIClient::runJavaScriptAlert(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, std::function<void ()> completionHandler) 118{ 119 if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler) { 120 completionHandler(); 121 return; 122 } 123 124 auto delegate = m_uiDelegate.m_delegate.get(); 125 if (!delegate) { 126 completionHandler(); 127 return; 128 } 129 130 RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)); 131 [delegate webView:m_uiDelegate.m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*webFrameProxy]).get() completionHandler:[completionHandler, checker] { 132 completionHandler(); 133 checker->didCallCompletionHandler(); 134 }]; 135} 136 137void UIDelegate::UIClient::runJavaScriptConfirm(WebKit::WebPageProxy*, const WTF::String& message, WebKit::WebFrameProxy* webFrameProxy, std::function<void (bool)> completionHandler) 138{ 139 if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler) { 140 completionHandler(false); 141 return; 142 } 143 144 auto delegate = m_uiDelegate.m_delegate.get(); 145 if (!delegate) { 146 completionHandler(false); 147 return; 148 } 149 150 RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)); 151 [delegate webView:m_uiDelegate.m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*webFrameProxy]).get() completionHandler:[completionHandler, checker](BOOL result) { 152 completionHandler(result); 153 checker->didCallCompletionHandler(); 154 }]; 155} 156 157void UIDelegate::UIClient::runJavaScriptPrompt(WebKit::WebPageProxy*, const WTF::String& message, const WTF::String& defaultValue, WebKit::WebFrameProxy* webFrameProxy, std::function<void (const WTF::String&)> completionHandler) 158{ 159 if (!m_uiDelegate.m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler) { 160 completionHandler(String()); 161 return; 162 } 163 164 auto delegate = m_uiDelegate.m_delegate.get(); 165 if (!delegate) { 166 completionHandler(String()); 167 return; 168 } 169 170 RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)); 171 [delegate webView:m_uiDelegate.m_webView runJavaScriptTextInputPanelWithPrompt:message defaultText:defaultValue initiatedByFrame:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*webFrameProxy]).get() completionHandler:[completionHandler, checker](NSString *result) { 172 completionHandler(result); 173 checker->didCallCompletionHandler(); 174 }]; 175} 176 177void UIDelegate::UIClient::exceededDatabaseQuota(WebPageProxy*, WebFrameProxy*, WebSecurityOrigin* 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) 178{ 179 if (!m_uiDelegate.m_delegateMethods.webViewDecideDatabaseQuotaForSecurityOriginCurrentQuotaCurrentOriginUsageCurrentDatabaseUsageExpectedUsageDecisionHandler) { 180 completionHandler(currentQuota); 181 return; 182 } 183 184 auto delegate = m_uiDelegate.m_delegate.get(); 185 if (!delegate) { 186 completionHandler(currentQuota); 187 return; 188 } 189 190 RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:)); 191 [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideDatabaseQuotaForSecurityOrigin:adoptNS([[_WKSecurityOrigin alloc] _initWithSecurityOrigin:securityOrigin->securityOrigin()]).get() currentQuota:currentQuota currentOriginUsage:currentOriginUsage currentDatabaseUsage:currentUsage expectedUsage:expectedUsage decisionHandler:[completionHandler, checker](unsigned long long newQuota) { 192 checker->didCallCompletionHandler(); 193 completionHandler(newQuota); 194 }]; 195} 196 197void UIDelegate::UIClient::reachedApplicationCacheOriginQuota(WebPageProxy*, const WebCore::SecurityOrigin& securityOrigin, uint64_t currentQuota, uint64_t totalBytesNeeded, std::function<void (unsigned long long)> completionHandler) 198{ 199 if (!m_uiDelegate.m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded) { 200 completionHandler(currentQuota); 201 return; 202 } 203 204 auto delegate = m_uiDelegate.m_delegate.get(); 205 if (!delegate) { 206 completionHandler(currentQuota); 207 return; 208 } 209 210 RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideWebApplicationCacheQuotaForSecurityOrigin:currentQuota:totalBytesNeeded:decisionHandler:)); 211 [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideWebApplicationCacheQuotaForSecurityOrigin:adoptNS([[_WKSecurityOrigin alloc] _initWithSecurityOrigin:securityOrigin]).get() currentQuota:currentQuota totalBytesNeeded:totalBytesNeeded decisionHandler:[completionHandler, checker](unsigned long long newQuota) { 212 checker->didCallCompletionHandler(); 213 completionHandler(newQuota); 214 }]; 215} 216 217void UIDelegate::UIClient::printFrame(WebKit::WebPageProxy*, WebKit::WebFrameProxy* webFrameProxy) 218{ 219 ASSERT_ARG(webFrameProxy, webFrameProxy); 220 221 if (!m_uiDelegate.m_delegateMethods.webViewPrintFrame) 222 return; 223 224 auto delegate = m_uiDelegate.m_delegate.get(); 225 if (!delegate) 226 return; 227 228 [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView printFrame:wrapper(*API::FrameHandle::create(webFrameProxy->frameID()))]; 229} 230 231#if PLATFORM(IOS) 232RetainPtr<NSArray> UIDelegate::UIClient::actionsForElement(_WKActivatedElementInfo *elementInfo, RetainPtr<NSArray> defaultActions) 233{ 234 if (!m_uiDelegate.m_delegateMethods.webViewActionsForElementDefaultActions) 235 return WTF::move(defaultActions); 236 237 auto delegate = m_uiDelegate.m_delegate.get(); 238 if (!delegate) 239 return defaultActions; 240 241 return [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView actionsForElement:elementInfo defaultActions:defaultActions.get()]; 242} 243 244void UIDelegate::UIClient::didNotHandleTapAsClick(const WebCore::IntPoint& point) 245{ 246 if (!m_uiDelegate.m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint) 247 return; 248 249 auto delegate = m_uiDelegate.m_delegate.get(); 250 if (!delegate) 251 return; 252 253 [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView didNotHandleTapAsClickAtPoint:point]; 254} 255#endif 256 257} // namespace WebKit 258 259#endif // WK_API_ENABLED 260