1/* 2 * Copyright (C) 2009, 2012, 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 "WebGeolocationClient.h" 27 28#if ENABLE(GEOLOCATION) 29 30#import "WebDelegateImplementationCaching.h" 31#import "WebFrameInternal.h" 32#import "WebGeolocationPositionInternal.h" 33#import "WebSecurityOriginInternal.h" 34#import "WebUIDelegatePrivate.h" 35#import "WebViewInternal.h" 36#import <WebCore/BlockExceptions.h> 37#import <WebCore/Document.h> 38#import <WebCore/Frame.h> 39#import <WebCore/Geolocation.h> 40 41#if PLATFORM(IOS) 42#import <WebCore/WAKResponder.h> 43#import <WebKitLegacy/WebCoreThreadRun.h> 44#endif 45 46using namespace WebCore; 47 48#if !PLATFORM(IOS) 49@interface WebGeolocationPolicyListener : NSObject <WebAllowDenyPolicyListener> 50{ 51 RefPtr<Geolocation> _geolocation; 52} 53- (id)initWithGeolocation:(Geolocation*)geolocation; 54@end 55#else 56@interface WebGeolocationPolicyListener : NSObject <WebAllowDenyPolicyListener> 57{ 58 RefPtr<Geolocation> _geolocation; 59 RetainPtr<WebView *> _webView; 60} 61- (id)initWithGeolocation:(Geolocation*)geolocation forWebView:(WebView*)webView; 62@end 63#endif 64 65#if PLATFORM(IOS) 66@interface WebGeolocationProviderInitializationListener : NSObject <WebGeolocationProviderInitializationListener> { 67@private 68 RefPtr<Geolocation> m_geolocation; 69} 70- (id)initWithGeolocation:(Geolocation*)geolocation; 71@end 72#endif 73 74WebGeolocationClient::WebGeolocationClient(WebView *webView) 75 : m_webView(webView) 76{ 77} 78 79void WebGeolocationClient::geolocationDestroyed() 80{ 81 delete this; 82} 83 84void WebGeolocationClient::startUpdating() 85{ 86 [[m_webView _geolocationProvider] registerWebView:m_webView]; 87} 88 89void WebGeolocationClient::stopUpdating() 90{ 91 [[m_webView _geolocationProvider] unregisterWebView:m_webView]; 92} 93 94#if PLATFORM(IOS) 95void WebGeolocationClient::setEnableHighAccuracy(bool wantsHighAccuracy) 96{ 97 BEGIN_BLOCK_OBJC_EXCEPTIONS; 98 [[m_webView _geolocationProvider] setEnableHighAccuracy:wantsHighAccuracy]; 99 END_BLOCK_OBJC_EXCEPTIONS; 100} 101#endif 102 103void WebGeolocationClient::requestPermission(Geolocation* geolocation) 104{ 105 BEGIN_BLOCK_OBJC_EXCEPTIONS; 106 107 SEL selector = @selector(webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:); 108 if (![[m_webView UIDelegate] respondsToSelector:selector]) { 109 geolocation->setIsAllowed(false); 110 return; 111 } 112 113#if !PLATFORM(IOS) 114 Frame *frame = geolocation->frame(); 115 116 if (!frame) { 117 geolocation->setIsAllowed(false); 118 return; 119 } 120 121 WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()]; 122 WebGeolocationPolicyListener* listener = [[WebGeolocationPolicyListener alloc] initWithGeolocation:geolocation]; 123 124 CallUIDelegate(m_webView, selector, webOrigin, kit(frame), listener); 125 126 [webOrigin release]; 127 [listener release]; 128#else 129 RetainPtr<WebGeolocationProviderInitializationListener> listener = adoptNS([[WebGeolocationProviderInitializationListener alloc] initWithGeolocation:geolocation]); 130 [[m_webView _geolocationProvider] initializeGeolocationForWebView:m_webView listener:listener.get()]; 131#endif 132 END_BLOCK_OBJC_EXCEPTIONS; 133} 134 135GeolocationPosition* WebGeolocationClient::lastPosition() 136{ 137 return core([[m_webView _geolocationProvider] lastPosition]); 138} 139 140#if !PLATFORM(IOS) 141@implementation WebGeolocationPolicyListener 142 143- (id)initWithGeolocation:(Geolocation*)geolocation 144{ 145 if (!(self = [super init])) 146 return nil; 147 _geolocation = geolocation; 148 return self; 149} 150 151- (void)allow 152{ 153 _geolocation->setIsAllowed(true); 154} 155 156- (void)deny 157{ 158 _geolocation->setIsAllowed(false); 159} 160 161@end 162 163#else 164@implementation WebGeolocationPolicyListener 165- (id)initWithGeolocation:(Geolocation*)geolocation forWebView:(WebView*)webView 166{ 167 self = [super init]; 168 if (!self) 169 return nil; 170 _geolocation = geolocation; 171 _webView = webView; 172 return self; 173} 174 175- (void)allow 176{ 177 WebThreadRun(^{ 178 _geolocation->setIsAllowed(true); 179 }); 180} 181 182- (void)deny 183{ 184 WebThreadRun(^{ 185 _geolocation->setIsAllowed(false); 186 }); 187} 188 189- (void)denyOnlyThisRequest 190{ 191 WebThreadRun(^{ 192 // A soft deny does not prevent subsequent request from the Geolocation object. 193 [self deny]; 194 _geolocation->resetAllGeolocationPermission(); 195 }); 196} 197 198- (BOOL)shouldClearCache 199{ 200 // Theoretically, WebView could changes the WebPreferences after we get the pointer. 201 // We lock to be on the safe side. 202 WebThreadLock(); 203 204 return [[_webView.get() preferences] _alwaysRequestGeolocationPermission]; 205} 206@end 207 208@implementation WebGeolocationProviderInitializationListener 209- (id)initWithGeolocation:(Geolocation*)geolocation 210{ 211 self = [super init]; 212 if (self) 213 m_geolocation = geolocation; 214 return self; 215} 216 217- (void)initializationAllowedWebView:(WebView *)webView 218{ 219 BEGIN_BLOCK_OBJC_EXCEPTIONS; 220 221 Frame* frame = m_geolocation->frame(); 222 if (!frame) 223 return; 224 WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()]; 225 WebGeolocationPolicyListener *listener = [[WebGeolocationPolicyListener alloc] initWithGeolocation:m_geolocation.get() forWebView:webView]; 226 SEL selector = @selector(webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:); 227 CallUIDelegate(webView, selector, webOrigin, kit(frame), listener); 228 [webOrigin release]; 229 [listener release]; 230 231 END_BLOCK_OBJC_EXCEPTIONS; 232} 233 234- (void)initializationDeniedWebView:(WebView *)webView 235{ 236 m_geolocation->setIsAllowed(false); 237} 238@end 239#endif // PLATFORM(IOS) 240 241#endif // ENABLE(GEOLOCATION) 242