Remember device orientation permission for the duration of the browsing session
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Apr 2019 17:03:59 +0000 (17:03 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Apr 2019 17:03:59 +0000 (17:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196992
<rdar://problem/49946067>

Reviewed by Alex Christensen.

Source/WebCore:

Use DeviceOrientationOrMotionPermissionState type more consistently in the code base
instead of bool or Optional<bool>. Added "Prompt" value to this enumeration which is the
default state and which indicates we should ask the client.

* WebCore.xcodeproj/project.pbxproj:
* dom/DeviceOrientationAndMotionAccessController.cpp:
(WebCore::DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessController):
(WebCore::DeviceOrientationAndMotionAccessController::shouldAllowAccess):
* dom/DeviceOrientationAndMotionAccessController.h:
(WebCore::DeviceOrientationAndMotionAccessController::accessState const):
* dom/DeviceOrientationOrMotionEvent.cpp:
(WebCore::DeviceOrientationOrMotionEvent::requestPermission):
* dom/DeviceOrientationOrMotionPermissionState.h:
* loader/DocumentLoader.h:
(WebCore::DocumentLoader::deviceOrientationAndMotionAccessState const):
(WebCore::DocumentLoader::setDeviceOrientationAndMotionAccessState):
* page/ChromeClient.h:
* page/DOMWindow.cpp:
(WebCore::DOMWindow::isAllowedToAddDeviceMotionOrientationListener const):

Source/WebKit:

Implement caching of device orientation permission decisions on the WebDeviceOrientationAndMotionAccessController,
which is owned by the WebsiteDataStore. This way, if we already prompted the user of a given origin, we will
remember the previous decision for the duration of the session and not prompt again.

* Shared/WebsitePoliciesData.cpp:
(WebKit::WebsitePoliciesData::encode const):
(WebKit::WebsitePoliciesData::decode):
* Shared/WebsitePoliciesData.h:
* UIProcess/API/APIWebsitePolicies.cpp:
(API::WebsitePolicies::copy const):
(API::WebsitePolicies::data):
* UIProcess/API/APIWebsitePolicies.h:
* UIProcess/API/Cocoa/WKWebpagePreferences.mm:
(toDeviceOrientationOrMotionPermissionState):
(-[WKWebpagePreferences _setDeviceOrientationAndMotionAccessPolicy:]):
(toWKWebsiteDeviceOrientationAndMotionAccessPolicy):
(-[WKWebpagePreferences _deviceOrientationAndMotionAccessPolicy]):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::shouldAllowDeviceOrientationAndMotionAccess):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp: Added.
(WebKit::WebDeviceOrientationAndMotionAccessController::shouldAllowDeviceOrientationAndMotionAccess):
(WebKit::WebDeviceOrientationAndMotionAccessController::deviceOrientationPermission const):
* UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.h: Copied from Source/WebCore/dom/DeviceOrientationAndMotionAccessController.h.
* UIProcess/WebsiteData/WebsiteDataStore.h:
(WebKit::WebsiteDataStore::deviceOrientationAndMotionAccessController):
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::shouldAllowDeviceOrientationAndMotionAccess):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::shouldAllowDeviceOrientationAndMotionAccess):
* WebProcess/WebPage/WebPage.h:

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/DeviceOrientation.mm:
(-[DeviceOrientationPermissionUIDelegate _webView:shouldAllowDeviceOrientationAndMotionAccessRequestedByFrame:decisionHandler:]):
(TEST):

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

34 files changed:
LayoutTests/fast/device-orientation/device-motion-request-permission-user-gesture-expected.txt
LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/DeviceOrientationAndMotionAccessController.cpp
Source/WebCore/dom/DeviceOrientationAndMotionAccessController.h
Source/WebCore/dom/DeviceOrientationOrMotionEvent.cpp
Source/WebCore/dom/DeviceOrientationOrMotionPermissionState.h
Source/WebCore/loader/DocumentLoader.h
Source/WebCore/page/ChromeClient.h
Source/WebCore/page/DOMWindow.cpp
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebsitePoliciesData.cpp
Source/WebKit/Shared/WebsitePoliciesData.h
Source/WebKit/Sources.txt
Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp
Source/WebKit/UIProcess/API/APIWebsitePolicies.h
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h
Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.mm
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/DeviceOrientation.mm
Tools/WebKitTestRunner/TestController.cpp

index 89ce6b5..56d0536 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 14: NotAllowedError: Requesting device orientation or motion access requires a user gesture
+CONSOLE MESSAGE: line 14: NotAllowedError: Requesting device orientation or motion access requires a user gesture to prompt
 Tests that DeviceMotionEvent.requestPermission() requires a user gesture.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
index 6093b24..49e7a30 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 14: NotAllowedError: Requesting device orientation or motion access requires a user gesture
+CONSOLE MESSAGE: line 14: NotAllowedError: Requesting device orientation or motion access requires a user gesture to prompt
 Tests that DeviceOrientationEvent.requestPermission() requires a user gesture.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
index 04e4bdb..86b5f3c 100644 (file)
@@ -1,3 +1,31 @@
+2019-04-17  Chris Dumez  <cdumez@apple.com>
+
+        Remember device orientation permission for the duration of the browsing session
+        https://bugs.webkit.org/show_bug.cgi?id=196992
+        <rdar://problem/49946067>
+
+        Reviewed by Alex Christensen.
+
+        Use DeviceOrientationOrMotionPermissionState type more consistently in the code base
+        instead of bool or Optional<bool>. Added "Prompt" value to this enumeration which is the
+        default state and which indicates we should ask the client.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/DeviceOrientationAndMotionAccessController.cpp:
+        (WebCore::DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessController):
+        (WebCore::DeviceOrientationAndMotionAccessController::shouldAllowAccess):
+        * dom/DeviceOrientationAndMotionAccessController.h:
+        (WebCore::DeviceOrientationAndMotionAccessController::accessState const):
+        * dom/DeviceOrientationOrMotionEvent.cpp:
+        (WebCore::DeviceOrientationOrMotionEvent::requestPermission):
+        * dom/DeviceOrientationOrMotionPermissionState.h:
+        * loader/DocumentLoader.h:
+        (WebCore::DocumentLoader::deviceOrientationAndMotionAccessState const):
+        (WebCore::DocumentLoader::setDeviceOrientationAndMotionAccessState):
+        * page/ChromeClient.h:
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::isAllowedToAddDeviceMotionOrientationListener const):
+
 2019-04-17  Rob Buis  <rbuis@igalia.com>
 
         XMLHttpRequest has the wrong fallback encoding
index 8f84328..85db74a 100644 (file)
                460BB6161D0A1BF000221812 /* Base64Utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 460BB6141D0A1BEC00221812 /* Base64Utilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
                460CBF361D4BCD0E0092E88E /* JSDOMWindowProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 460CBF341D4BCCFE0092E88E /* JSDOMWindowProperties.h */; };
                460E3075222F4EFD009A0606 /* DeviceOrientationOrMotionEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 461DA52A222F486F00D05A87 /* DeviceOrientationOrMotionEvent.h */; };
-               460E3077222F4F03009A0606 /* DeviceOrientationOrMotionPermissionState.h in Headers */ = {isa = PBXBuildFile; fileRef = 465EDD9F222F4EC300B46E16 /* DeviceOrientationOrMotionPermissionState.h */; };
+               460E3077222F4F03009A0606 /* DeviceOrientationOrMotionPermissionState.h in Headers */ = {isa = PBXBuildFile; fileRef = 465EDD9F222F4EC300B46E16 /* DeviceOrientationOrMotionPermissionState.h */; settings = {ATTRIBUTES = (Private, ); }; };
                46218ACB1F72D64E00574FBE /* DOMHighResTimeStamp.h in Headers */ = {isa = PBXBuildFile; fileRef = 46E016AD1F72D61E00282B2C /* DOMHighResTimeStamp.h */; settings = {ATTRIBUTES = (Private, ); }; };
                463521AD2081092A00C28922 /* WindowProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 463521AA2081090B00C28922 /* WindowProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
                463EB6231B8789E00096ED51 /* TagCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 463EB6211B8789CB0096ED51 /* TagCollection.h */; };
index d86c160..100aaf1 100644 (file)
@@ -43,54 +43,39 @@ DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessCont
     : m_document(document)
 {
     ASSERT(&m_document.topDocument() == &m_document);
-}
-
-void DeviceOrientationAndMotionAccessController::shouldAllowAccess(Function<void(ExceptionOr<bool> granted)>&& callback)
-{
-    if (auto accessState = this->accessState())
-        return callback(*accessState);
-    ASSERT(m_document.frame());
-
-    if (!UserGestureIndicator::processingUserGesture())
-        return callback(Exception { NotAllowedError, "Requesting device orientation or motion access requires a user gesture"_s });
 
-    auto* page = m_document.page();
-    if (!page)
-        return callback(false);
-
-    m_pendingRequests.append(WTFMove(callback));
-    if (m_pendingRequests.size() > 1)
-        return;
-
-    page->chrome().client().shouldAllowDeviceOrientationAndMotionAccess(*m_document.frame(), [this, weakThis = makeWeakPtr(*this)](bool granted) mutable {
-        if (weakThis)
-            setAccessState(granted);
-    });
+    // Initial value is based on the per-site setting.
+    auto* frame = m_document.frame();
+    if (auto* documentLoader = frame ? frame->loader().documentLoader() : nullptr)
+        m_accessState = documentLoader->deviceOrientationAndMotionAccessState();
 }
 
-void DeviceOrientationAndMotionAccessController::setAccessState(bool granted)
+void DeviceOrientationAndMotionAccessController::shouldAllowAccess(Function<void(DeviceOrientationOrMotionPermissionState)>&& callback)
 {
+    auto* page = m_document.page();
     auto* frame = m_document.frame();
-    if (frame && frame->loader().documentLoader())
-        frame->loader().documentLoader()->setDeviceOrientationAndMotionAccessState(granted);
+    if (!page || !frame)
+        return callback(DeviceOrientationOrMotionPermissionState::Denied);
 
-    auto pendingRequests = WTFMove(m_pendingRequests);
-    for (auto& request : pendingRequests)
-        request(granted);
+    bool mayPrompt = UserGestureIndicator::processingUserGesture();
+    if (m_accessState != DeviceOrientationOrMotionPermissionState::Prompt)
+        return callback(m_accessState);
 
-    if (!granted)
-        return;
+    page->chrome().client().shouldAllowDeviceOrientationAndMotionAccess(*m_document.frame(), mayPrompt, [this, weakThis = makeWeakPtr(this), callback = WTFMove(callback)](DeviceOrientationOrMotionPermissionState permissionState) mutable {
+        if (!weakThis)
+            return;
 
-    for (auto* frame = m_document.frame(); frame && frame->window(); frame = frame->tree().traverseNext(m_document.frame())) {
-        frame->window()->startListeningForDeviceOrientationIfNecessary();
-        frame->window()->startListeningForDeviceMotionIfNecessary();
-    }
-}
+        m_accessState = permissionState;
+        callback(permissionState);
 
-Optional<bool> DeviceOrientationAndMotionAccessController::accessState() const
-{
-    auto* frame = m_document.frame();
-    return frame && frame->loader().documentLoader() ? frame->loader().documentLoader()->deviceOrientationAndMotionAccessState() : false;
+        if (permissionState != DeviceOrientationOrMotionPermissionState::Granted)
+            return;
+
+        for (auto* frame = m_document.frame(); frame && frame->window(); frame = frame->tree().traverseNext(m_document.frame())) {
+            frame->window()->startListeningForDeviceOrientationIfNecessary();
+            frame->window()->startListeningForDeviceMotionIfNecessary();
+        }
+    });
 }
 
 } // namespace WebCore
index e599cad..4af9461 100644 (file)
@@ -27,6 +27,7 @@
 
 #if ENABLE(DEVICE_ORIENTATION)
 
+#include "DeviceOrientationOrMotionPermissionState.h"
 #include "ExceptionOr.h"
 #include <wtf/Function.h>
 #include <wtf/Vector.h>
@@ -41,14 +42,13 @@ class DeviceOrientationAndMotionAccessController : public CanMakeWeakPtr<DeviceO
 public:
     explicit DeviceOrientationAndMotionAccessController(Document&);
 
-    Optional<bool> accessState() const;
-    void shouldAllowAccess(Function<void(ExceptionOr<bool> granted)>&&);
 
-private:
-    void setAccessState(bool);
+    DeviceOrientationOrMotionPermissionState accessState() const { return m_accessState; }
+    void shouldAllowAccess(Function<void(DeviceOrientationOrMotionPermissionState)>&&);
 
+private:
     Document& m_document;
-    Vector<Function<void(bool)>> m_pendingRequests;
+    DeviceOrientationOrMotionPermissionState m_accessState { DeviceOrientationOrMotionPermissionState::Prompt };
 };
 
 } // namespace WebCore
index 41cf6fe..69e06e7 100644 (file)
@@ -43,10 +43,10 @@ void DeviceOrientationOrMotionEvent::requestPermission(Document& document, Permi
         return promise.resolve(PermissionState::Denied);
     }
 
-    document.deviceOrientationAndMotionAccessController().shouldAllowAccess([promise = WTFMove(promise)](ExceptionOr<bool> granted) mutable {
-        if (granted.hasException())
-            return promise.reject(granted.releaseException());
-        promise.resolve(granted.returnValue() ? PermissionState::Granted : PermissionState::Denied);
+    document.deviceOrientationAndMotionAccessController().shouldAllowAccess([promise = WTFMove(promise)](PermissionState permissionState) mutable {
+        if (permissionState == PermissionState::Prompt)
+            return promise.reject(Exception { NotAllowedError, "Requesting device orientation or motion access requires a user gesture to prompt"_s });
+        promise.resolve(permissionState);
     });
 }
 #endif
index dd65edb..e568a26 100644 (file)
 
 #pragma once
 
+#include <wtf/EnumTraits.h>
+
 namespace WebCore {
 
-enum class DeviceOrientationOrMotionPermissionState { Granted, Denied };
+enum class DeviceOrientationOrMotionPermissionState : uint8_t { Granted, Denied, Prompt };
+
+}
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::DeviceOrientationOrMotionPermissionState> {
+    using values = EnumValues<
+        WebCore::DeviceOrientationOrMotionPermissionState,
+        WebCore::DeviceOrientationOrMotionPermissionState::Granted,
+        WebCore::DeviceOrientationOrMotionPermissionState::Denied,
+        WebCore::DeviceOrientationOrMotionPermissionState::Prompt
+    >;
+};
 
 }
index c3884aa..b1445e7 100644 (file)
@@ -32,6 +32,7 @@
 #include "CachedRawResourceClient.h"
 #include "CachedResourceHandle.h"
 #include "ContentSecurityPolicyClient.h"
+#include "DeviceOrientationOrMotionPermissionState.h"
 #include "DocumentIdentifier.h"
 #include "DocumentWriter.h"
 #include "FrameDestructionObserver.h"
@@ -280,8 +281,10 @@ public:
     bool userContentExtensionsEnabled() const { return m_userContentExtensionsEnabled; }
     void setUserContentExtensionsEnabled(bool enabled) { m_userContentExtensionsEnabled = enabled; }
 
-    const Optional<bool>& deviceOrientationAndMotionAccessState() const { return m_deviceOrientationAndMotionAccessState; }
-    void setDeviceOrientationAndMotionAccessState(const Optional<bool>& state) { m_deviceOrientationAndMotionAccessState = state; }
+#if ENABLE(DEVICE_ORIENTATION)
+    DeviceOrientationOrMotionPermissionState deviceOrientationAndMotionAccessState() const { return m_deviceOrientationAndMotionAccessState; }
+    void setDeviceOrientationAndMotionAccessState(DeviceOrientationOrMotionPermissionState state) { m_deviceOrientationAndMotionAccessState = state; }
+#endif
 
     AutoplayPolicy autoplayPolicy() const { return m_autoplayPolicy; }
     void setAutoplayPolicy(AutoplayPolicy policy) { m_autoplayPolicy = policy; }
@@ -584,7 +587,9 @@ private:
     String m_customJavaScriptUserAgentAsSiteSpecificQuirks;
     String m_customNavigatorPlatform;
     bool m_userContentExtensionsEnabled { true };
-    Optional<bool> m_deviceOrientationAndMotionAccessState;
+#if ENABLE(DEVICE_ORIENTATION)
+    DeviceOrientationOrMotionPermissionState m_deviceOrientationAndMotionAccessState { DeviceOrientationOrMotionPermissionState::Prompt };
+#endif
     AutoplayPolicy m_autoplayPolicy { AutoplayPolicy::Default };
     OptionSet<AutoplayQuirk> m_allowedAutoplayQuirks;
     PopUpPolicy m_popUpPolicy { PopUpPolicy::Default };
index 0c3cb09..540d78a 100644 (file)
@@ -25,6 +25,7 @@
 #include "AutoplayEvent.h"
 #include "Cursor.h"
 #include "DatabaseDetails.h"
+#include "DeviceOrientationOrMotionPermissionState.h"
 #include "DisabledAdaptations.h"
 #include "DisplayRefreshMonitor.h"
 #include "FocusDirection.h"
@@ -485,7 +486,7 @@ public:
     virtual void requestStorageAccess(String&& /*subFrameHost*/, String&& /*topFrameHost*/, uint64_t /*frameID*/, uint64_t /*pageID*/, WTF::CompletionHandler<void (bool)>&& callback) { callback(false); }
 
 #if ENABLE(DEVICE_ORIENTATION)
-    virtual void shouldAllowDeviceOrientationAndMotionAccess(Frame&, WTF::CompletionHandler<void(bool)>&& callback) { callback(true); }
+    virtual void shouldAllowDeviceOrientationAndMotionAccess(Frame&, bool /* mayPrompt */, WTF::CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& callback) { callback(DeviceOrientationOrMotionPermissionState::Denied); }
 #endif
 
     virtual void didInsertMenuElement(HTMLMenuElement&) { }
index 3599c23..7341ec7 100644 (file)
@@ -1872,13 +1872,15 @@ bool DOMWindow::isAllowedToAddDeviceMotionOrientationListener(String& message) c
 
     if (frame()->settings().deviceOrientationPermissionAPIEnabled()) {
         auto accessState = document()->deviceOrientationAndMotionAccessController().accessState();
-        if (accessState && !*accessState) {
+        switch (accessState) {
+        case DeviceOrientationOrMotionPermissionState::Denied:
             message = "No device motion or orientation events will be fired because permission to use the API was denied."_s;
             return false;
-        }
-        if (!accessState) {
+        case DeviceOrientationOrMotionPermissionState::Prompt:
             message = "No device motion or orientation events will be fired until permission has been requested and granted."_s;
             return false;
+        case DeviceOrientationOrMotionPermissionState::Granted:
+            break;
         }
     }
 
index 750c74e..170a3a1 100644 (file)
@@ -1,3 +1,46 @@
+2019-04-17  Chris Dumez  <cdumez@apple.com>
+
+        Remember device orientation permission for the duration of the browsing session
+        https://bugs.webkit.org/show_bug.cgi?id=196992
+        <rdar://problem/49946067>
+
+        Reviewed by Alex Christensen.
+
+        Implement caching of device orientation permission decisions on the WebDeviceOrientationAndMotionAccessController,
+        which is owned by the WebsiteDataStore. This way, if we already prompted the user of a given origin, we will
+        remember the previous decision for the duration of the session and not prompt again.
+
+        * Shared/WebsitePoliciesData.cpp:
+        (WebKit::WebsitePoliciesData::encode const):
+        (WebKit::WebsitePoliciesData::decode):
+        * Shared/WebsitePoliciesData.h:
+        * UIProcess/API/APIWebsitePolicies.cpp:
+        (API::WebsitePolicies::copy const):
+        (API::WebsitePolicies::data):
+        * UIProcess/API/APIWebsitePolicies.h:
+        * UIProcess/API/Cocoa/WKWebpagePreferences.mm:
+        (toDeviceOrientationOrMotionPermissionState):
+        (-[WKWebpagePreferences _setDeviceOrientationAndMotionAccessPolicy:]):
+        (toWKWebsiteDeviceOrientationAndMotionAccessPolicy):
+        (-[WKWebpagePreferences _deviceOrientationAndMotionAccessPolicy]):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::shouldAllowDeviceOrientationAndMotionAccess):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp: Added.
+        (WebKit::WebDeviceOrientationAndMotionAccessController::shouldAllowDeviceOrientationAndMotionAccess):
+        (WebKit::WebDeviceOrientationAndMotionAccessController::deviceOrientationPermission const):
+        * UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.h: Copied from Source/WebCore/dom/DeviceOrientationAndMotionAccessController.h.
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+        (WebKit::WebsiteDataStore::deviceOrientationAndMotionAccessController):
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::shouldAllowDeviceOrientationAndMotionAccess):
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::shouldAllowDeviceOrientationAndMotionAccess):
+        * WebProcess/WebPage/WebPage.h:
+
 2019-04-16  Andy Estes  <aestes@apple.com>
 
         [iOSMac] Use UIDocumentPickerViewController for picking files
index eaa2981..5a54860 100644 (file)
@@ -38,7 +38,9 @@ void WebsitePoliciesData::encode(IPC::Encoder& encoder) const
 {
     encoder << contentBlockersEnabled;
     encoder << autoplayPolicy;
+#if ENABLE(DEVICE_ORIENTATION)
     encoder << deviceOrientationAndMotionAccessState;
+#endif
     encoder << allowedAutoplayQuirks;
     encoder << customHeaderFields;
     encoder << popUpPolicy;
@@ -63,10 +65,12 @@ Optional<WebsitePoliciesData> WebsitePoliciesData::decode(IPC::Decoder& decoder)
     if (!autoplayPolicy)
         return WTF::nullopt;
 
-    Optional<Optional<bool>> deviceOrientationAndMotionAccessState;
+#if ENABLE(DEVICE_ORIENTATION)
+    Optional<DeviceOrientationOrMotionPermissionState> deviceOrientationAndMotionAccessState;
     decoder >> deviceOrientationAndMotionAccessState;
     if (!deviceOrientationAndMotionAccessState)
         return WTF::nullopt;
+#endif
     
     Optional<OptionSet<WebsiteAutoplayQuirk>> allowedAutoplayQuirks;
     decoder >> allowedAutoplayQuirks;
@@ -122,7 +126,9 @@ Optional<WebsitePoliciesData> WebsitePoliciesData::decode(IPC::Decoder& decoder)
         WTFMove(*contentBlockersEnabled),
         WTFMove(*allowedAutoplayQuirks),
         WTFMove(*autoplayPolicy),
+#if ENABLE(DEVICE_ORIENTATION)
         WTFMove(*deviceOrientationAndMotionAccessState),
+#endif
         WTFMove(*customHeaderFields),
         WTFMove(*popUpPolicy),
         WTFMove(*websiteDataStoreParameters),
@@ -141,8 +147,11 @@ void WebsitePoliciesData::applyToDocumentLoader(WebsitePoliciesData&& websitePol
     documentLoader.setCustomUserAgent(websitePolicies.customUserAgent);
     documentLoader.setCustomJavaScriptUserAgentAsSiteSpecificQuirks(websitePolicies.customJavaScriptUserAgentAsSiteSpecificQuirks);
     documentLoader.setCustomNavigatorPlatform(websitePolicies.customNavigatorPlatform);
+
+#if ENABLE(DEVICE_ORIENTATION)
     documentLoader.setDeviceOrientationAndMotionAccessState(websitePolicies.deviceOrientationAndMotionAccessState);
-    
+#endif
+
     // Only setUserContentExtensionsEnabled if it hasn't already been disabled by reloading without content blockers.
     if (documentLoader.userContentExtensionsEnabled())
         documentLoader.setUserContentExtensionsEnabled(websitePolicies.contentBlockersEnabled);
index 6176706..6a02fca 100644 (file)
@@ -32,6 +32,7 @@
 #include "WebsiteMetaViewportPolicy.h"
 #include "WebsitePopUpPolicy.h"
 #include "WebsiteSimulatedMouseEventsDispatchPolicy.h"
+#include <WebCore/DeviceOrientationOrMotionPermissionState.h>
 #include <WebCore/HTTPHeaderField.h>
 #include <wtf/OptionSet.h>
 
@@ -52,7 +53,9 @@ struct WebsitePoliciesData {
     bool contentBlockersEnabled { true };
     OptionSet<WebsiteAutoplayQuirk> allowedAutoplayQuirks;
     WebsiteAutoplayPolicy autoplayPolicy { WebsiteAutoplayPolicy::Default };
-    Optional<bool> deviceOrientationAndMotionAccessState;
+#if ENABLE(DEVICE_ORIENTATION)
+    WebCore::DeviceOrientationOrMotionPermissionState deviceOrientationAndMotionAccessState;
+#endif
     Vector<WebCore::HTTPHeaderField> customHeaderFields;
     WebsitePopUpPolicy popUpPolicy { WebsitePopUpPolicy::Default };
     Optional<WebsiteDataStoreParameters> websiteDataStoreParameters;
index 3c7281e..48f58e3 100644 (file)
@@ -413,6 +413,7 @@ UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp
 UIProcess/WebStorage/LocalStorageDatabase.cpp
 UIProcess/WebStorage/LocalStorageDatabaseTracker.cpp
 
+UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp
 UIProcess/WebsiteData/WebsiteDataRecord.cpp
 UIProcess/WebsiteData/WebsiteDataStore.cpp
 UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp
index ce41e33..aa95a44 100644 (file)
@@ -48,7 +48,9 @@ Ref<WebsitePolicies> WebsitePolicies::copy() const
     policies->setContentBlockersEnabled(m_contentBlockersEnabled);
     policies->setAllowedAutoplayQuirks(m_allowedAutoplayQuirks);
     policies->setAutoplayPolicy(m_autoplayPolicy);
+#if ENABLE(DEVICE_ORIENTATION)
     policies->setDeviceOrientationAndMotionAccessState(m_deviceOrientationAndMotionAccessState);
+#endif
     policies->setPopUpPolicy(m_popUpPolicy);
     policies->setWebsiteDataStore(m_websiteDataStore.get());
     policies->setCustomUserAgent(m_customUserAgent);
@@ -81,7 +83,9 @@ WebKit::WebsitePoliciesData WebsitePolicies::data()
         contentBlockersEnabled(),
         allowedAutoplayQuirks(),
         autoplayPolicy(),
+#if ENABLE(DEVICE_ORIENTATION)
         deviceOrientationAndMotionAccessState(),
+#endif
         customHeaderFields(),
         popUpPolicy(),
         m_websiteDataStore ? Optional<WebKit::WebsiteDataStoreParameters> { m_websiteDataStore->websiteDataStore().parameters() } : WTF::nullopt,
index 64b0779..f2e11ff 100644 (file)
@@ -33,6 +33,7 @@
 #include "WebsiteMetaViewportPolicy.h"
 #include "WebsitePopUpPolicy.h"
 #include "WebsiteSimulatedMouseEventsDispatchPolicy.h"
+#include <WebCore/DeviceOrientationOrMotionPermissionState.h>
 #include <WebCore/HTTPHeaderField.h>
 #include <wtf/OptionSet.h>
 #include <wtf/Vector.h>
@@ -62,9 +63,11 @@ public:
     WebKit::WebsiteAutoplayPolicy autoplayPolicy() const { return m_autoplayPolicy; }
     void setAutoplayPolicy(WebKit::WebsiteAutoplayPolicy policy) { m_autoplayPolicy = policy; }
 
-    const Optional<bool>& deviceOrientationAndMotionAccessState() const { return m_deviceOrientationAndMotionAccessState; }
-    void setDeviceOrientationAndMotionAccessState(Optional<bool> state) { m_deviceOrientationAndMotionAccessState = state; }
-    
+#if ENABLE(DEVICE_ORIENTATION)
+    WebCore::DeviceOrientationOrMotionPermissionState deviceOrientationAndMotionAccessState() const { return m_deviceOrientationAndMotionAccessState; }
+    void setDeviceOrientationAndMotionAccessState(WebCore::DeviceOrientationOrMotionPermissionState state) { m_deviceOrientationAndMotionAccessState = state; }
+#endif
+
     const Vector<WebCore::HTTPHeaderField>& customHeaderFields() const { return m_customHeaderFields; }
     Vector<WebCore::HTTPHeaderField>&& takeCustomHeaderFields() { return WTFMove(m_customHeaderFields); }
     void setCustomHeaderFields(Vector<WebCore::HTTPHeaderField>&& fields) { m_customHeaderFields = WTFMove(fields); }
@@ -104,7 +107,9 @@ private:
     bool m_contentBlockersEnabled { true };
     OptionSet<WebKit::WebsiteAutoplayQuirk> m_allowedAutoplayQuirks;
     WebKit::WebsiteAutoplayPolicy m_autoplayPolicy { WebKit::WebsiteAutoplayPolicy::Default };
-    Optional<bool> m_deviceOrientationAndMotionAccessState;
+#if ENABLE(DEVICE_ORIENTATION)
+    WebCore::DeviceOrientationOrMotionPermissionState m_deviceOrientationAndMotionAccessState { WebCore::DeviceOrientationOrMotionPermissionState::Prompt };
+#endif
     Vector<WebCore::HTTPHeaderField> m_customHeaderFields;
     WebKit::WebsitePopUpPolicy m_popUpPolicy { WebKit::WebsitePopUpPolicy::Default };
     RefPtr<WebsiteDataStore> m_websiteDataStore;
index 2a02d04..bc9a576 100644 (file)
@@ -36,6 +36,7 @@
 #include "WKRetainPtr.h"
 #include "WKSecurityOriginRef.h"
 #include "WKString.h"
+#include "WebDeviceOrientationAndMotionAccessController.h"
 #include "WebResourceLoadStatisticsStore.h"
 #include "WebsiteData.h"
 #include "WebsiteDataFetchOption.h"
@@ -578,6 +579,13 @@ void WKWebsiteDataStoreSetPerOriginStorageQuota(WKWebsiteDataStoreRef dataStoreR
     WebKit::toImpl(dataStoreRef)->websiteDataStore().setPerOriginStorageQuota(quota);
 }
 
+void WKWebsiteDataStoreClearAllDeviceOrientationPermissions(WKWebsiteDataStoreRef dataStoreRef)
+{
+#if ENABLE(DEVICE_ORIENTATION)
+    WebKit::toImpl(dataStoreRef)->websiteDataStore().deviceOrientationAndMotionAccessController().clearPermissions();
+#endif
+}
+
 void WKWebsiteDataStoreSetWebAuthenticationMockConfiguration(WKWebsiteDataStoreRef dataStoreRef, WKDictionaryRef configurationRef)
 {
 #if ENABLE(WEB_AUTHN)
index be12592..5390a22 100644 (file)
@@ -129,6 +129,8 @@ WK_EXPORT void WKWebsiteDataStoreSetPerOriginStorageQuota(WKWebsiteDataStoreRef
 
 WK_EXPORT void WKWebsiteDataStoreSetWebAuthenticationMockConfiguration(WKWebsiteDataStoreRef dataStoreRef, WKDictionaryRef configuration);
 
+WK_EXPORT void WKWebsiteDataStoreClearAllDeviceOrientationPermissions(WKWebsiteDataStoreRef dataStoreRef);
+
 #ifdef __cplusplus
 }
 #endif
index 617a318..b431d84 100644 (file)
     }
 }
 
-- (void)_setDeviceOrientationAndMotionAccessPolicy:(_WKWebsiteDeviceOrientationAndMotionAccessPolicy)policy
+#if ENABLE(DEVICE_ORIENTATION)
+static WebCore::DeviceOrientationOrMotionPermissionState toDeviceOrientationOrMotionPermissionState(_WKWebsiteDeviceOrientationAndMotionAccessPolicy policy)
 {
     switch (policy) {
     case _WKWebsiteDeviceOrientationAndMotionAccessPolicyAsk:
-        _websitePolicies->setDeviceOrientationAndMotionAccessState(WTF::nullopt);
-        break;
+        return WebCore::DeviceOrientationOrMotionPermissionState::Prompt;
     case _WKWebsiteDeviceOrientationAndMotionAccessPolicyGrant:
-        _websitePolicies->setDeviceOrientationAndMotionAccessState(true);
-        break;
+        return WebCore::DeviceOrientationOrMotionPermissionState::Granted;
     case _WKWebsiteDeviceOrientationAndMotionAccessPolicyDeny:
-        _websitePolicies->setDeviceOrientationAndMotionAccessState(false);
         break;
     }
+    return WebCore::DeviceOrientationOrMotionPermissionState::Denied;
 }
+#endif
 
-- (_WKWebsiteDeviceOrientationAndMotionAccessPolicy)_deviceOrientationAndMotionAccessPolicy
+- (void)_setDeviceOrientationAndMotionAccessPolicy:(_WKWebsiteDeviceOrientationAndMotionAccessPolicy)policy
+{
+#if ENABLE(DEVICE_ORIENTATION)
+    _websitePolicies->setDeviceOrientationAndMotionAccessState(toDeviceOrientationOrMotionPermissionState(policy));
+#endif
+}
+
+#if ENABLE(DEVICE_ORIENTATION)
+static _WKWebsiteDeviceOrientationAndMotionAccessPolicy toWKWebsiteDeviceOrientationAndMotionAccessPolicy(WebCore::DeviceOrientationOrMotionPermissionState state)
 {
-    if (!_websitePolicies->deviceOrientationAndMotionAccessState())
+    switch (state) {
+    case WebCore::DeviceOrientationOrMotionPermissionState::Prompt:
         return _WKWebsiteDeviceOrientationAndMotionAccessPolicyAsk;
-    return *_websitePolicies->deviceOrientationAndMotionAccessState() ? _WKWebsiteDeviceOrientationAndMotionAccessPolicyGrant : _WKWebsiteDeviceOrientationAndMotionAccessPolicyDeny;
+    case WebCore::DeviceOrientationOrMotionPermissionState::Granted:
+        return _WKWebsiteDeviceOrientationAndMotionAccessPolicyGrant;
+    case WebCore::DeviceOrientationOrMotionPermissionState::Denied:
+        break;
+    }
+    return _WKWebsiteDeviceOrientationAndMotionAccessPolicyDeny;
+}
+#endif
+
+- (_WKWebsiteDeviceOrientationAndMotionAccessPolicy)_deviceOrientationAndMotionAccessPolicy
+{
+#if ENABLE(DEVICE_ORIENTATION)
+    return toWKWebsiteDeviceOrientationAndMotionAccessPolicy(_websitePolicies->deviceOrientationAndMotionAccessState());
+#else
+    return _WKWebsiteDeviceOrientationAndMotionAccessPolicyDeny;
+#endif
 }
 
 - (void)_setPopUpPolicy:(_WKWebsitePopUpPolicy)policy
index a9a6a28..915a029 100644 (file)
@@ -7297,12 +7297,12 @@ void WebPageProxy::clearUserMediaState()
 }
 
 #if ENABLE(DEVICE_ORIENTATION)
-void WebPageProxy::requestDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&& originData, CompletionHandler<void(bool)>&& completionHandler)
+void WebPageProxy::shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&& originData, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
 {
     WebFrameProxy* frame = m_process->webFrame(frameID);
     MESSAGE_CHECK(m_process, frame);
 
-    m_uiClient->shouldAllowDeviceOrientationAndMotionAccess(*this, *frame, WTFMove(originData), WTFMove(completionHandler));
+    websiteDataStore().deviceOrientationAndMotionAccessController().shouldAllowAccess(*this, *frame, WTFMove(originData), mayPrompt, WTFMove(completionHandler));
 }
 #endif
 
index 9a06de7..b2480fa 100644 (file)
@@ -1437,7 +1437,7 @@ public:
 #endif
 
 #if ENABLE(DEVICE_ORIENTATION)
-    void requestDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&&, CompletionHandler<void(bool)>&&);
+    void shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&&, bool mayPrompt, CompletionHandler<void(WebCore::DeviceOrientationOrMotionPermissionState)>&&);
 #endif
 
     static WebPageProxy* nonEphemeralWebPageProxy();
index a1a2fea..1d44c6a 100644 (file)
@@ -537,7 +537,7 @@ messages -> WebPageProxy {
     LoadSynchronousURLSchemeTask(struct WebKit::URLSchemeTaskParameters parameters) -> (WebCore::ResourceResponse response, WebCore::ResourceError error, IPC::DataReference data) Synchronous
 
 #if ENABLE(DEVICE_ORIENTATION)
-    RequestDeviceOrientationAndMotionAccess(uint64_t frameID, struct WebCore::SecurityOriginData origin) -> (bool granted) Async
+    ShouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, struct WebCore::SecurityOriginData origin, bool mayPrompt) -> (enum:uint8_t WebCore::DeviceOrientationOrMotionPermissionState permissionState) Async
 #endif
 
 #if ENABLE(ATTACHMENT_ELEMENT)
diff --git a/Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp b/Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp
new file mode 100644 (file)
index 0000000..3ffec93
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER OR
+ * 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.
+ */
+
+#include "config.h"
+#include "WebDeviceOrientationAndMotionAccessController.h"
+
+#if ENABLE(DEVICE_ORIENTATION)
+
+#include "APIUIClient.h"
+#include "WebPageProxy.h"
+
+namespace WebKit {
+
+using namespace WebCore;
+
+void WebDeviceOrientationAndMotionAccessController::shouldAllowAccess(WebPageProxy& page, WebFrameProxy& frame, WebCore::SecurityOriginData&& originData, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
+{
+    auto currentPermission = deviceOrientationPermission(originData);
+    if (currentPermission != DeviceOrientationOrMotionPermissionState::Prompt || !mayPrompt)
+        return completionHandler(currentPermission);
+
+    auto& pendingRequests = m_pendingRequests.ensure(originData, [] {
+        return Vector<CompletionHandler<void(WebCore::DeviceOrientationOrMotionPermissionState)>> { };
+    }).iterator->value;
+    pendingRequests.append(WTFMove(completionHandler));
+    if (pendingRequests.size() > 1)
+        return;
+
+    page.uiClient().shouldAllowDeviceOrientationAndMotionAccess(page, frame, originData, [this, weakThis = makeWeakPtr(this), originData](bool granted) mutable {
+        if (!weakThis)
+            return;
+        m_deviceOrientationPermissionDecisions.set(originData, granted);
+        auto requests = m_pendingRequests.take(originData);
+        for (auto& completionHandler : requests)
+            completionHandler(granted ? DeviceOrientationOrMotionPermissionState::Granted : DeviceOrientationOrMotionPermissionState::Denied);
+    });
+}
+
+DeviceOrientationOrMotionPermissionState WebDeviceOrientationAndMotionAccessController::deviceOrientationPermission(const SecurityOriginData& origin) const
+{
+    auto it = m_deviceOrientationPermissionDecisions.find(origin);
+    if (it == m_deviceOrientationPermissionDecisions.end())
+        return DeviceOrientationOrMotionPermissionState::Prompt;
+    return it->value ? DeviceOrientationOrMotionPermissionState::Granted : DeviceOrientationOrMotionPermissionState::Denied;
+}
+
+void WebDeviceOrientationAndMotionAccessController::clearPermissions()
+{
+    m_deviceOrientationPermissionDecisions.clear();
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(DEVICE_ORIENTATION)
diff --git a/Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.h b/Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.h
new file mode 100644 (file)
index 0000000..fa18531
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 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:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER OR
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(DEVICE_ORIENTATION)
+
+#include <WebCore/DeviceOrientationOrMotionPermissionState.h>
+#include <WebCore/SecurityOriginData.h>
+#include <wtf/HashMap.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebKit {
+
+class WebPageProxy;
+class WebFrameProxy;
+
+class WebDeviceOrientationAndMotionAccessController : public CanMakeWeakPtr<WebDeviceOrientationAndMotionAccessController> {
+public:
+    WebDeviceOrientationAndMotionAccessController() = default;
+
+    void shouldAllowAccess(WebPageProxy&, WebFrameProxy&, WebCore::SecurityOriginData&&, bool mayPrompt, CompletionHandler<void(WebCore::DeviceOrientationOrMotionPermissionState)>&&);
+    void clearPermissions();
+
+private:
+    WebCore::DeviceOrientationOrMotionPermissionState deviceOrientationPermission(const WebCore::SecurityOriginData&) const;
+
+    HashMap<WebCore::SecurityOriginData, bool> m_deviceOrientationPermissionDecisions;
+    HashMap<WebCore::SecurityOriginData, Vector<CompletionHandler<void(WebCore::DeviceOrientationOrMotionPermissionState)>>> m_pendingRequests;
+};
+
+}
+
+#endif
index 1450e76..c28b731 100644 (file)
 #pragma once
 
 #include "NetworkSessionCreationParameters.h"
+#include "WebDeviceOrientationAndMotionAccessController.h"
 #include "WebProcessLifetimeObserver.h"
 #include "WebsiteDataStoreClient.h"
 #include "WebsiteDataStoreConfiguration.h"
 #include <WebCore/Cookie.h>
+#include <WebCore/DeviceOrientationOrMotionPermissionState.h>
 #include <WebCore/SecurityOriginData.h>
 #include <WebCore/SecurityOriginHash.h>
 #include <pal/SessionID.h>
@@ -252,6 +254,10 @@ public:
 
     API::HTTPCookieStore& cookieStore();
 
+#if ENABLE(DEVICE_ORIENTATION)
+    WebDeviceOrientationAndMotionAccessController& deviceOrientationAndMotionAccessController() { return m_deviceOrientationAndMotionAccessController; }
+#endif
+
 #if HAVE(LOAD_OPTIMIZER)
 WEBSITEDATASTORE_LOADOPTIMIZER_ADDITIONS_1
 #endif
@@ -335,6 +341,10 @@ private:
     UniqueRef<AuthenticatorManager> m_authenticatorManager;
 #endif
 
+#if ENABLE(DEVICE_ORIENTATION)
+    WebDeviceOrientationAndMotionAccessController m_deviceOrientationAndMotionAccessController;
+#endif
+
     UniqueRef<WebsiteDataStoreClient> m_client;
 
     RefPtr<API::HTTPCookieStore> m_cookieStore;
index f758723..b248f6b 100644 (file)
                466BC03C1FA266DA002FA9C1 /* WebSWContextManagerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 466BC0391FA266C9002FA9C1 /* WebSWContextManagerConnection.h */; };
                467E43E82243FF7D00B13924 /* WebProcessDataStoreParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 467E43E72243FF6D00B13924 /* WebProcessDataStoreParameters.h */; };
                46A2B6091E5676A600C3DEDA /* BackgroundProcessResponsivenessTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */; };
+               46B0524722668D8500265B97 /* WebDeviceOrientationAndMotionAccessController.h in Headers */ = {isa = PBXBuildFile; fileRef = 46B0524422668D2300265B97 /* WebDeviceOrientationAndMotionAccessController.h */; };
                46DF063C1F3905F8001980BB /* NetworkCORSPreflightChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 46DF063A1F3905E5001980BB /* NetworkCORSPreflightChecker.h */; };
                4A3CC18B19B0640F00D14AEF /* UserMediaPermissionRequestManagerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F3A19AF7B04002EBAB5 /* UserMediaPermissionRequestManagerProxy.h */; };
                4A3CC18D19B0641900D14AEF /* UserMediaPermissionRequestProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F3C19AF7B04002EBAB5 /* UserMediaPermissionRequestProxy.h */; };
                4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProvisionalPageProxy.cpp; sourceTree = "<group>"; };
                46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackgroundProcessResponsivenessTimer.cpp; sourceTree = "<group>"; };
                46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackgroundProcessResponsivenessTimer.h; sourceTree = "<group>"; };
+               46B0524422668D2300265B97 /* WebDeviceOrientationAndMotionAccessController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebDeviceOrientationAndMotionAccessController.h; sourceTree = "<group>"; };
+               46B0524522668D2400265B97 /* WebDeviceOrientationAndMotionAccessController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebDeviceOrientationAndMotionAccessController.cpp; sourceTree = "<group>"; };
                46DF06391F3905E5001980BB /* NetworkCORSPreflightChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCORSPreflightChecker.cpp; sourceTree = "<group>"; };
                46DF063A1F3905E5001980BB /* NetworkCORSPreflightChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCORSPreflightChecker.h; sourceTree = "<group>"; };
                4A410F3519AF7AC3002EBAB5 /* WKUserMediaPermissionRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKUserMediaPermissionRequest.cpp; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                1A4832C01A965A33008B4DFE /* Cocoa */,
+                               46B0524522668D2400265B97 /* WebDeviceOrientationAndMotionAccessController.cpp */,
+                               46B0524422668D2300265B97 /* WebDeviceOrientationAndMotionAccessController.h */,
                                1A4832D81A9D1FD2008B4DFE /* WebsiteDataRecord.cpp */,
                                1A4832CF1A9BD821008B4DFE /* WebsiteDataRecord.h */,
                                1A53C2A41A32569F004E8C70 /* WebsiteDataStore.cpp */,
                                E568B91F20A3AB2F00E3C856 /* WebDataListSuggestionsDropdown.h in Headers */,
                                E5BEF6822130C48000F31111 /* WebDataListSuggestionsDropdownIOS.h in Headers */,
                                E568B92220A3AC6A00E3C856 /* WebDataListSuggestionsDropdownMac.h in Headers */,
+                               46B0524722668D8500265B97 /* WebDeviceOrientationAndMotionAccessController.h in Headers */,
                                CD19A26E1A13E834008D650E /* WebDiagnosticLoggingClient.h in Headers */,
                                1A5B1C5518987EDF004FCF9B /* WebDocumentLoader.h in Headers */,
                                BC032D7B10F4378D0058C15A /* WebDragClient.h in Headers */,
index 8c8b0fc..0766cd6 100644 (file)
@@ -1317,11 +1317,11 @@ void WebChromeClient::requestStorageAccess(String&& subFrameHost, String&& topFr
 #endif
 
 #if ENABLE(DEVICE_ORIENTATION)
-void WebChromeClient::shouldAllowDeviceOrientationAndMotionAccess(Frame& frame, CompletionHandler<void(bool)>&& callback)
+void WebChromeClient::shouldAllowDeviceOrientationAndMotionAccess(Frame& frame, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& callback)
 {
     auto* webFrame = WebFrame::fromCoreFrame(frame);
     ASSERT(webFrame);
-    m_page.shouldAllowDeviceOrientationAndMotionAccess(webFrame->frameID(), SecurityOriginData::fromFrame(&frame), WTFMove(callback));
+    m_page.shouldAllowDeviceOrientationAndMotionAccess(webFrame->frameID(), SecurityOriginData::fromFrame(&frame), mayPrompt, WTFMove(callback));
 }
 #endif
 
index 269aa3e..911f76a 100644 (file)
@@ -367,7 +367,7 @@ private:
 #endif
 
 #if ENABLE(DEVICE_ORIENTATION)
-    void shouldAllowDeviceOrientationAndMotionAccess(WebCore::Frame&, CompletionHandler<void(bool)>&&) final;
+    void shouldAllowDeviceOrientationAndMotionAccess(WebCore::Frame&, bool mayPrompt, CompletionHandler<void(WebCore::DeviceOrientationOrMotionPermissionState)>&&) final;
 #endif
 
     void configureLoggingChannel(const String&, WTFLogChannelState, WTFLogLevel) final;
index e10e8fd..c66ebe6 100644 (file)
@@ -6403,9 +6403,9 @@ void WebPage::requestStorageAccess(String&& subFrameHost, String&& topFrameHost,
 #endif
 
 #if ENABLE(DEVICE_ORIENTATION)
-void WebPage::shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&& origin, CompletionHandler<void(bool)>&& completionHandler)
+void WebPage::shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&& origin, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
 {
-    sendWithAsyncReply(Messages::WebPageProxy::RequestDeviceOrientationAndMotionAccess(frameID, WTFMove(origin)), WTFMove(completionHandler));
+    sendWithAsyncReply(Messages::WebPageProxy::ShouldAllowDeviceOrientationAndMotionAccess(frameID, WTFMove(origin), mayPrompt), WTFMove(completionHandler));
 }
 #endif
     
index a34dadc..3f5bc3a 100644 (file)
@@ -1121,7 +1121,7 @@ public:
 #endif
 
 #if ENABLE(DEVICE_ORIENTATION)
-    void shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&&, CompletionHandler<void(bool)>&&);
+    void shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&&, bool mayPrompt, CompletionHandler<void(WebCore::DeviceOrientationOrMotionPermissionState)>&&);
 #endif
 
     void showShareSheet(WebCore::ShareDataWithParsedURL&, CompletionHandler<void(bool)>&& callback);
index 1963360..9e36bfc 100644 (file)
@@ -1,3 +1,17 @@
+2019-04-17  Chris Dumez  <cdumez@apple.com>
+
+        Remember device orientation permission for the duration of the browsing session
+        https://bugs.webkit.org/show_bug.cgi?id=196992
+        <rdar://problem/49946067>
+
+        Reviewed by Alex Christensen.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/DeviceOrientation.mm:
+        (-[DeviceOrientationPermissionUIDelegate _webView:shouldAllowDeviceOrientationAndMotionAccessRequestedByFrame:decisionHandler:]):
+        (TEST):
+
 2019-04-17  Aakash Jain  <aakash_jain@apple.com>
 
         [ews-app] Clicking 'submit to new ews' doesn't reload status-bubble
index 1bbe74c..59b1f17 100644 (file)
@@ -39,6 +39,7 @@
 
 static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
 static bool didReceiveMessage;
+static bool askedClientForPermission;
 
 @interface DeviceOrientationMessageHandler : NSObject <WKScriptMessageHandler>
 @end
@@ -74,6 +75,7 @@ Function<bool()> _decisionHandler;
 - (void)_webView:(WKWebView *)webView shouldAllowDeviceOrientationAndMotionAccessRequestedByFrame:(WKFrameInfo *)requestingFrame decisionHandler:(void (^)(BOOL))decisionHandler
 {
     decisionHandler(_decisionHandler());
+    askedClientForPermission = true;
 }
 
 @end
@@ -156,4 +158,96 @@ TEST(DeviceOrientation, PermissionDenied)
     runDeviceOrientationTest(DeviceOrientationPermission::Denied);
 }
 
+TEST(DeviceOrientation, RememberPermissionForSession)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    configuration.get().websiteDataStore = [WKWebsiteDataStore defaultDataStore];
+
+    auto messageHandler = adoptNS([[DeviceOrientationMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    RetainPtr<DeviceOrientationPermissionUIDelegate> uiDelegate = adoptNS([[DeviceOrientationPermissionUIDelegate alloc] initWithHandler:[] { return true; }]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [webView loadRequest:request];
+    [webView _test_waitForDidFinishNavigation];
+
+    [webView evaluateJavaScript:@"DeviceOrientationEvent.requestPermission().then((granted) => { webkit.messageHandlers.testHandler.postMessage(granted) });" completionHandler: [&] (id result, NSError *error) { }];
+
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    didReceiveMessage = false;
+
+    EXPECT_TRUE(askedClientForPermission);
+    askedClientForPermission = false;
+    EXPECT_WK_STREQ(@"granted", receivedMessages.get()[0]);
+
+    // Load the same origin again in a new WebView, it should not ask the client.
+    webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    [webView loadRequest:request];
+    [webView _test_waitForDidFinishNavigation];
+
+    [webView _evaluateJavaScriptWithoutUserGesture:@"DeviceOrientationEvent.requestPermission().then((granted) => { webkit.messageHandlers.testHandler.postMessage(granted) }, (error) => { webkit.messageHandlers.testHandler.postMessage('error'); });" completionHandler: [&] (id result, NSError *error) { }];
+
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    didReceiveMessage = false;
+
+    EXPECT_WK_STREQ(@"granted", receivedMessages.get()[1]);
+    EXPECT_FALSE(askedClientForPermission);
+    askedClientForPermission = false;
+
+    // Load the same origin again in a new WebView but this time with a different data store, it should ask the client again.
+    configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    configuration.get().websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"];
+
+    webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    [webView loadRequest:request];
+    [webView _test_waitForDidFinishNavigation];
+
+    [webView evaluateJavaScript:@"DeviceOrientationEvent.requestPermission().then((granted) => { webkit.messageHandlers.testHandler.postMessage(granted) });" completionHandler: [&] (id result, NSError *error) { }];
+
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    didReceiveMessage = false;
+
+    EXPECT_TRUE(askedClientForPermission);
+    askedClientForPermission = false;
+    EXPECT_WK_STREQ(@"granted", receivedMessages.get()[2]);
+
+    // Now go to a different origin, it should ask the client again.
+    NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]];
+    [webView loadRequest:request2];
+    [webView _test_waitForDidFinishNavigation];
+
+    [webView evaluateJavaScript:@"DeviceOrientationEvent.requestPermission().then((granted) => { webkit.messageHandlers.testHandler.postMessage(granted) });" completionHandler: [&] (id result, NSError *error) { }];
+
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    didReceiveMessage = false;
+
+    EXPECT_TRUE(askedClientForPermission);
+    askedClientForPermission = false;
+    EXPECT_WK_STREQ(@"granted", receivedMessages.get()[3]);
+
+    // Go back to the first origin in a new WebView (same data store) and make sure it does not ask the client.
+    webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    [webView loadRequest:request];
+    [webView _test_waitForDidFinishNavigation];
+
+    [webView _evaluateJavaScriptWithoutUserGesture:@"DeviceOrientationEvent.requestPermission().then((granted) => { webkit.messageHandlers.testHandler.postMessage(granted) }, (error) => { webkit.messageHandlers.testHandler.postMessage('error'); });" completionHandler: [&] (id result, NSError *error) { }];
+
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+    didReceiveMessage = false;
+
+    EXPECT_WK_STREQ(@"granted", receivedMessages.get()[4]);
+    EXPECT_FALSE(askedClientForPermission);
+    askedClientForPermission = false;
+}
+
 #endif // PLATFORM(IOS_FAMILY)
index 046a5f7..48bd25b 100644 (file)
@@ -914,6 +914,9 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options, Re
 
     WKContextClearCachedCredentials(TestController::singleton().context());
 
+    auto websiteDataStore = WKContextGetWebsiteDataStore(TestController::singleton().context());
+    WKWebsiteDataStoreClearAllDeviceOrientationPermissions(websiteDataStore);
+
     ClearIndexedDatabases();
     setIDBPerOriginQuota(50 * MB);