Add SPI for handling geolocation authorization requests
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Apr 2017 18:43:46 +0000 (18:43 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Apr 2017 18:43:46 +0000 (18:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170362
rdar://problem/17508627

Patch by David Quesada <david_quesada@apple.com> on 2017-04-11
Reviewed by Alex Christensen.

Source/WebKit2:

Add a new WKUIDelegate method for the WKGeolocationProviderIOS to call when a web page
requests geolocation access. To support testing this change, make it possible to override
the CoreLocation abstraction WKGeolocationProviderIOS uses. There is now a configurable
object on the process pool that implements a protocol for providing location updates for
web views in the process pool. If the client doesn't provide this object,
WKGeolocationProviderIOS falls back to an object that wraps the existing WebKit1
WebGeolocationCoreLocationProvider and conforms to the new protocol.

* Shared/Cocoa/APIObject.mm:
(API::Object::newObject):
* Shared/WebGeolocationPosition.h:
(WebKit::WebGeolocationPosition::create):
* UIProcess/API/C/WKGeolocationPosition.cpp:
(WKGeolocationPositionCreate_b):
* UIProcess/API/Cocoa/WKProcessPool.mm:
(-[WKProcessPool _coreLocationProvider]):
(-[WKProcessPool _setCoreLocationProvider:]):
* UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
* UIProcess/API/Cocoa/_WKGeolocationCoreLocationProvider.h: Copied from Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp.
* UIProcess/API/Cocoa/_WKGeolocationPosition.h: Copied from Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp.
* UIProcess/API/Cocoa/_WKGeolocationPosition.mm: Added.
(WebKit::if):
(-[_WKGeolocationPosition dealloc]):
(-[_WKGeolocationPosition _apiObject]):
* UIProcess/API/Cocoa/_WKGeolocationPositionInternal.h: Copied from Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp.
(WebKit::wrapper):
* UIProcess/ios/WKGeolocationProviderIOS.mm:
(kit):
(-[WKGeolocationProviderIOS initWithProcessPool:]):
(-[WKGeolocationProviderIOS geolocationAuthorizationGranted]):
(-[WKGeolocationProviderIOS positionChanged:]):
(-[WKLegacyCoreLocationProvider setListener:]):
(-[WKLegacyCoreLocationProvider requestGeolocationAuthorization]):
(-[WKLegacyCoreLocationProvider start]):
(-[WKLegacyCoreLocationProvider stop]):
(-[WKLegacyCoreLocationProvider setEnableHighAccuracy:]):
(-[WKLegacyCoreLocationProvider geolocationAuthorizationGranted]):
(-[WKLegacyCoreLocationProvider geolocationAuthorizationDenied]):
(-[WKLegacyCoreLocationProvider positionChanged:]):
(-[WKLegacyCoreLocationProvider errorOccurred:]):
(-[WKLegacyCoreLocationProvider resetGeolocation]):
Implement a new class that bridges the currently used WebGeolocationCoreLocationProvider
to conform to the _WKGeolocationCoreLocationProvider protocol that WKGeolocationProviderIOS
expects.
* WebKit2.xcodeproj/project.pbxproj:

Tools:

Add API tests for the new WKUIDelegate SPI for allowing or denying websites permission
to use geolocation. Adopt the new WKProcessPool._coreLocationProvider property to
provide a stub object to simulate the various configurations of geolocation permissions:
1. The app doesn't have permission to use geolocation.
2. The app is allowed to use geolocation, but the UI delegate denies the web view permission.
3. The app is allowed to use geolocation, and the UI delegate allows the web view permission.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/Geolocation.mm: Added.
(-[TestCoreLocationProvider setListener:]):
(-[TestCoreLocationProvider requestGeolocationAuthorization]):
(-[TestCoreLocationProvider start]):
(-[TestCoreLocationProvider stop]):
(-[TestCoreLocationProvider setEnableHighAccuracy:]):
(expectException):
(-[GeolocationTestUIDelegate _webView:requestGeolocationAuthorizationForURL:frame:decisionHandler:]):
(-[GeolocationTestUIDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/GeolocationGetCurrentPositionResult.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215246 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/Cocoa/APIObject.mm
Source/WebKit2/Shared/WebGeolocationPosition.h
Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp
Source/WebKit2/UIProcess/API/Cocoa/WKProcessPool.mm
Source/WebKit2/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationCoreLocationProvider.h [new file with mode: 0644]
Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPosition.h [new file with mode: 0644]
Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPosition.mm [new file with mode: 0644]
Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPositionInternal.h [new file with mode: 0644]
Source/WebKit2/UIProcess/ios/WKGeolocationProviderIOS.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/Geolocation.mm [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/GeolocationGetCurrentPositionResult.html [new file with mode: 0644]

index f21f769..3d22cdf 100644 (file)
@@ -1,3 +1,58 @@
+2017-04-11  David Quesada  <david_quesada@apple.com>
+
+        Add SPI for handling geolocation authorization requests
+        https://bugs.webkit.org/show_bug.cgi?id=170362
+        rdar://problem/17508627
+
+        Reviewed by Alex Christensen.
+
+        Add a new WKUIDelegate method for the WKGeolocationProviderIOS to call when a web page
+        requests geolocation access. To support testing this change, make it possible to override
+        the CoreLocation abstraction WKGeolocationProviderIOS uses. There is now a configurable
+        object on the process pool that implements a protocol for providing location updates for
+        web views in the process pool. If the client doesn't provide this object,
+        WKGeolocationProviderIOS falls back to an object that wraps the existing WebKit1
+        WebGeolocationCoreLocationProvider and conforms to the new protocol.
+
+        * Shared/Cocoa/APIObject.mm:
+        (API::Object::newObject):
+        * Shared/WebGeolocationPosition.h:
+        (WebKit::WebGeolocationPosition::create):
+        * UIProcess/API/C/WKGeolocationPosition.cpp:
+        (WKGeolocationPositionCreate_b):
+        * UIProcess/API/Cocoa/WKProcessPool.mm:
+        (-[WKProcessPool _coreLocationProvider]):
+        (-[WKProcessPool _setCoreLocationProvider:]):
+        * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+        * UIProcess/API/Cocoa/_WKGeolocationCoreLocationProvider.h: Copied from Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp.
+        * UIProcess/API/Cocoa/_WKGeolocationPosition.h: Copied from Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp.
+        * UIProcess/API/Cocoa/_WKGeolocationPosition.mm: Added.
+        (WebKit::if):
+        (-[_WKGeolocationPosition dealloc]):
+        (-[_WKGeolocationPosition _apiObject]):
+        * UIProcess/API/Cocoa/_WKGeolocationPositionInternal.h: Copied from Source/WebKit2/UIProcess/API/C/WKGeolocationPosition.cpp.
+        (WebKit::wrapper):
+        * UIProcess/ios/WKGeolocationProviderIOS.mm:
+        (kit):
+        (-[WKGeolocationProviderIOS initWithProcessPool:]):
+        (-[WKGeolocationProviderIOS geolocationAuthorizationGranted]):
+        (-[WKGeolocationProviderIOS positionChanged:]):
+        (-[WKLegacyCoreLocationProvider setListener:]):
+        (-[WKLegacyCoreLocationProvider requestGeolocationAuthorization]):
+        (-[WKLegacyCoreLocationProvider start]):
+        (-[WKLegacyCoreLocationProvider stop]):
+        (-[WKLegacyCoreLocationProvider setEnableHighAccuracy:]):
+        (-[WKLegacyCoreLocationProvider geolocationAuthorizationGranted]):
+        (-[WKLegacyCoreLocationProvider geolocationAuthorizationDenied]):
+        (-[WKLegacyCoreLocationProvider positionChanged:]):
+        (-[WKLegacyCoreLocationProvider errorOccurred:]):
+        (-[WKLegacyCoreLocationProvider resetGeolocation]):
+        Implement a new class that bridges the currently used WebGeolocationCoreLocationProvider
+        to conform to the _WKGeolocationCoreLocationProvider protocol that WKGeolocationProviderIOS
+        expects.
+        * WebKit2.xcodeproj/project.pbxproj:
+
 2017-04-11  Eric Carlson  <eric.carlson@apple.com>
 
         [MediaStream] Set correct audio session category when capturing audio
index 441b34f..258f42b 100644 (file)
@@ -72,6 +72,7 @@
 #import "_WKDownloadInternal.h"
 #import "_WKExperimentalFeatureInternal.h"
 #import "_WKFrameHandleInternal.h"
+#import "_WKGeolocationPositionInternal.h"
 #import "_WKHitTestResultInternal.h"
 #import "_WKProcessPoolConfigurationInternal.h"
 #import "_WKUserContentWorldInternal.h"
@@ -179,6 +180,12 @@ void* Object::newObject(size_t size, Type type)
         wrapper = [WKFrameInfo alloc];
         break;
 
+#if PLATFORM(IOS)
+    case Type::GeolocationPosition:
+        wrapper = [_WKGeolocationPosition alloc];
+        break;
+#endif
+
     case Type::HTTPCookieStore:
         wrapper = [WKHTTPCookieStore alloc];
         break;
index f4815e6..3f03971 100644 (file)
@@ -58,9 +58,9 @@ public:
         bool canProvideSpeed;
     };
 
-    static PassRefPtr<WebGeolocationPosition> create(double timestamp, double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed)
+    static Ref<WebGeolocationPosition> create(double timestamp, double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed)
     {
-        return adoptRef(new WebGeolocationPosition(timestamp, latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed));
+        return adoptRef(*new WebGeolocationPosition(timestamp, latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed));
     }
 
     virtual ~WebGeolocationPosition();
index 8b4c5b6..57fbdcf 100644 (file)
@@ -44,5 +44,5 @@ WKGeolocationPositionRef WKGeolocationPositionCreate(double timestamp, double la
 WKGeolocationPositionRef WKGeolocationPositionCreate_b(double timestamp, double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed)
 {
     auto position = WebGeolocationPosition::create(timestamp, latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
-    return toAPI(position.leakRef());
+    return toAPI(&position.leakRef());
 }
index 8f87dac..83c4fda 100644 (file)
@@ -61,6 +61,7 @@ static WKProcessPool *sharedProcessPool;
     RetainPtr<_WKAutomationSession> _automationSession;
 #if PLATFORM(IOS)
     RetainPtr<WKGeolocationProviderIOS> _geolocationProvider;
+    RetainPtr<id <_WKGeolocationCoreLocationProvider>> _coreLocationProvider;
 #endif // PLATFORM(IOS)
 }
 
@@ -308,6 +309,21 @@ static WebKit::HTTPCookieAcceptPolicy toHTTPCookieAcceptPolicy(NSHTTPCookieAccep
     _processPool->setCookieStoragePartitioningEnabled(enabled);
 }
 
+#if PLATFORM(IOS)
+- (id <_WKGeolocationCoreLocationProvider>)_coreLocationProvider
+{
+    return _coreLocationProvider.get();
+}
+
+- (void)_setCoreLocationProvider:(id<_WKGeolocationCoreLocationProvider>)coreLocationProvider
+{
+    if (_geolocationProvider)
+        [NSException raise:NSGenericException format:@"Changing the location provider is not supported after a web view in the process pool has begun servicing geolocation requests."];
+
+    _coreLocationProvider = coreLocationProvider;
+}
+#endif // PLATFORM(IOS)
+
 @end
 
 #endif // WK_API_ENABLED
index 818962c..e3cba67 100644 (file)
@@ -31,6 +31,7 @@
 @class _WKProcessPoolConfiguration;
 @protocol _WKAutomationDelegate;
 @protocol _WKDownloadDelegate;
+@protocol _WKGeolocationCoreLocationProvider;
 
 @interface WKProcessPool ()
 - (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration __attribute__((objc_method_family(init))) NS_DESIGNATED_INITIALIZER;
 @property (nonatomic, weak, setter=_setDownloadDelegate:) id <_WKDownloadDelegate> _downloadDelegate;
 @property (nonatomic, weak, setter=_setAutomationDelegate:) id <_WKAutomationDelegate> _automationDelegate WK_API_AVAILABLE(macosx(10.12), ios(10.0));
 
+#if TARGET_OS_IPHONE
+@property (nonatomic, setter=_setCoreLocationProvider:) id <_WKGeolocationCoreLocationProvider> _coreLocationProvider WK_API_AVAILABLE(ios(WK_IOS_TBA));
+#endif
+
 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL;
 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL bundleIdentifierIfNotInContainer:(NSString *)bundleIdentifier;
 
index 05a1096..4e3614e 100644 (file)
@@ -35,6 +35,7 @@
 @class UIItemProvider;
 @class UIScrollView;
 @class UIViewController;
+@class WKFrameInfo;
 @class _WKContextMenuElementInfo;
 @class _WKActivatedElementInfo;
 @class _WKElementAction;
@@ -72,6 +73,7 @@ struct UIEdgeInsets;
 - (NSArray *)_webView:(WKWebView *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray<_WKElementAction *> *)defaultActions;
 - (void)_webView:(WKWebView *)webView didNotHandleTapAsClickAtPoint:(CGPoint)point;
 - (BOOL)_webView:(WKWebView *)webView shouldRequestGeolocationAuthorizationForURL:(NSURL *)url isMainFrame:(BOOL)isMainFrame mainFrameURL:(NSURL *)mainFrameURL;
+- (void)_webView:(WKWebView *)webView requestGeolocationAuthorizationForURL:(NSURL *)url frame:(WKFrameInfo *)frame decisionHandler:(void (^)(BOOL authorized))decisionHandler WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (UIViewController *)_webView:(WKWebView *)webView previewViewControllerForURL:(NSURL *)url WK_API_AVAILABLE(ios(9.0));
 - (void)_webView:(WKWebView *)webView commitPreviewedViewController:(UIViewController *)previewedViewController WK_API_AVAILABLE(ios(9.0));
 - (void)_webView:(WKWebView *)webView willPreviewImageWithURL:(NSURL *)imageURL WK_API_AVAILABLE(ios(9.0));
diff --git a/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationCoreLocationProvider.h b/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationCoreLocationProvider.h
new file mode 100644 (file)
index 0000000..066ab78
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if WK_API_ENABLED && TARGET_OS_IPHONE
+
+#import <Foundation/NSObject.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class _WKGeolocationPosition;
+
+@protocol _WKGeolocationCoreLocationListener <NSObject>
+- (void)geolocationAuthorizationGranted;
+- (void)geolocationAuthorizationDenied;
+- (void)positionChanged:(_WKGeolocationPosition *)position;
+- (void)errorOccurred:(NSString *)errorMessage;
+- (void)resetGeolocation;
+@end
+
+@protocol _WKGeolocationCoreLocationProvider <NSObject>
+- (void)setListener:(id <_WKGeolocationCoreLocationListener>)listener;
+- (void)requestGeolocationAuthorization;
+- (void)start;
+- (void)stop;
+- (void)setEnableHighAccuracy:(BOOL)flag;
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // WK_API_ENABLED && TARGET_OS_IPHONE
diff --git a/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPosition.h b/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPosition.h
new file mode 100644 (file)
index 0000000..2c24ccb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if WK_API_ENABLED && TARGET_OS_IPHONE
+
+#import <Foundation/Foundation.h>
+
+@class CLLocation;
+
+NS_ASSUME_NONNULL_BEGIN
+
+WK_CLASS_AVAILABLE(ios(WK_IOS_TBA))
+@interface _WKGeolocationPosition : NSObject
+
++ (instancetype)positionWithLocation:(CLLocation *)location;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // WK_API_ENABLED && TARGET_OS_IPHONE
diff --git a/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPosition.mm b/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPosition.mm
new file mode 100644 (file)
index 0000000..8eefbec
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "_WKGeolocationPositionInternal.h"
+
+#if WK_API_ENABLED && TARGET_OS_IPHONE
+
+#import <CoreLocation/CLLocation.h>
+
+using namespace WebKit;
+
+@implementation _WKGeolocationPosition
+
++ (instancetype)positionWithLocation:(CLLocation *)location
+{
+    if (!location)
+        return nil;
+
+    bool canProvideAltitude = true;
+    bool canProvideAltitudeAccuracy = true;
+    double altitude = location.altitude;
+    double altitudeAccuracy = location.verticalAccuracy;
+    if (altitudeAccuracy < 0.0) {
+        canProvideAltitude = false;
+        canProvideAltitudeAccuracy = false;
+    }
+
+    bool canProvideSpeed = true;
+    double speed = location.speed;
+    if (speed < 0.0)
+        canProvideSpeed = false;
+
+    bool canProvideHeading = true;
+    double heading = location.course;
+    if (heading < 0.0)
+        canProvideHeading = false;
+
+    CLLocationCoordinate2D coordinate = location.coordinate;
+    double timestamp = location.timestamp.timeIntervalSince1970;
+
+    return [wrapper(WebGeolocationPosition::create(timestamp, coordinate.latitude, coordinate.longitude, location.horizontalAccuracy, canProvideAltitude, altitude, canProvideAltitudeAccuracy, altitudeAccuracy, canProvideHeading, heading, canProvideSpeed, speed).leakRef()) autorelease];
+}
+
+- (void)dealloc
+{
+    _geolocationPosition->~WebGeolocationPosition();
+
+    [super dealloc];
+}
+
+#pragma mark WKObject protocol implementation
+
+- (API::Object&)_apiObject
+{
+    return *_geolocationPosition;
+}
+
+@end
+
+#endif // WK_API_ENABLED && TARGET_OS_IPHONE
diff --git a/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPositionInternal.h b/Source/WebKit2/UIProcess/API/Cocoa/_WKGeolocationPositionInternal.h
new file mode 100644 (file)
index 0000000..71a3579
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "_WKGeolocationPosition.h"
+
+#if WK_API_ENABLED && TARGET_OS_IPHONE
+
+#import "WebGeolocationPosition.h"
+
+namespace WebKit {
+
+inline _WKGeolocationPosition *wrapper(WebKit::WebGeolocationPosition &position)
+{
+    ASSERT([position.wrapper() isKindOfClass:[_WKGeolocationPosition class]]);
+    return (_WKGeolocationPosition *)position.wrapper();
+}
+
+}
+
+@interface _WKGeolocationPosition () <WKObject> {
+@package
+    API::ObjectStorage<WebKit::WebGeolocationPosition> _geolocationPosition;
+}
+@end
+
+#endif // WK_API_ENABLED && TARGET_OS_IPHONE
index 2478104..31a375d 100644 (file)
 
 #if PLATFORM(IOS)
 
+#import "APIFrameInfo.h"
 #import "APISecurityOrigin.h"
+#import "CompletionHandlerCallChecker.h"
 #import "GeolocationPermissionRequestProxy.h"
+#import "WKFrameInfoInternal.h"
+#import "WKProcessPoolInternal.h"
 #import "WKUIDelegatePrivate.h"
 #import "WKWebView.h"
 #import "WebGeolocationManagerProxy.h"
 #import "WebProcessPool.h"
+#import "_WKGeolocationCoreLocationProvider.h"
+#import "_WKGeolocationPositionInternal.h"
 #import <WebCore/GeolocationPosition.h>
 #import <WebCore/URL.h>
 #import <WebGeolocationPosition.h>
 #import <wtf/Assertions.h>
+#import <wtf/BlockPtr.h>
 #import <wtf/HashSet.h>
 #import <wtf/PassRefPtr.h>
 #import <wtf/RefPtr.h>
@@ -53,7 +60,10 @@ using namespace WebKit;
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 
-@interface WKGeolocationProviderIOS (WebGeolocationCoreLocationUpdateListener) <WebGeolocationCoreLocationUpdateListener>
+@interface WKGeolocationProviderIOS (_WKGeolocationCoreLocationListener) <_WKGeolocationCoreLocationListener>
+@end
+
+@interface WKLegacyCoreLocationProvider : NSObject<_WKGeolocationCoreLocationProvider, WebGeolocationCoreLocationUpdateListener>
 @end
 
 @interface WKWebAllowDenyPolicyListener : NSObject<WebAllowDenyPolicyListener>
@@ -65,6 +75,11 @@ namespace WebKit {
 void decidePolicyForGeolocationRequestFromOrigin(SecurityOrigin*, const String& urlString, id<WebAllowDenyPolicyListener>, UIWindow*);
 };
 
+static inline Ref<WebGeolocationPosition> kit(WebCore::GeolocationPosition *position)
+{
+    return WebGeolocationPosition::create(position->timestamp(), position->latitude(), position->longitude(), position->accuracy(), position->canProvideAltitude(), position->altitude(), position->canProvideAltitudeAccuracy(), position->altitudeAccuracy(), position->canProvideHeading(), position->heading(), position->canProvideSpeed(), position->speed());
+}
+
 struct GeolocationRequestData {
     RefPtr<SecurityOrigin> origin;
     RefPtr<WebFrameProxy> frame;
@@ -74,7 +89,7 @@ struct GeolocationRequestData {
 
 @implementation WKGeolocationProviderIOS {
     RefPtr<WebGeolocationManagerProxy> _geolocationManager;
-    RetainPtr<WebGeolocationCoreLocationProvider> _coreLocationProvider;
+    RetainPtr<id <_WKGeolocationCoreLocationProvider>> _coreLocationProvider;
     BOOL _isWebCoreGeolocationActive;
     RefPtr<WebGeolocationPosition> _lastActivePosition;
     Vector<GeolocationRequestData> _requestsWaitingForCoreLocationAuthorization;
@@ -148,7 +163,8 @@ static void setEnableHighAccuracy(WKGeolocationManagerRef geolocationManager, bo
         setEnableHighAccuracy
     };
     _geolocationManager->initializeProvider(reinterpret_cast<WKGeolocationProviderBase*>(&providerCallback));
-    _coreLocationProvider = adoptNS([[WebGeolocationCoreLocationProvider alloc] initWithListener:self]);
+    _coreLocationProvider = wrapper(processPool)._coreLocationProvider ?: adoptNS(static_cast<id <_WKGeolocationCoreLocationProvider>>([[WKLegacyCoreLocationProvider alloc] init]));
+    [_coreLocationProvider setListener:self];
     return self;
 }
 
@@ -177,6 +193,22 @@ static void setEnableHighAccuracy(WKGeolocationManagerRef geolocationManager, bo
         bool requiresUserAuthorization = true;
 
         id<WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([request.view UIDelegate]);
+        if ([uiDelegate respondsToSelector:@selector(_webView:requestGeolocationAuthorizationForURL:frame:decisionHandler:)]) {
+            URL requestFrameURL(URL(), request.frame->url());
+            RetainPtr<WKFrameInfo> frameInfo = wrapper(API::FrameInfo::create(*request.frame.get(), *request.origin.get()));
+            RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(uiDelegate, @selector(_webView:requestGeolocationAuthorizationForURL:frame:decisionHandler:));
+            [uiDelegate _webView:request.view.get() requestGeolocationAuthorizationForURL:requestFrameURL frame:frameInfo.get() decisionHandler:BlockPtr<void(BOOL)>::fromCallable([request, checker = WTFMove(checker)](BOOL authorized) {
+                if (checker->completionHandlerHasBeenCalled())
+                    return;
+                if (authorized)
+                    request.permissionRequest->allow();
+                else
+                    request.permissionRequest->deny();
+                checker->didCallCompletionHandler();
+            }).get()];
+            return;
+        }
+
         if ([uiDelegate respondsToSelector:@selector(_webView:shouldRequestGeolocationAuthorizationForURL:isMainFrame:mainFrameURL:)]) {
             const WebFrameProxy* mainFrame = request.frame->page()->mainFrame();
             bool isMainFrame = request.frame == mainFrame;
@@ -203,9 +235,9 @@ static void setEnableHighAccuracy(WKGeolocationManagerRef geolocationManager, bo
         requestData.permissionRequest->deny();
 }
 
-- (void)positionChanged:(GeolocationPosition*)position
+- (void)positionChanged:(_WKGeolocationPosition *)position
 {
-    _lastActivePosition = WebGeolocationPosition::create(position->timestamp(), position->latitude(), position->longitude(), position->accuracy(), position->canProvideAltitude(), position->altitude(), position->canProvideAltitudeAccuracy(), position->altitudeAccuracy(), position->canProvideHeading(), position->heading(), position->canProvideSpeed(), position->speed());
+    _lastActivePosition = position->_geolocationPosition.get();
     _geolocationManager->providerDidChangePosition(_lastActivePosition.get());
 }
 
@@ -221,6 +253,81 @@ static void setEnableHighAccuracy(WKGeolocationManagerRef geolocationManager, bo
 
 @end
 
+# pragma mark - Implementation of WKLegacyCoreLocationProvider
+
+@implementation WKLegacyCoreLocationProvider {
+    id <_WKGeolocationCoreLocationListener> _listener;
+    RetainPtr<WebGeolocationCoreLocationProvider> _provider;
+}
+
+// <_WKGeolocationCoreLocationProvider> Methods
+
+- (void)setListener:(id<_WKGeolocationCoreLocationListener>)listener
+{
+    ASSERT(listener && !_listener && !_provider);
+    _listener = listener;
+    _provider = adoptNS([[WebGeolocationCoreLocationProvider alloc] initWithListener:self]);
+}
+
+- (void)requestGeolocationAuthorization
+{
+    ASSERT(_provider);
+    [_provider requestGeolocationAuthorization];
+}
+
+- (void)start
+{
+    ASSERT(_provider);
+    [_provider start];
+}
+
+- (void)stop
+{
+    ASSERT(_provider);
+    [_provider stop];
+}
+
+- (void)setEnableHighAccuracy:(BOOL)flag
+{
+    ASSERT(_provider);
+    [_provider setEnableHighAccuracy:flag];
+}
+
+// <WebGeolocationCoreLocationUpdateListener> Methods
+
+- (void)geolocationAuthorizationGranted
+{
+    ASSERT(_listener);
+    [_listener geolocationAuthorizationGranted];
+}
+
+- (void)geolocationAuthorizationDenied
+{
+    ASSERT(_listener);
+    [_listener geolocationAuthorizationDenied];
+}
+
+- (void)positionChanged:(WebCore::GeolocationPosition *)corePosition
+{
+    ASSERT(_listener);
+    auto position = kit(corePosition);
+    [_listener positionChanged:wrapper(position.get())];
+}
+
+- (void)errorOccurred:(NSString *)errorMessage
+{
+    ASSERT(_listener);
+    [_listener errorOccurred:errorMessage];
+}
+
+- (void)resetGeolocation
+{
+    ASSERT(_listener);
+    [_listener resetGeolocation];
+}
+
+@end
+
 # pragma mark - Implementation of WKWebAllowDenyPolicyListener
 @implementation WKWebAllowDenyPolicyListener {
     RefPtr<GeolocationPermissionRequestProxy> _permissionRequestProxy;
index 7f31f80..0fd426e 100644 (file)
                5CD286581E7235D10094FDC8 /* WKContentExtensionStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD286501E722F440094FDC8 /* WKContentExtensionStorePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5CE85B201C88E64B0070BFCE /* PingLoad.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE85B1F1C88E6430070BFCE /* PingLoad.h */; };
                5CFECB041E1ED1CC00F88504 /* LegacyCustomProtocolManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CFECB031E1ED1C800F88504 /* LegacyCustomProtocolManager.cpp */; };
+               636353A51E9858DF0009F8AF /* _WKGeolocationCoreLocationProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FABE191E970D65003011D5 /* _WKGeolocationCoreLocationProvider.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               63C32C251E9810D900699BD0 /* _WKGeolocationPosition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 63C32C231E9810D900699BD0 /* _WKGeolocationPosition.mm */; };
+               63C32C261E9810D900699BD0 /* _WKGeolocationPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = 63C32C241E9810D900699BD0 /* _WKGeolocationPosition.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               63C32C281E98119000699BD0 /* _WKGeolocationPositionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 63C32C271E98119000699BD0 /* _WKGeolocationPositionInternal.h */; };
                6501BD1A12F1243400E9F248 /* WKBundleInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65B86F1712F11D7B00B7DD8A /* WKBundleInspector.cpp */; };
                659C551E130006410025C0C2 /* InjectedBundlePageResourceLoadClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6546A82913000164000CEB1C /* InjectedBundlePageResourceLoadClient.cpp */; };
                65B86F1E12F11DE300B7DD8A /* WKBundleInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B86F1812F11D7B00B7DD8A /* WKBundleInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5CFECB031E1ED1C800F88504 /* LegacyCustomProtocolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LegacyCustomProtocolManager.cpp; path = NetworkProcess/CustomProtocols/LegacyCustomProtocolManager.cpp; sourceTree = "<group>"; };
                5D442A5516D5856700AC3331 /* PluginService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PluginService.entitlements; sourceTree = "<group>"; };
                5DAD73F1116FF90C00EE5396 /* BaseTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = BaseTarget.xcconfig; sourceTree = "<group>"; };
+               63C32C231E9810D900699BD0 /* _WKGeolocationPosition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKGeolocationPosition.mm; sourceTree = "<group>"; };
+               63C32C241E9810D900699BD0 /* _WKGeolocationPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKGeolocationPosition.h; sourceTree = "<group>"; };
+               63C32C271E98119000699BD0 /* _WKGeolocationPositionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKGeolocationPositionInternal.h; sourceTree = "<group>"; };
+               63FABE191E970D65003011D5 /* _WKGeolocationCoreLocationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _WKGeolocationCoreLocationProvider.h; sourceTree = "<group>"; };
                6546A82913000164000CEB1C /* InjectedBundlePageResourceLoadClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundlePageResourceLoadClient.cpp; sourceTree = "<group>"; };
                6546A82A13000164000CEB1C /* InjectedBundlePageResourceLoadClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundlePageResourceLoadClient.h; sourceTree = "<group>"; };
                65B86F1712F11D7B00B7DD8A /* WKBundleInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKBundleInspector.cpp; sourceTree = "<group>"; };
                                2E7A94491BBD95C600945547 /* _WKFocusedElementInfo.h */,
                                37A64E5618F38F4600EB30F1 /* _WKFormInputSession.h */,
                                CD78E1181DB7E5AD0014A2DE /* _WKFullscreenDelegate.h */,
+                               63FABE191E970D65003011D5 /* _WKGeolocationCoreLocationProvider.h */,
+                               63C32C241E9810D900699BD0 /* _WKGeolocationPosition.h */,
+                               63C32C231E9810D900699BD0 /* _WKGeolocationPosition.mm */,
+                               63C32C271E98119000699BD0 /* _WKGeolocationPositionInternal.h */,
                                5143B25E1DDCDFD10014FAC6 /* _WKIconLoadingDelegate.h */,
                                37A64E5418F38E3C00EB30F1 /* _WKInputDelegate.h */,
                                2D790A9C1AD7050D00AB90B3 /* _WKLayoutMode.h */,
                                93A88B3B1BC710D900ABA5C2 /* _WKHitTestResultInternal.h in Headers */,
                                510F59101DDE296900412FF5 /* _WKIconLoadingDelegate.h in Headers */,
                                37A64E5518F38E3C00EB30F1 /* _WKInputDelegate.h in Headers */,
+                               63C32C281E98119000699BD0 /* _WKGeolocationPositionInternal.h in Headers */,
                                2D790A9D1AD7050D00AB90B3 /* _WKLayoutMode.h in Headers */,
                                510F59111DDE297000412FF5 /* _WKLinkIconParameters.h in Headers */,
                                A118A9F31908B8EA00F7C92B /* _WKNSFileManagerExtras.h in Headers */,
                                BCCF6B2512C93E7A008F9C35 /* ImageOptions.h in Headers */,
                                1A1EC69E1872092100B951F0 /* ImportanceAssertion.h in Headers */,
                                BC204EE311C83E98008F3375 /* InjectedBundle.h in Headers */,
+                               636353A51E9858DF0009F8AF /* _WKGeolocationCoreLocationProvider.h in Headers */,
                                935EEBA2127761D0003322B8 /* InjectedBundleBackForwardList.h in Headers */,
                                935EEBA4127761D6003322B8 /* InjectedBundleBackForwardListItem.h in Headers */,
                                BCEE7DC5128B645D009827DA /* InjectedBundleClient.h in Headers */,
                                BC14DF9F120B635F00826C0C /* WKBundleScriptWorld.h in Headers */,
                                BC4075F6124FF0270068F20A /* WKCertificateInfo.h in Headers */,
                                BC407627124FF0400068F20A /* WKCertificateInfoMac.h in Headers */,
+                               63C32C261E9810D900699BD0 /* _WKGeolocationPosition.h in Headers */,
                                BCA284D71492F2C7001F9042 /* WKConnection.h in Headers */,
                                BC5C75C814954DA600BC4775 /* WKConnectionInternal.h in Headers */,
                                BC4A6297147313A0006C681A /* WKConnectionRef.h in Headers */,
                                2DA944A31884E4F000ED86DB /* WebTouchEventIOS.cpp in Sources */,
                                BCA0EF8012331E78007D3CFB /* WebUndoStep.cpp in Sources */,
                                51D124281E6D3F5D002B2820 /* WebURLSchemeHandler.cpp in Sources */,
+                               63C32C251E9810D900699BD0 /* _WKGeolocationPosition.mm in Sources */,
                                51D124331E6DE6CA002B2820 /* WebURLSchemeHandlerCocoa.mm in Sources */,
                                51D1242C1E6D41FD002B2820 /* WebURLSchemeHandlerProxy.cpp in Sources */,
                                51E8B68E1E712877001B7132 /* WebURLSchemeHandlerTask.cpp in Sources */,
index 826d2b4..39f2b86 100644 (file)
@@ -1,3 +1,31 @@
+2017-04-11  David Quesada  <david_quesada@apple.com>
+
+        Add SPI for handling geolocation authorization requests
+        https://bugs.webkit.org/show_bug.cgi?id=170362
+        rdar://problem/17508627
+
+        Reviewed by Alex Christensen.
+
+        Add API tests for the new WKUIDelegate SPI for allowing or denying websites permission
+        to use geolocation. Adopt the new WKProcessPool._coreLocationProvider property to
+        provide a stub object to simulate the various configurations of geolocation permissions:
+        1. The app doesn't have permission to use geolocation.
+        2. The app is allowed to use geolocation, but the UI delegate denies the web view permission.
+        3. The app is allowed to use geolocation, and the UI delegate allows the web view permission.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/Geolocation.mm: Added.
+        (-[TestCoreLocationProvider setListener:]):
+        (-[TestCoreLocationProvider requestGeolocationAuthorization]):
+        (-[TestCoreLocationProvider start]):
+        (-[TestCoreLocationProvider stop]):
+        (-[TestCoreLocationProvider setEnableHighAccuracy:]):
+        (expectException):
+        (-[GeolocationTestUIDelegate _webView:requestGeolocationAuthorizationForURL:frame:decisionHandler:]):
+        (-[GeolocationTestUIDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/GeolocationGetCurrentPositionResult.html: Added.
+
 2017-04-10  Matt Rajca  <mrajca@apple.com>
 
         Change autoplay state to "prevented" when media is paused due to restrictions.
index 9e718f6..6c0da79 100644 (file)
                5C9E59431D3EB5AC00E3C62E /* ApplicationCache.db-wal in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5C9E59401D3EB1DE00E3C62E /* ApplicationCache.db-wal */; };
                5CE354D91E70DA5C00BEFE3B /* WKUserContentExtensionStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5CE354D81E70D9C300BEFE3B /* WKUserContentExtensionStore.mm */; };
                5E4B1D2E1D404C6100053621 /* WKScrollViewDelegateCrash.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E4B1D2C1D404C6100053621 /* WKScrollViewDelegateCrash.mm */; };
+               631EFFF61E7B5E8D00D2EBB8 /* Geolocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 631EFFF51E7B5E8D00D2EBB8 /* Geolocation.mm */; };
+               634910E01E9D3FF300880309 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 634910DF1E9D3FF300880309 /* CoreLocation.framework */; };
+               636353A71E98665D0009F8AF /* GeolocationGetCurrentPositionResult.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */; };
                6BFD294C1D5E6C1D008EC968 /* HashCountedSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A38D7E51C752D5F004F157D /* HashCountedSet.cpp */; };
                755A20AF1E6E38630093C69F /* DatabaseTrackerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 755A20AE1E6E38630093C69F /* DatabaseTrackerTest.cpp */; };
                764322D71B61CCC30024F801 /* WordBoundaryTypingAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 764322D51B61CCA40024F801 /* WordBoundaryTypingAttributes.mm */; };
                                379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
                                1C2B81871C8925A000A5529F /* Ahem.ttf in Copy Resources */,
                                1A63479F183D72A4005B1707 /* all-content-in-one-iframe.html in Copy Resources */,
+                               636353A71E98665D0009F8AF /* GeolocationGetCurrentPositionResult.html in Copy Resources */,
                                C25CCA0D1E5141840026CB8A /* AllAhem.svg in Copy Resources */,
                                5C9E59411D3EB5AC00E3C62E /* ApplicationCache.db in Copy Resources */,
                                5C9E59421D3EB5AC00E3C62E /* ApplicationCache.db-shm in Copy Resources */,
                5C9E59401D3EB1DE00E3C62E /* ApplicationCache.db-wal */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ApplicationCache.db-wal"; sourceTree = "<group>"; };
                5CE354D81E70D9C300BEFE3B /* WKUserContentExtensionStore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKUserContentExtensionStore.mm; sourceTree = "<group>"; };
                5E4B1D2C1D404C6100053621 /* WKScrollViewDelegateCrash.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKScrollViewDelegateCrash.mm; path = ../ios/WKScrollViewDelegateCrash.mm; sourceTree = "<group>"; };
+               631EFFF51E7B5E8D00D2EBB8 /* Geolocation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Geolocation.mm; sourceTree = "<group>"; };
+               634910DF1E9D3FF300880309 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
+               636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = GeolocationGetCurrentPositionResult.html; sourceTree = "<group>"; };
                755A20AE1E6E38630093C69F /* DatabaseTrackerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseTrackerTest.cpp; sourceTree = "<group>"; };
                7560917719259C59009EF06E /* MemoryCacheAddImageToCacheIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryCacheAddImageToCacheIOS.mm; sourceTree = "<group>"; };
                75F3133F18C171B70041CAEC /* EphemeralSessionPushStateNoHistoryCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EphemeralSessionPushStateNoHistoryCallback.cpp; sourceTree = "<group>"; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               634910E01E9D3FF300880309 /* CoreLocation.framework in Frameworks */,
                                7A010BCB1D877C0500EDE72A /* CoreGraphics.framework in Frameworks */,
                                7C83E03F1D0A61A000FEBCF3 /* libicucore.dylib in Frameworks */,
                                7A010BCD1D877C0D00EDE72A /* QuartzCore.framework in Frameworks */,
                                CD78E11A1DB7EA360014A2DE /* FullscreenDelegate.mm */,
                                3F1B52681D3D7129008D60C4 /* FullscreenLayoutConstraints.mm */,
                                CDE195B31CFE0ADE0053D256 /* FullscreenTopContentInset.mm */,
+                               631EFFF51E7B5E8D00D2EBB8 /* Geolocation.mm */,
                                510477751D298E03009747EB /* IDBDeleteRecovery.mm */,
                                5110FCEF1E01CBAA006F8D0B /* IDBIndexUpgradeToV2.mm */,
                                51A587841D272EF3004BA9AF /* IndexedDBDatabaseProcessKill.mm */,
                7C83E0281D0A5CDF00FEBCF3 /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               634910DF1E9D3FF300880309 /* CoreLocation.framework */,
                                7A010BCA1D877C0500EDE72A /* CoreGraphics.framework */,
                                7C83E0331D0A5F2700FEBCF3 /* libicucore.dylib */,
                                7C83E0291D0A5CDF00FEBCF3 /* libWTF.a */,
                                CD78E11B1DB7EA360014A2DE /* FullscreenDelegate.html */,
                                3FBD1B491D39D1DB00E6D6FA /* FullscreenLayoutConstraints.html */,
                                CDE195B21CFE0ADE0053D256 /* FullscreenTopContentInset.html */,
+                               636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */,
                                F4DEF6EC1E9B4D950048EF61 /* image-in-link-and-input.html */,
                                510477761D298E57009747EB /* IDBDeleteRecovery.html */,
                                5104776F1D298D85009747EB /* IDBDeleteRecovery.sqlite3 */,
                                7C83E0BD1D0A650C00FEBCF3 /* FullscreenTopContentInset.mm in Sources */,
                                CDBFCC451A9FF45300A7B691 /* FullscreenZoomInitialFrame.mm in Sources */,
                                7CCE7EF81A411AE600447C4C /* Geolocation.cpp in Sources */,
+                               631EFFF61E7B5E8D00D2EBB8 /* Geolocation.mm in Sources */,
                                7CCE7EE11A411A9A00447C4C /* GetBackingScaleFactor.mm in Sources */,
                                7CCE7EF91A411AE600447C4C /* GetInjectedBundleInitializationUserDataCallback.cpp in Sources */,
                                7CCE7EE21A411A9A00447C4C /* GetPIDAfterAbortedProcessLaunch.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/Geolocation.mm b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/Geolocation.mm
new file mode 100644 (file)
index 0000000..8bc9a09
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if WK_API_ENABLED && PLATFORM(IOS)
+
+#import "PlatformUtilities.h"
+#import "TestWKWebView.h"
+#import <CoreLocation/CLLocation.h>
+#import <WebKit/WKProcessPoolPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/_WKGeolocationCoreLocationProvider.h>
+#import <WebKit/_WKGeolocationPosition.h>
+#import <wtf/MainThread.h>
+#import <wtf/RetainPtr.h>
+
+static bool hasReceivedAlert;
+
+@interface TestCoreLocationProvider : NSObject<_WKGeolocationCoreLocationProvider>
+@property (nonatomic) BOOL shouldAuthorizeGeolocation;
+@property (nonatomic) BOOL authorizationWasRequested;
+@property (nonatomic) BOOL simulateError;
+@end
+
+@implementation TestCoreLocationProvider {
+    __unsafe_unretained id <_WKGeolocationCoreLocationListener> _listener;
+}
+
+// _WKGeolocationCoreLocationProvider implementation
+
+- (void)setListener:(id <_WKGeolocationCoreLocationListener>)listener
+{
+    ASSERT(!_listener);
+    _listener = listener;
+}
+
+- (void)requestGeolocationAuthorization
+{
+    _authorizationWasRequested = YES;
+    WTF::callOnMainThread([shouldAuthorizeGeolocation = _shouldAuthorizeGeolocation, listener = _listener] {
+        if (shouldAuthorizeGeolocation)
+            [listener geolocationAuthorizationGranted];
+        else
+            [listener geolocationAuthorizationDenied];
+    });
+}
+
+- (void)start
+{
+    ASSERT(_shouldAuthorizeGeolocation);
+    WTF::callOnMainThread([listener = _listener, simulateError = _simulateError] {
+        if (!simulateError) {
+            auto location = adoptNS([[CLLocation alloc] initWithLatitude:37.3348 longitude:-122.009]);
+            [listener positionChanged:[_WKGeolocationPosition positionWithLocation:location.get()]];
+        } else
+            [listener errorOccurred:@"Error Message"];
+    });
+}
+
+- (void)stop
+{
+}
+
+- (void)setEnableHighAccuracy:(BOOL)flag
+{
+}
+
+@end
+
+@interface GeolocationTestUIDelegate : NSObject <WKUIDelegatePrivate>
+
+@property (nonatomic) BOOL allowGeolocation;
+@property (nonatomic) BOOL callDecisionHandlerTwice;
+@property (nonatomic) BOOL authorizationWasRequested;
+@property (nonatomic, readonly) NSString *alertMessage;
+
+@end
+
+@implementation GeolocationTestUIDelegate
+
+static void expectException(void (^completionHandler)())
+{
+    bool exceptionThrown = false;
+    @try {
+        completionHandler();
+    } @catch (NSException *exception) {
+        EXPECT_WK_STREQ(NSInternalInconsistencyException, exception.name);
+        exceptionThrown = true;
+    }
+    EXPECT_TRUE(exceptionThrown);
+}
+
+- (void)_webView:(WKWebView *)webView requestGeolocationAuthorizationForURL:(NSURL *)url frame:(WKFrameInfo *)frame decisionHandler:(void (^)(BOOL))decisionHandler
+{
+    _authorizationWasRequested = YES;
+    decisionHandler(_allowGeolocation);
+
+    if (_callDecisionHandlerTwice) {
+        expectException(^ {
+            decisionHandler(_allowGeolocation);
+        });
+    }
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
+{
+    completionHandler();
+    _alertMessage = message;
+    hasReceivedAlert = true;
+}
+
+@end
+
+
+using namespace std;
+
+namespace TestWebKitAPI {
+
+// These tests need to use TestWKWebView because it sets up a visible window for the web
+// view. Without this, the web process would wait until the page is visible before sending
+// the requests to the UI process.
+
+TEST(WebKit2, GeolocationDeniedByLocationProvider)
+{
+    auto uiDelegate = adoptNS([[GeolocationTestUIDelegate alloc] init]);
+    auto coreLocationProvider = adoptNS([[TestCoreLocationProvider alloc] init]);
+    auto processPool = adoptNS([[WKProcessPool alloc] init]);
+    processPool.get()._coreLocationProvider = coreLocationProvider.get();
+    auto config = adoptNS([[WKWebViewConfiguration alloc] init]);
+    config.get().processPool = processPool.get();
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:config.get()]);
+    webView.get().UIDelegate = uiDelegate.get();
+
+    coreLocationProvider.get().shouldAuthorizeGeolocation = NO;
+    uiDelegate.get().allowGeolocation = NO;
+    
+    hasReceivedAlert = false;
+    [webView loadTestPageNamed:@"GeolocationGetCurrentPositionResult"];
+
+    TestWebKitAPI::Util::run(&hasReceivedAlert);
+
+    EXPECT_WK_STREQ(uiDelegate.get().alertMessage, "ERROR:1");
+    EXPECT_TRUE(coreLocationProvider.get().authorizationWasRequested);
+    EXPECT_FALSE(uiDelegate.get().authorizationWasRequested);
+}
+
+TEST(WebKit2, GeolocationDeniedByAPI)
+{
+    auto uiDelegate = adoptNS([[GeolocationTestUIDelegate alloc] init]);
+    auto coreLocationProvider = adoptNS([[TestCoreLocationProvider alloc] init]);
+    auto processPool = adoptNS([[WKProcessPool alloc] init]);
+    processPool.get()._coreLocationProvider = coreLocationProvider.get();
+    auto config = adoptNS([[WKWebViewConfiguration alloc] init]);
+    config.get().processPool = processPool.get();
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:config.get()]);
+    webView.get().UIDelegate = uiDelegate.get();
+
+    coreLocationProvider.get().shouldAuthorizeGeolocation = YES;
+    uiDelegate.get().allowGeolocation = NO;
+
+    hasReceivedAlert = false;
+    [webView loadTestPageNamed:@"GeolocationGetCurrentPositionResult"];
+
+    TestWebKitAPI::Util::run(&hasReceivedAlert);
+
+    EXPECT_WK_STREQ(uiDelegate.get().alertMessage, "ERROR:1");
+    EXPECT_TRUE(coreLocationProvider.get().authorizationWasRequested);
+    EXPECT_TRUE(uiDelegate.get().authorizationWasRequested);
+}
+
+TEST(WebKit2, GeolocationAllowedByAPI)
+{
+    auto uiDelegate = adoptNS([[GeolocationTestUIDelegate alloc] init]);
+    auto coreLocationProvider = adoptNS([[TestCoreLocationProvider alloc] init]);
+    auto processPool = adoptNS([[WKProcessPool alloc] init]);
+    processPool.get()._coreLocationProvider = coreLocationProvider.get();
+    auto config = adoptNS([[WKWebViewConfiguration alloc] init]);
+    config.get().processPool = processPool.get();
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:config.get()]);
+    webView.get().UIDelegate = uiDelegate.get();
+
+    coreLocationProvider.get().shouldAuthorizeGeolocation = YES;
+    uiDelegate.get().allowGeolocation = YES;
+
+    hasReceivedAlert = false;
+    [webView loadTestPageNamed:@"GeolocationGetCurrentPositionResult"];
+
+    TestWebKitAPI::Util::run(&hasReceivedAlert);
+
+    EXPECT_WK_STREQ(uiDelegate.get().alertMessage, "SUCCESS");
+    EXPECT_TRUE(coreLocationProvider.get().authorizationWasRequested);
+    EXPECT_TRUE(uiDelegate.get().authorizationWasRequested);
+}
+
+TEST(WebKit2, GeolocationError)
+{
+    auto uiDelegate = adoptNS([[GeolocationTestUIDelegate alloc] init]);
+    auto coreLocationProvider = adoptNS([[TestCoreLocationProvider alloc] init]);
+    auto processPool = adoptNS([[WKProcessPool alloc] init]);
+    processPool.get()._coreLocationProvider = coreLocationProvider.get();
+    auto config = adoptNS([[WKWebViewConfiguration alloc] init]);
+    config.get().processPool = processPool.get();
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:config.get()]);
+    webView.get().UIDelegate = uiDelegate.get();
+
+    coreLocationProvider.get().shouldAuthorizeGeolocation = YES;
+    coreLocationProvider.get().simulateError = YES;
+    uiDelegate.get().allowGeolocation = YES;
+
+    hasReceivedAlert = false;
+    [webView loadTestPageNamed:@"GeolocationGetCurrentPositionResult"];
+
+    TestWebKitAPI::Util::run(&hasReceivedAlert);
+
+    EXPECT_WK_STREQ(uiDelegate.get().alertMessage, "ERROR:2");
+    EXPECT_TRUE(coreLocationProvider.get().authorizationWasRequested);
+    EXPECT_TRUE(uiDelegate.get().authorizationWasRequested);
+}
+
+TEST(WebKit2, DuplicateGeolocationAuthorizationCallbackCalls)
+{
+    auto uiDelegate = adoptNS([[GeolocationTestUIDelegate alloc] init]);
+    auto coreLocationProvider = adoptNS([[TestCoreLocationProvider alloc] init]);
+    auto processPool = adoptNS([[WKProcessPool alloc] init]);
+    processPool.get()._coreLocationProvider = coreLocationProvider.get();
+    auto config = adoptNS([[WKWebViewConfiguration alloc] init]);
+    config.get().processPool = processPool.get();
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:config.get()]);
+    webView.get().UIDelegate = uiDelegate.get();
+
+    coreLocationProvider.get().shouldAuthorizeGeolocation = YES;
+    uiDelegate.get().allowGeolocation = YES;
+    uiDelegate.get().callDecisionHandlerTwice = YES;
+
+    hasReceivedAlert = false;
+    [webView loadTestPageNamed:@"GeolocationGetCurrentPositionResult"];
+
+    TestWebKitAPI::Util::run(&hasReceivedAlert);
+
+    EXPECT_WK_STREQ(uiDelegate.get().alertMessage, "SUCCESS");
+    EXPECT_TRUE(coreLocationProvider.get().authorizationWasRequested);
+    EXPECT_TRUE(uiDelegate.get().authorizationWasRequested);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // WK_API_ENABLED && PLATFORM(IOS)
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/GeolocationGetCurrentPositionResult.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/GeolocationGetCurrentPositionResult.html
new file mode 100644 (file)
index 0000000..4ba3677
--- /dev/null
@@ -0,0 +1,9 @@
+<script>
+function success(position) {
+    alert("SUCCESS");
+}
+function error(err) {
+    alert("ERROR:" + err.code);
+}
+navigator.geolocation.getCurrentPosition(success, error);
+</script>