Title: [273444] trunk
Revision
273444
Author
cdu...@apple.com
Date
2021-02-24 15:17:35 -0800 (Wed, 24 Feb 2021)

Log Message

Device motion / orientation events not working in third-party iframes despite Feature-Policy allowing it
https://bugs.webkit.org/show_bug.cgi?id=221399
<rdar://problem/74229227>

Reviewed by Youenn Fablet.

Source/WebCore:

Allow third-party iframes to request access to device motion / orientation events if permitted via
Feature-Policy. To match Blink, the following features need to be allowed via Feature-Policy:
- DeviceOrientationEvent: gyroscope, accelerometer and magnetometer
- DeviceMotionEvent: gyroscope and accelerometer

Tests: http/tests/device-orientation/device-motion-allowed-in-first-party-only.html
       http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html
       http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html
       http/tests/device-orientation/device-motion-third-party-iframe-denied.html
       http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html
       http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html
       http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html
       http/tests/device-orientation/device-orientation-third-party-iframe-denied.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
Drop DeviceOrientationOrMotionEvent class as it is no longer needed.

* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::executeScriptInWorld):
Make sure we specify the document when taking a user gesture when asked to run a script.
This is important because some clients want to know that there was a user gesture for
a document within their origin (like device motion & orientation).

* dom/DeviceMotionEvent.cpp:
(WebCore::DeviceMotionEvent::requestPermission):
* dom/DeviceMotionEvent.h:
* dom/DeviceOrientationEvent.cpp:
(WebCore::DeviceOrientationEvent::requestPermission):
* dom/DeviceOrientationEvent.h:
Move requestPermission() from DeviceOrientationOrMotionEvent class to its subclasses now that their
implementations are slightly different.

* dom/DeviceOrientationAndMotionAccessController.cpp:
(WebCore::DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessController):
(WebCore::DeviceOrientationAndMotionAccessController::accessState const):
(WebCore::DeviceOrientationAndMotionAccessController::shouldAllowAccess):
(WebCore::DeviceOrientationAndMotionAccessController::clearPermissions):
* dom/DeviceOrientationAndMotionAccessController.h:
DeviceOrientationAndMotionAccessController is tied to the top document as used to have a single
cached 'permission state' since we used to only support device orientation & motion events in
first-party content. Now that we support those events in third-party content, I replaced the
single 'permission state' data member into a map of 'permission state' per origin. This allows
us to know synchronously (and without IPC to the UIProcess) the known permission state of each
iframe.
Also, I now pass the document to UserGestureIndicator::processingUserGesture() to make sure that
interacting with the top frame does not allow a third-party iframe to request permission to use
the device motion & orientation API. The user needs to interact with that third-party iframe
to allow the iframe to prompt the user.

* dom/DeviceOrientationOrMotionEvent.cpp: Removed.
* dom/DeviceOrientationOrMotionEvent.h: Removed.
Drop DeviceOrientationOrMotionEvent class now that the 2 subclasses need a slightly different
implementation of requestPermission().

* dom/UserGestureIndicator.cpp:
(WebCore::UserGestureToken::isValidForDocument const):
Make parameter const since it can be.

(WebCore::UserGestureIndicator::processingUserGesture):
Check state first in the condition to avoid doing a null-deref when a UserGestureIndicator
gets constructed with no |state| but with a non-null |document|.

* dom/UserGestureIndicator.h:

* html/FeaturePolicy.cpp:
(WebCore::policyTypeName):
(WebCore::FeaturePolicy::parse):
(WebCore::FeaturePolicy::allows const):
* html/FeaturePolicy.h:
Add the following feature policies: accelerometer, gyroscope & magnetometer.
https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md

* page/DOMWindow.cpp:
(WebCore::DOMWindow::page const):
(WebCore::DOMWindow::isAllowedToUseDeviceMotionOrOrientation const):
(WebCore::DOMWindow::isAllowedToUseDeviceMotion const):
(WebCore::DOMWindow::isAllowedToUseDeviceOrientation const):
(WebCore::DOMWindow::hasPermissionToReceiveDeviceMotionOrOrientationEvents const):
(WebCore::DOMWindow::startListeningForDeviceOrientationIfNecessary):
(WebCore::DOMWindow::startListeningForDeviceMotionIfNecessary):
* page/DOMWindow.h:
Differentiate permission support for device motion and device orientation that
they are different. In particular, the two types of events now require a different
subset of feature policies.

LayoutTests:

Add layout test coverage.

* TestExpectations:
* fast/device-orientation/device-motion-request-permission-denied-expected.txt:
* fast/device-orientation/device-motion-request-permission-granted-expected.txt:
* fast/device-orientation/device-motion-request-permission-user-gesture-expected.txt:
* fast/device-orientation/device-orientation-request-permission-denied-expected.txt:
* fast/device-orientation/device-orientation-request-permission-granted-expected.txt:
* fast/device-orientation/device-orientation-request-permission-user-gesture-expected.txt:
* fast/device-orientation/device-orientation-request-permission-user-gesture.html:
* http/tests/device-orientation/device-motion-allowed-in-first-party-only-expected.txt: Added.
* http/tests/device-orientation/device-motion-allowed-in-first-party-only.html: Added.
* http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy-expected.txt: Added.
* http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html: Added.
* http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt: Added.
* http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html: Added.
* http/tests/device-orientation/device-motion-third-party-iframe-denied-expected.txt: Added.
* http/tests/device-orientation/device-motion-third-party-iframe-denied.html: Added.
* http/tests/device-orientation/device-orientation-allowed-in-first-party-only-expected.txt: Added.
* http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html: Added.
* http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy-expected.txt: Added.
* http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html: Added.
* http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt: Added.
* http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html: Added.
* http/tests/device-orientation/device-orientation-third-party-iframe-denied-expected.txt: Added.
* http/tests/device-orientation/device-orientation-third-party-iframe-denied.html: Added.
* http/tests/device-orientation/resources/request-motion-events.html: Added.
* http/tests/device-orientation/resources/request-orientation-events.html: Added.
* platform/ios-wk2/TestExpectations:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (273443 => 273444)


--- trunk/LayoutTests/ChangeLog	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/ChangeLog	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,5 +1,43 @@
 2021-02-24  Chris Dumez  <cdu...@apple.com>
 
+        Device motion / orientation events not working in third-party iframes despite Feature-Policy allowing it
+        https://bugs.webkit.org/show_bug.cgi?id=221399
+        <rdar://problem/74229227>
+
+        Reviewed by Youenn Fablet.
+
+        Add layout test coverage.
+
+        * TestExpectations:
+        * fast/device-orientation/device-motion-request-permission-denied-expected.txt:
+        * fast/device-orientation/device-motion-request-permission-granted-expected.txt:
+        * fast/device-orientation/device-motion-request-permission-user-gesture-expected.txt:
+        * fast/device-orientation/device-orientation-request-permission-denied-expected.txt:
+        * fast/device-orientation/device-orientation-request-permission-granted-expected.txt:
+        * fast/device-orientation/device-orientation-request-permission-user-gesture-expected.txt:
+        * fast/device-orientation/device-orientation-request-permission-user-gesture.html:
+        * http/tests/device-orientation/device-motion-allowed-in-first-party-only-expected.txt: Added.
+        * http/tests/device-orientation/device-motion-allowed-in-first-party-only.html: Added.
+        * http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy-expected.txt: Added.
+        * http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html: Added.
+        * http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt: Added.
+        * http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html: Added.
+        * http/tests/device-orientation/device-motion-third-party-iframe-denied-expected.txt: Added.
+        * http/tests/device-orientation/device-motion-third-party-iframe-denied.html: Added.
+        * http/tests/device-orientation/device-orientation-allowed-in-first-party-only-expected.txt: Added.
+        * http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html: Added.
+        * http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy-expected.txt: Added.
+        * http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html: Added.
+        * http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt: Added.
+        * http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html: Added.
+        * http/tests/device-orientation/device-orientation-third-party-iframe-denied-expected.txt: Added.
+        * http/tests/device-orientation/device-orientation-third-party-iframe-denied.html: Added.
+        * http/tests/device-orientation/resources/request-motion-events.html: Added.
+        * http/tests/device-orientation/resources/request-orientation-events.html: Added.
+        * platform/ios-wk2/TestExpectations:
+
+2021-02-24  Chris Dumez  <cdu...@apple.com>
+
         Regression(r268700) postMessage changes prototype of basic types
         https://bugs.webkit.org/show_bug.cgi?id=222228
         <rdar://problem/74612853>

Modified: trunk/LayoutTests/TestExpectations (273443 => 273444)


--- trunk/LayoutTests/TestExpectations	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/TestExpectations	2021-02-24 23:17:35 UTC (rev 273444)
@@ -50,6 +50,7 @@
 fast/viewport/ios [ Skip ]
 fast/visual-viewport/ios/ [ Skip ]
 fast/device-orientation [ Skip ]
+http/tests/device-orientation [ Skip ]
 fast/events/cursors [ Skip ]
 fast/events/ios [ Skip ]
 fast/events/watchos [ Skip ]

Modified: trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-denied-expected.txt (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-denied-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-denied-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,6 +1,6 @@
-CONSOLE MESSAGE: No device motion or orientation events will be fired until permission has been requested and granted.
+CONSOLE MESSAGE: No device motion events will be fired, reason: Permission to use the API was not yet requested.
 Received device orientation & motion access request for security origin "".
-CONSOLE MESSAGE: No device motion or orientation events will be fired because permission to use the API was denied.
+CONSOLE MESSAGE: No device motion events will be fired, reason: Permission to use the API was denied.
 Basic testing for DeviceMotionEvent.requestPermission().
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".

Modified: trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-granted-expected.txt (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-granted-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-granted-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: No device motion or orientation events will be fired until permission has been requested and granted.
+CONSOLE MESSAGE: No device motion events will be fired, reason: Permission to use the API was not yet requested.
 Received device orientation & motion access request for security origin "".
 Basic testing for DeviceMotionEvent.requestPermission().
 

Modified: trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-user-gesture-expected.txt (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-user-gesture-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-motion-request-permission-user-gesture-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: NotAllowedError: Requesting device orientation or motion access requires a user gesture to prompt
+CONSOLE MESSAGE: NotAllowedError: Requesting device 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".

Modified: trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-denied-expected.txt (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-denied-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-denied-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,6 +1,6 @@
-CONSOLE MESSAGE: No device motion or orientation events will be fired until permission has been requested and granted.
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Permission to use the API was not yet requested.
 Received device orientation & motion access request for security origin "".
-CONSOLE MESSAGE: No device motion or orientation events will be fired because permission to use the API was denied.
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Permission to use the API was denied.
 Basic testing for DeviceOrientationEvent.requestPermission().
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".

Modified: trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-granted-expected.txt (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-granted-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-granted-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: No device motion or orientation events will be fired until permission has been requested and granted.
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Permission to use the API was not yet requested.
 Received device orientation & motion access request for security origin "".
 Basic testing for DeviceOrientationEvent.requestPermission().
 

Modified: trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture-expected.txt (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: NotAllowedError: Requesting device orientation or motion access requires a user gesture to prompt
+CONSOLE MESSAGE: NotAllowedError: Requesting device orientation 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".

Modified: trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture.html (273443 => 273444)


--- trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture.html	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/fast/device-orientation/device-orientation-request-permission-user-gesture.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -9,6 +9,7 @@
 
 DeviceOrientationEvent.requestPermission().then((result) => {
     testFailed("requestPermission promise was not rejected");
+    finishJSTest();
 }, (_e) => {
     e = _e;
     console.log(e);

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-allowed-in-first-party-only-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-allowed-in-first-party-only-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-allowed-in-first-party-only-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,14 @@
+Received device orientation & motion access request for security origin "http://127.0.0.1:8000".
+CONSOLE MESSAGE: No device motion events will be fired, reason: Permission to use the API was not yet requested.
+Received device orientation & motion access request for security origin "http://localhost:8000".
+Tests that giving device motion permission in the main frame does not give access to third-party iframes.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS result is "granted"
+PASS e.data is "denied"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-allowed-in-first-party-only.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-allowed-in-first-party-only.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-allowed-in-first-party-only.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that giving device motion permission in the main frame does not give access to third-party iframes.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "denied");
+    finishJSTest();    
+};
+
+internals.withUserGesture(() => {
+    DeviceMotionEvent.requestPermission().then((_result) => {
+        result = _result;
+        shouldBeEqualToString("result", "granted");
+        // If prompted, deny.
+        if (window.testRunner)
+            testRunner.setShouldAllowDeviceOrientationAndMotionAccess(false);
+
+        // Create third-party iframe that requests permission for itself, but this time should be rejected.
+        let testFrame = document.createElement("iframe");
+        testFrame.src = ""
+        testFrame.allow = "accelerometer;gyroscope";
+        document.body.append(testFrame);
+    });
+});
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: No device motion events will be fired, reason: Permission to use the API was not yet requested.
+Received device orientation & motion access request for security origin "http://localhost:8000".
+Tests that third-party iframes can request access to device motion events if allowed by feature policy.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "granted"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that third-party iframes can request access to device motion events if allowed by feature policy.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "granted");
+    finishJSTest();    
+};
+</script>
+<iframe src="" allow="accelerometer;gyroscope"></iframe>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: No device motion events will be fired, reason: Third-party iframes are not allowed access to device motion unless explicitly allowed via Feature-Policy (gyroscope & accelerometer).
+CONSOLE MESSAGE: Call to requestPermission() failed, reason: Third-party iframes are not allowed access to device motion unless explicitly allowed via Feature-Policy (gyroscope & accelerometer).
+Tests that third-party iframes cannot request access to device motion events with insufficient feature policy.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "denied"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that third-party iframes cannot request access to device motion events with insufficient feature policy.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "denied");
+    finishJSTest();    
+};
+</script>
+<iframe src="" allow="gyroscope"></iframe>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: No device motion events will be fired, reason: Third-party iframes are not allowed access to device motion unless explicitly allowed via Feature-Policy (gyroscope & accelerometer).
+CONSOLE MESSAGE: Call to requestPermission() failed, reason: Third-party iframes are not allowed access to device motion unless explicitly allowed via Feature-Policy (gyroscope & accelerometer).
+Tests that third-party iframes cannot request access to device motion events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "denied"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-motion-third-party-iframe-denied.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that third-party iframes cannot request access to device motion events.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "denied");
+    finishJSTest();    
+};
+</script>
+<iframe src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-allowed-in-first-party-only-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-allowed-in-first-party-only-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-allowed-in-first-party-only-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,14 @@
+Received device orientation & motion access request for security origin "http://127.0.0.1:8000".
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Permission to use the API was not yet requested.
+Received device orientation & motion access request for security origin "http://localhost:8000".
+Tests that giving device orientation permission in the main frame does not give access to third-party iframes.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS result is "granted"
+PASS e.data is "denied"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that giving device orientation permission in the main frame does not give access to third-party iframes.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "denied");
+    finishJSTest();    
+};
+
+internals.withUserGesture(() => {
+    DeviceOrientationEvent.requestPermission().then((_result) => {
+        result = _result;
+        shouldBeEqualToString("result", "granted");
+        // If prompted, deny.
+        if (window.testRunner)
+            testRunner.setShouldAllowDeviceOrientationAndMotionAccess(false);
+
+        // Create third-party iframe that requests permission for itself, but this time should be rejected.
+        let testFrame = document.createElement("iframe");
+        testFrame.src = ""
+        testFrame.allow = "accelerometer;gyroscope;magnetometer";
+        document.body.append(testFrame);
+    });
+});
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-permission-granted-in-other-iframes-from-same-origin-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-permission-granted-in-other-iframes-from-same-origin-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-permission-granted-in-other-iframes-from-same-origin-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Permission to use the API was not yet requested.
+Received device orientation & motion access request for security origin "http://localhost:8000".
+Tests that giving device orientation permission to one third-party iframe gives it to other iframes of the same origin too.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "granted"
+PASS e.data is "granted"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-permission-granted-in-other-iframes-from-same-origin.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-permission-granted-in-other-iframes-from-same-origin.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-permission-granted-in-other-iframes-from-same-origin.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that giving device orientation permission to one third-party iframe gives it to other iframes of the same origin too.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+let firstFrame = true;
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "granted");
+
+    if (!firstFrame) {
+        finishJSTest();
+        return;
+    }
+    firstFrame = false;
+    if (window.testRunner)
+        testRunner.setShouldAllowDeviceOrientationAndMotionAccess(false);
+
+    let secondFrame = document.createElement("iframe");
+    secondFrame.src = ""
+    secondFrame.allow = "accelerometer;gyroscope;magnetometer";
+    document.body.append(secondFrame);
+};
+</script>
+<iframe src="" allow="accelerometer;gyroscope;magnetometer"></iframe>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Permission to use the API was not yet requested.
+Received device orientation & motion access request for security origin "http://localhost:8000".
+Tests that third-party iframes can request access to device orientation events if allowed by feature policy.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "granted"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that third-party iframes can request access to device orientation events if allowed by feature policy.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "granted");
+    finishJSTest();    
+};
+</script>
+<iframe src="" allow="accelerometer;gyroscope;magnetometer"></iframe>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Third-party iframes are not allowed access to device orientation unless explicitly allowed via Feature-Policy (gyroscope & accelerometer & magnetometer).
+CONSOLE MESSAGE: Call to requestPermission() failed, reason: Third-party iframes are not allowed access to device orientation unless explicitly allowed via Feature-Policy (gyroscope & accelerometer & magnetometer).
+Tests that third-party iframes cannot request access to device orientation events with insufficient feature policy.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "denied"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that third-party iframes cannot request access to device orientation events with insufficient feature policy.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "denied");
+    finishJSTest();    
+};
+</script>
+<iframe src="" allow="gyroscope"></iframe>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-expected.txt (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Third-party iframes are not allowed access to device orientation unless explicitly allowed via Feature-Policy (gyroscope & accelerometer & magnetometer).
+CONSOLE MESSAGE: Call to requestPermission() failed, reason: Third-party iframes are not allowed access to device orientation unless explicitly allowed via Feature-Policy (gyroscope & accelerometer & magnetometer).
+Tests that third-party iframes cannot request access to device orientation events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.data is "denied"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/device-orientation-third-party-iframe-denied.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that third-party iframes cannot request access to device orientation events.");
+jsTestIsAsync = true;
+
+// If prompted, allow.
+if (window.testRunner)
+    testRunner.setShouldAllowDeviceOrientationAndMotionAccess(true);
+
+_onmessage_ = (_e) => {
+    e = _e;
+    shouldBeEqualToString("e.data", "denied");
+    finishJSTest();    
+};
+</script>
+<iframe src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/resources/request-motion-events.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/resources/request-motion-events.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/resources/request-motion-events.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+addEventListener("devicemotion", () => {});
+
+internals.withUserGesture(() => {
+    DeviceMotionEvent.requestPermission().then((result) => {
+        top.postMessage(result, "*");
+    });
+});
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/device-orientation/resources/request-orientation-events.html (0 => 273444)


--- trunk/LayoutTests/http/tests/device-orientation/resources/request-orientation-events.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/device-orientation/resources/request-orientation-events.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+addEventListener("deviceorientation", () => {});
+
+internals.withUserGesture(() => {
+    DeviceOrientationEvent.requestPermission().then((result) => {
+        top.postMessage(result, "*");
+    });
+});
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/http/tests/events/device-orientation-motion-non-secure-context.html (273443 => 273444)


--- trunk/LayoutTests/http/tests/events/device-orientation-motion-non-secure-context.html	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/http/tests/events/device-orientation-motion-non-secure-context.html	2021-02-24 23:17:35 UTC (rev 273444)
@@ -27,7 +27,7 @@
     debug("* Registering device motion listener");
     addEventListener("devicemotion", function() { });
     internals.postTask(() => {
-        shouldBeEqualToString("lastConsoleMessage", "Blocked attempt to add a device motion or orientation event listener, reason: Browsing context is not secure.");
+        shouldBeEqualToString("lastConsoleMessage", "No device motion events will be fired, reason: Browsing context is not secure.");
         finishJSTest();
     });
 }
@@ -44,7 +44,7 @@
     debug("* Registering device orientation listener");
     addEventListener("deviceorientation", function() { });
     internals.postTask(() => {
-        shouldBeEqualToString("lastConsoleMessage", "Blocked attempt to add a device motion or orientation event listener, reason: Browsing context is not secure.");
+        shouldBeEqualToString("lastConsoleMessage", "No device orientation events will be fired, reason: Browsing context is not secure.");
         runDeviceMotionTest();
     });
 }

Modified: trunk/LayoutTests/platform/ios/http/tests/events/device-orientation-motion-non-secure-context-expected.txt (273443 => 273444)


--- trunk/LayoutTests/platform/ios/http/tests/events/device-orientation-motion-non-secure-context-expected.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/platform/ios/http/tests/events/device-orientation-motion-non-secure-context-expected.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,5 +1,5 @@
-CONSOLE MESSAGE: Blocked attempt to add a device motion or orientation event listener, reason: Browsing context is not secure.
-CONSOLE MESSAGE: Blocked attempt to add a device motion or orientation event listener, reason: Browsing context is not secure.
+CONSOLE MESSAGE: No device orientation events will be fired, reason: Browsing context is not secure.
+CONSOLE MESSAGE: No device motion events will be fired, reason: Browsing context is not secure.
 Tests that trying to set an event listener for deviceorientation and deviceorientation logs an error in non-secure contexts.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
@@ -6,10 +6,10 @@
 
 
 * Registering device orientation listener
-PASS lastConsoleMessage is "Blocked attempt to add a device motion or orientation event listener, reason: Browsing context is not secure."
+PASS lastConsoleMessage is "No device orientation events will be fired, reason: Browsing context is not secure."
 
 * Registering device motion listener
-PASS lastConsoleMessage is "Blocked attempt to add a device motion or orientation event listener, reason: Browsing context is not secure."
+PASS lastConsoleMessage is "No device motion events will be fired, reason: Browsing context is not secure."
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/platform/ios-wk2/TestExpectations (273443 => 273444)


--- trunk/LayoutTests/platform/ios-wk2/TestExpectations	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/LayoutTests/platform/ios-wk2/TestExpectations	2021-02-24 23:17:35 UTC (rev 273444)
@@ -15,6 +15,7 @@
 contact-picker/contacts-select-while-presenting-picker.html [ Pass ]
 contact-picker/contacts-select.html [ Pass ]
 fast/device-orientation [ Pass ]
+http/tests/device-orientation [ Pass ]
 fast/history/ios [ Pass ]
 fast/scrolling/ios [ Pass ]
 fast/speechrecognition/ios [ Pass ]

Modified: trunk/Source/WebCore/ChangeLog (273443 => 273444)


--- trunk/Source/WebCore/ChangeLog	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/ChangeLog	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,5 +1,99 @@
 2021-02-24  Chris Dumez  <cdu...@apple.com>
 
+        Device motion / orientation events not working in third-party iframes despite Feature-Policy allowing it
+        https://bugs.webkit.org/show_bug.cgi?id=221399
+        <rdar://problem/74229227>
+
+        Reviewed by Youenn Fablet.
+
+        Allow third-party iframes to request access to device motion / orientation events if permitted via
+        Feature-Policy. To match Blink, the following features need to be allowed via Feature-Policy:
+        - DeviceOrientationEvent: gyroscope, accelerometer and magnetometer
+        - DeviceMotionEvent: gyroscope and accelerometer
+
+        Tests: http/tests/device-orientation/device-motion-allowed-in-first-party-only.html
+               http/tests/device-orientation/device-motion-third-party-iframe-allowed-by-feature-policy.html
+               http/tests/device-orientation/device-motion-third-party-iframe-denied-by-insufficient-feature-policy.html
+               http/tests/device-orientation/device-motion-third-party-iframe-denied.html
+               http/tests/device-orientation/device-orientation-allowed-in-first-party-only.html
+               http/tests/device-orientation/device-orientation-third-party-iframe-allowed-by-feature-policy.html
+               http/tests/device-orientation/device-orientation-third-party-iframe-denied-by-insufficient-feature-policy.html
+               http/tests/device-orientation/device-orientation-third-party-iframe-denied.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        Drop DeviceOrientationOrMotionEvent class as it is no longer needed.
+
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::executeScriptInWorld):
+        Make sure we specify the document when taking a user gesture when asked to run a script.
+        This is important because some clients want to know that there was a user gesture for
+        a document within their origin (like device motion & orientation).
+
+        * dom/DeviceMotionEvent.cpp:
+        (WebCore::DeviceMotionEvent::requestPermission):
+        * dom/DeviceMotionEvent.h:
+        * dom/DeviceOrientationEvent.cpp:
+        (WebCore::DeviceOrientationEvent::requestPermission):
+        * dom/DeviceOrientationEvent.h:
+        Move requestPermission() from DeviceOrientationOrMotionEvent class to its subclasses now that their
+        implementations are slightly different.
+
+        * dom/DeviceOrientationAndMotionAccessController.cpp:
+        (WebCore::DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessController):
+        (WebCore::DeviceOrientationAndMotionAccessController::accessState const):
+        (WebCore::DeviceOrientationAndMotionAccessController::shouldAllowAccess):
+        (WebCore::DeviceOrientationAndMotionAccessController::clearPermissions):
+        * dom/DeviceOrientationAndMotionAccessController.h:
+        DeviceOrientationAndMotionAccessController is tied to the top document as used to have a single
+        cached 'permission state' since we used to only support device orientation & motion events in
+        first-party content. Now that we support those events in third-party content, I replaced the
+        single 'permission state' data member into a map of 'permission state' per origin. This allows
+        us to know synchronously (and without IPC to the UIProcess) the known permission state of each
+        iframe.
+        Also, I now pass the document to UserGestureIndicator::processingUserGesture() to make sure that
+        interacting with the top frame does not allow a third-party iframe to request permission to use
+        the device motion & orientation API. The user needs to interact with that third-party iframe
+        to allow the iframe to prompt the user.
+
+        * dom/DeviceOrientationOrMotionEvent.cpp: Removed.
+        * dom/DeviceOrientationOrMotionEvent.h: Removed.
+        Drop DeviceOrientationOrMotionEvent class now that the 2 subclasses need a slightly different
+        implementation of requestPermission().
+
+        * dom/UserGestureIndicator.cpp:
+        (WebCore::UserGestureToken::isValidForDocument const):
+        Make parameter const since it can be.
+
+        (WebCore::UserGestureIndicator::processingUserGesture):
+        Check state first in the condition to avoid doing a null-deref when a UserGestureIndicator
+        gets constructed with no |state| but with a non-null |document|.
+
+        * dom/UserGestureIndicator.h:
+
+        * html/FeaturePolicy.cpp:
+        (WebCore::policyTypeName):
+        (WebCore::FeaturePolicy::parse):
+        (WebCore::FeaturePolicy::allows const):
+        * html/FeaturePolicy.h:
+        Add the following feature policies: accelerometer, gyroscope & magnetometer.
+        https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md
+
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::page const):
+        (WebCore::DOMWindow::isAllowedToUseDeviceMotionOrOrientation const):
+        (WebCore::DOMWindow::isAllowedToUseDeviceMotion const):
+        (WebCore::DOMWindow::isAllowedToUseDeviceOrientation const):
+        (WebCore::DOMWindow::hasPermissionToReceiveDeviceMotionOrOrientationEvents const):
+        (WebCore::DOMWindow::startListeningForDeviceOrientationIfNecessary):
+        (WebCore::DOMWindow::startListeningForDeviceMotionIfNecessary):
+        * page/DOMWindow.h:
+        Differentiate permission support for device motion and device orientation that
+        they are different. In particular, the two types of events now require a different
+        subset of feature policies.
+
+2021-02-24  Chris Dumez  <cdu...@apple.com>
+
         Regression(r269481) Kugou Music: Can not leave "MV" category after selecting it
         https://bugs.webkit.org/show_bug.cgi?id=222380
         <rdar://74602294>

Modified: trunk/Source/WebCore/Sources.txt (273443 => 273444)


--- trunk/Source/WebCore/Sources.txt	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/Sources.txt	2021-02-24 23:17:35 UTC (rev 273444)
@@ -912,7 +912,6 @@
 dom/DeviceOrientationController.cpp
 dom/DeviceOrientationData.cpp
 dom/DeviceOrientationEvent.cpp
-dom/DeviceOrientationOrMotionEvent.cpp
 dom/Document.cpp
 dom/DocumentFragment.cpp
 dom/DocumentMarkerController.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (273443 => 273444)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1252,7 +1252,6 @@
 		45FEA5D0156DDE8C00654101 /* Decimal.h in Headers */ = {isa = PBXBuildFile; fileRef = 45FEA5CE156DDE8C00654101 /* Decimal.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		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 */; 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, ); }; };
@@ -8188,8 +8187,6 @@
 		460CBF331D4BCCFE0092E88E /* JSDOMWindowProperties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMWindowProperties.cpp; sourceTree = "<group>"; };
 		460CBF341D4BCCFE0092E88E /* JSDOMWindowProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMWindowProperties.h; sourceTree = "<group>"; };
 		460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSServiceWorkerGlobalScopeCustom.cpp; sourceTree = "<group>"; };
-		461DA52A222F486F00D05A87 /* DeviceOrientationOrMotionEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceOrientationOrMotionEvent.h; sourceTree = "<group>"; };
-		461DA52C222F486F00D05A87 /* DeviceOrientationOrMotionEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceOrientationOrMotionEvent.cpp; sourceTree = "<group>"; };
 		4634592B1AC2271000ECB71C /* PowerObserverMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PowerObserverMac.cpp; sourceTree = "<group>"; };
 		463521AA2081090B00C28922 /* WindowProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowProxy.h; sourceTree = "<group>"; };
 		463521AC2081090E00C28922 /* WindowProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WindowProxy.cpp; sourceTree = "<group>"; };
@@ -30140,8 +30137,6 @@
 				59A85EA1119D68D900DEF1EF /* DeviceOrientationEvent.cpp */,
 				59A85EA3119D68EC00DEF1EF /* DeviceOrientationEvent.h */,
 				59A85EAA119D7B6E00DEF1EF /* DeviceOrientationEvent.idl */,
-				461DA52C222F486F00D05A87 /* DeviceOrientationOrMotionEvent.cpp */,
-				461DA52A222F486F00D05A87 /* DeviceOrientationOrMotionEvent.h */,
 				465EDD9F222F4EC300B46E16 /* DeviceOrientationOrMotionPermissionState.h */,
 				465EDDA0222F4EC400B46E16 /* DeviceOrientationOrMotionPermissionState.idl */,
 				7C3A8AB82509A10F008C477F /* Document+CSSOMView.idl */,
@@ -31463,7 +31458,6 @@
 				115CFA7A208B8D9D001E6991 /* BlockFormattingState.h in Headers */,
 				BC5EB5E10E81BE8700B25965 /* BorderData.h in Headers */,
 				589556ED18D4A44000764B03 /* BorderEdge.h in Headers */,
-				BCB4779925D46EFF005EF0C8 /* RenderModel.h in Headers */,
 				BC5EB5DB0E81B7EA00B25965 /* BorderValue.h in Headers */,
 				9316DE00240C64F9009340AA /* BoundaryPoint.h in Headers */,
 				6ED8C37A183BFF8C009E53BD /* BoxShape.h in Headers */,
@@ -31977,7 +31971,6 @@
 				59A8F1D611A69513001AC34A /* DeviceOrientationController.h in Headers */,
 				590E1B4911E4EF4B0069F784 /* DeviceOrientationData.h in Headers */,
 				59A85EA4119D68EC00DEF1EF /* DeviceOrientationEvent.h in Headers */,
-				460E3075222F4EFD009A0606 /* DeviceOrientationOrMotionEvent.h in Headers */,
 				460E3077222F4F03009A0606 /* DeviceOrientationOrMotionPermissionState.h in Headers */,
 				E39628BF2395728F00658ECD /* DeviceOrientationUpdateProvider.h in Headers */,
 				572B401F21757A64000AD43E /* DeviceRequestConverter.h in Headers */,
@@ -34446,6 +34439,7 @@
 				E4C279590CF9741900E97B98 /* RenderMedia.h in Headers */,
 				ABDDFE7A0A5C6E7000A3E11D /* RenderMenuList.h in Headers */,
 				A454424F119B3687009BE912 /* RenderMeter.h in Headers */,
+				BCB4779925D46EFF005EF0C8 /* RenderModel.h in Headers */,
 				1A3586E015264C450022A659 /* RenderMultiColumnFlow.h in Headers */,
 				BCE32B9C1517C0B200F542EC /* RenderMultiColumnSet.h in Headers */,
 				BC1A7D9818FCB5B000421879 /* RenderMultiColumnSpannerPlaceholder.h in Headers */,

Modified: trunk/Source/WebCore/bindings/js/ScriptController.cpp (273443 => 273444)


--- trunk/Source/WebCore/bindings/js/ScriptController.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/bindings/js/ScriptController.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -591,7 +591,7 @@
     m_frame.loader().client().notifyPageOfAppBoundBehavior();
 #endif
 
-    UserGestureIndicator gestureIndicator(parameters.forceUserGesture == ForceUserGesture::Yes ? Optional<ProcessingUserGestureState>(ProcessingUserGesture) : WTF::nullopt);
+    UserGestureIndicator gestureIndicator(parameters.forceUserGesture == ForceUserGesture::Yes ? Optional<ProcessingUserGestureState>(ProcessingUserGesture) : WTF::nullopt, m_frame.document());
 
     if (!canExecuteScripts(AboutToExecuteScript) || isPaused())
         return makeUnexpected(ExceptionDetails { "Cannot execute _javascript_ in this document"_s });

Modified: trunk/Source/WebCore/dom/DeviceMotionEvent.cpp (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceMotionEvent.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceMotionEvent.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -27,6 +27,8 @@
 #include "DeviceMotionEvent.h"
 
 #include "DeviceMotionData.h"
+#include "DeviceOrientationAndMotionAccessController.h"
+#include "JSDOMPromiseDeferred.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -125,4 +127,26 @@
 #endif
 }
 
+#if ENABLE(DEVICE_ORIENTATION)
+void DeviceMotionEvent::requestPermission(Document& document, PermissionPromise&& promise)
+{
+    auto* window = document.domWindow();
+    auto* page = document.page();
+    if (!window || !page)
+        return promise.reject(Exception { InvalidStateError, "No browsing context"_s });
+
+    String errorMessage;
+    if (!window->isAllowedToUseDeviceMotion(errorMessage)) {
+        document.addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("Call to requestPermission() failed, reason: ", errorMessage, "."));
+        return promise.resolve(PermissionState::Denied);
+    }
+
+    document.deviceOrientationAndMotionAccessController().shouldAllowAccess(document, [promise = WTFMove(promise)](auto permissionState) mutable {
+        if (permissionState == PermissionState::Prompt)
+            return promise.reject(Exception { NotAllowedError, "Requesting device motion access requires a user gesture to prompt"_s });
+        promise.resolve(permissionState);
+    });
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/DeviceMotionEvent.h (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceMotionEvent.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceMotionEvent.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -25,14 +25,16 @@
 
 #pragma once
 
-#include "DeviceOrientationOrMotionEvent.h"
+#include "DeviceOrientationOrMotionPermissionState.h"
 #include "Event.h"
+#include "IDLTypes.h"
 
 namespace WebCore {
 
 class DeviceMotionData;
+template<typename IDLType> class DOMPromiseDeferred;
 
-class DeviceMotionEvent final : public Event, public DeviceOrientationOrMotionEvent {
+class DeviceMotionEvent final : public Event {
     WTF_MAKE_ISO_ALLOCATED(DeviceMotionEvent);
 public:
     virtual ~DeviceMotionEvent();
@@ -68,6 +70,12 @@
 
     void initDeviceMotionEvent(const AtomString& type, bool bubbles, bool cancelable, Optional<Acceleration>&&, Optional<Acceleration>&&, Optional<RotationRate>&&, Optional<double>);
 
+#if ENABLE(DEVICE_ORIENTATION)
+    using PermissionState = DeviceOrientationOrMotionPermissionState;
+    using PermissionPromise = DOMPromiseDeferred<IDLEnumeration<PermissionState>>;
+    static void requestPermission(Document&, PermissionPromise&&);
+#endif
+
 private:
     DeviceMotionEvent();
     DeviceMotionEvent(const AtomString& eventType, DeviceMotionData*);

Modified: trunk/Source/WebCore/dom/DeviceOrientationAndMotionAccessController.cpp (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceOrientationAndMotionAccessController.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceOrientationAndMotionAccessController.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -39,39 +39,50 @@
 
 namespace WebCore {
 
-DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessController(Document& document)
-    : m_document(document)
+DeviceOrientationAndMotionAccessController::DeviceOrientationAndMotionAccessController(Document& topDocument)
+    : m_topDocument(topDocument)
 {
-    ASSERT(&m_document.topDocument() == &m_document);
+}
 
-    // 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();
+DeviceOrientationOrMotionPermissionState DeviceOrientationAndMotionAccessController::accessState(const Document& document) const
+{
+    auto iterator = m_accessStatePerOrigin.find(document.securityOrigin().data());
+    if (iterator != m_accessStatePerOrigin.end())
+        return iterator->value;
+
+    // Check per-site setting.
+    if (&document == &m_topDocument || document.securityOrigin().isSameOriginAs(m_topDocument.securityOrigin())) {
+        auto* frame = m_topDocument.frame();
+        if (auto* documentLoader = frame ? frame->loader().documentLoader() : nullptr)
+            return documentLoader->deviceOrientationAndMotionAccessState();
+    }
+
+    return DeviceOrientationOrMotionPermissionState::Prompt;
 }
 
-void DeviceOrientationAndMotionAccessController::shouldAllowAccess(Function<void(DeviceOrientationOrMotionPermissionState)>&& callback)
+void DeviceOrientationAndMotionAccessController::shouldAllowAccess(const Document& document, Function<void(DeviceOrientationOrMotionPermissionState)>&& callback)
 {
-    auto* page = m_document.page();
-    auto* frame = m_document.frame();
+    auto* page = document.page();
+    auto* frame = document.frame();
     if (!page || !frame)
         return callback(DeviceOrientationOrMotionPermissionState::Denied);
 
-    bool mayPrompt = UserGestureIndicator::processingUserGesture();
-    if (m_accessState != DeviceOrientationOrMotionPermissionState::Prompt)
-        return callback(m_accessState);
+    auto accessState = this->accessState(document);
+    if (accessState != DeviceOrientationOrMotionPermissionState::Prompt)
+        return callback(accessState);
 
-    page->chrome().client().shouldAllowDeviceOrientationAndMotionAccess(*m_document.frame(), mayPrompt, [this, weakThis = makeWeakPtr(this), callback = WTFMove(callback)](DeviceOrientationOrMotionPermissionState permissionState) mutable {
+    bool mayPrompt = UserGestureIndicator::processingUserGesture(&document);
+    page->chrome().client().shouldAllowDeviceOrientationAndMotionAccess(*document.frame(), mayPrompt, [this, weakThis = makeWeakPtr(this), securityOrigin = makeRef(document.securityOrigin()), callback = WTFMove(callback)](DeviceOrientationOrMotionPermissionState permissionState) mutable {
         if (!weakThis)
             return;
 
-        m_accessState = permissionState;
+        m_accessStatePerOrigin.set(securityOrigin->data(), permissionState);
         callback(permissionState);
 
         if (permissionState != DeviceOrientationOrMotionPermissionState::Granted)
             return;
 
-        for (auto* frame = m_document.frame(); frame && frame->window(); frame = frame->tree().traverseNext(m_document.frame())) {
+        for (auto* frame = m_topDocument.frame(); frame && frame->window(); frame = frame->tree().traverseNext()) {
             frame->window()->startListeningForDeviceOrientationIfNecessary();
             frame->window()->startListeningForDeviceMotionIfNecessary();
         }

Modified: trunk/Source/WebCore/dom/DeviceOrientationAndMotionAccessController.h (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceOrientationAndMotionAccessController.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceOrientationAndMotionAccessController.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -36,19 +36,19 @@
 namespace WebCore {
 
 class Document;
+class Page;
 
 class DeviceOrientationAndMotionAccessController : public CanMakeWeakPtr<DeviceOrientationAndMotionAccessController> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    explicit DeviceOrientationAndMotionAccessController(Document&);
+    explicit DeviceOrientationAndMotionAccessController(Document& topDocument);
 
+    DeviceOrientationOrMotionPermissionState accessState(const Document&) const;
+    void shouldAllowAccess(const Document&, Function<void(DeviceOrientationOrMotionPermissionState)>&&);
 
-    DeviceOrientationOrMotionPermissionState accessState() const { return m_accessState; }
-    void shouldAllowAccess(Function<void(DeviceOrientationOrMotionPermissionState)>&&);
-
 private:
-    Document& m_document;
-    DeviceOrientationOrMotionPermissionState m_accessState { DeviceOrientationOrMotionPermissionState::Prompt };
+    Document& m_topDocument;
+    HashMap<SecurityOriginData, DeviceOrientationOrMotionPermissionState> m_accessStatePerOrigin;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/DeviceOrientationEvent.cpp (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceOrientationEvent.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceOrientationEvent.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -26,7 +26,9 @@
 #include "config.h"
 #include "DeviceOrientationEvent.h"
 
+#include "DeviceOrientationAndMotionAccessController.h"
 #include "DeviceOrientationData.h"
+#include "JSDOMPromiseDeferred.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -112,4 +114,26 @@
 #endif
 }
 
+#if ENABLE(DEVICE_ORIENTATION)
+void DeviceOrientationEvent::requestPermission(Document& document, PermissionPromise&& promise)
+{
+    auto* window = document.domWindow();
+    auto* page = document.page();
+    if (!window || !page)
+        return promise.reject(Exception { InvalidStateError, "No browsing context"_s });
+
+    String errorMessage;
+    if (!window->isAllowedToUseDeviceOrientation(errorMessage)) {
+        document.addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("Call to requestPermission() failed, reason: ", errorMessage, "."));
+        return promise.resolve(PermissionState::Denied);
+    }
+
+    document.deviceOrientationAndMotionAccessController().shouldAllowAccess(document, [promise = WTFMove(promise)](PermissionState permissionState) mutable {
+        if (permissionState == PermissionState::Prompt)
+            return promise.reject(Exception { NotAllowedError, "Requesting device orientation access requires a user gesture to prompt"_s });
+        promise.resolve(permissionState);
+    });
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/DeviceOrientationEvent.h (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceOrientationEvent.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceOrientationEvent.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -25,14 +25,16 @@
 
 #pragma once
 
-#include "DeviceOrientationOrMotionEvent.h"
+#include "DeviceOrientationOrMotionPermissionState.h"
 #include "Event.h"
+#include "IDLTypes.h"
 
 namespace WebCore {
 
 class DeviceOrientationData;
+template<typename IDLType> class DOMPromiseDeferred;
 
-class DeviceOrientationEvent final : public Event, public DeviceOrientationOrMotionEvent {
+class DeviceOrientationEvent final : public Event {
     WTF_MAKE_ISO_ALLOCATED(DeviceOrientationEvent);
 public:
     static Ref<DeviceOrientationEvent> create(const AtomString& eventType, DeviceOrientationData* orientation)
@@ -62,6 +64,12 @@
     void initDeviceOrientationEvent(const AtomString& type, bool bubbles, bool cancelable, Optional<double> alpha, Optional<double> beta, Optional<double> gamma, Optional<bool> absolute);
 #endif
 
+#if ENABLE(DEVICE_ORIENTATION)
+    using PermissionState = DeviceOrientationOrMotionPermissionState;
+    using PermissionPromise = DOMPromiseDeferred<IDLEnumeration<PermissionState>>;
+    static void requestPermission(Document&, PermissionPromise&&);
+#endif
+
 private:
     DeviceOrientationEvent();
     DeviceOrientationEvent(const AtomString& eventType, DeviceOrientationData*);

Deleted: trunk/Source/WebCore/dom/DeviceOrientationOrMotionEvent.cpp (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceOrientationOrMotionEvent.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceOrientationOrMotionEvent.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,57 +0,0 @@
-/*
- * 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 "DeviceOrientationOrMotionEvent.h"
-
-#include "DOMWindow.h"
-#include "DeviceOrientationAndMotionAccessController.h"
-#include "Document.h"
-#include "JSDOMPromiseDeferred.h"
-
-namespace WebCore {
-
-#if ENABLE(DEVICE_ORIENTATION)
-void DeviceOrientationOrMotionEvent::requestPermission(Document& document, PermissionPromise&& promise)
-{
-    auto* window = document.domWindow();
-    if (!window)
-        return promise.reject(Exception { InvalidStateError, "No browsing context"_s });
-
-    String errorMessage;
-    if (!window->isAllowedToUseDeviceMotionOrientation(errorMessage)) {
-        document.addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("Call to requestPermission() failed, reason: ", errorMessage, "."));
-        return promise.resolve(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
-
-} // namespace WebCore

Deleted: trunk/Source/WebCore/dom/DeviceOrientationOrMotionEvent.h (273443 => 273444)


--- trunk/Source/WebCore/dom/DeviceOrientationOrMotionEvent.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/DeviceOrientationOrMotionEvent.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -1,51 +0,0 @@
-/*
- * 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
-
-#include "DeviceOrientationOrMotionPermissionState.h"
-#include "IDLTypes.h"
-
-namespace WebCore {
-
-class Document;
-
-template<typename IDLType> class DOMPromiseDeferred;
-
-class DeviceOrientationOrMotionEvent {
-public:
-
-#if ENABLE(DEVICE_ORIENTATION)
-    using PermissionState = DeviceOrientationOrMotionPermissionState;
-    using PermissionPromise = DOMPromiseDeferred<IDLEnumeration<PermissionState>>;
-    static void requestPermission(Document&, PermissionPromise&&);
-#endif
-
-protected:
-    DeviceOrientationOrMotionEvent() = default;
-    ~DeviceOrientationOrMotionEvent() = default;
-};
-
-} // namespace WebCore

Modified: trunk/Source/WebCore/dom/UserGestureIndicator.cpp (273443 => 273444)


--- trunk/Source/WebCore/dom/UserGestureIndicator.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/UserGestureIndicator.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -89,7 +89,7 @@
     maxIntervalForUserGestureForwardingForFetch = WTFMove(value);
 }
 
-bool UserGestureToken::isValidForDocument(Document& document) const
+bool UserGestureToken::isValidForDocument(const Document& document) const
 {
     return m_documentsImpactedByUserGesture.contains(document);
 }
@@ -102,7 +102,7 @@
     if (state)
         currentToken() = UserGestureToken::create(state.value(), gestureType, document);
 
-    if (document && currentToken()->processingUserGesture() && state) {
+    if (state && document && currentToken()->processingUserGesture()) {
         document->updateLastHandledUserGestureTimestamp(currentToken()->startTime());
         if (processInteractionStyle == ProcessInteractionStyle::Immediate)
             ResourceLoadObserver::shared().logUserInteractionWithReducedTimeResolution(document->topDocument());
@@ -157,7 +157,7 @@
     return currentToken();
 }
 
-bool UserGestureIndicator::processingUserGesture(Document* document)
+bool UserGestureIndicator::processingUserGesture(const Document* document)
 {
     if (!isMainThread())
         return false;

Modified: trunk/Source/WebCore/dom/UserGestureIndicator.h (273443 => 273444)


--- trunk/Source/WebCore/dom/UserGestureIndicator.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/dom/UserGestureIndicator.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -102,7 +102,7 @@
 
     MonotonicTime startTime() const { return m_startTime; }
 
-    bool isValidForDocument(Document&) const;
+    bool isValidForDocument(const Document&) const;
 
 private:
     UserGestureToken(ProcessingUserGestureState, UserGestureType, Document*);
@@ -123,7 +123,7 @@
 public:
     WEBCORE_EXPORT static RefPtr<UserGestureToken> currentUserGesture();
 
-    WEBCORE_EXPORT static bool processingUserGesture(Document* = nullptr);
+    WEBCORE_EXPORT static bool processingUserGesture(const Document* = nullptr);
     WEBCORE_EXPORT static bool processingUserGestureForMedia();
 
     // If a document is provided, its last known user gesture timestamp is updated.

Modified: trunk/Source/WebCore/html/FeaturePolicy.cpp (273443 => 273444)


--- trunk/Source/WebCore/html/FeaturePolicy.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/html/FeaturePolicy.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -52,6 +52,14 @@
         return "SyncXHR";
     case FeaturePolicy::Type::Fullscreen:
         return "Fullscreen";
+#if ENABLE(DEVICE_ORIENTATION)
+    case FeaturePolicy::Type::Gyroscope:
+        return "Gyroscope";
+    case FeaturePolicy::Type::Accelerometer:
+        return "Accelerometer";
+    case FeaturePolicy::Type::Magnetometer:
+        return "Magnetometer";
+#endif
 #if ENABLE(WEBXR)
     case FeaturePolicy::Type::XRSpatialTracking:
         return "XRSpatialTracking";
@@ -161,6 +169,11 @@
     bool isDisplayCaptureInitialized = false;
     bool isSyncXHRInitialized = false;
     bool isFullscreenInitialized = false;
+#if ENABLE(DEVICE_ORIENTATION)
+    bool isGyroscopeInitialized = false;
+    bool isAccelerometerInitialized = false;
+    bool isMagnetometerInitialized = false;
+#endif
 #if ENABLE(WEBXR)
     bool isXRSpatialTrackingInitialized = false;
 #endif
@@ -196,6 +209,23 @@
             updateList(document, policy.m_fullscreenRule, item.substring(11));
             continue;
         }
+#if ENABLE(DEVICE_ORIENTATION)
+        if (item.startsWith("gyroscope")) {
+            isGyroscopeInitialized = true;
+            updateList(document, policy.m_gyroscopeRule, item.substring(10));
+            continue;
+        }
+        if (item.startsWith("accelerometer")) {
+            isAccelerometerInitialized = true;
+            updateList(document, policy.m_accelerometerRule, item.substring(14));
+            continue;
+        }
+        if (item.startsWith("magnetometer")) {
+            isMagnetometerInitialized = true;
+            updateList(document, policy.m_magnetometerRule, item.substring(13));
+            continue;
+        }
+#endif
 #if ENABLE(WEBXR)
         if (item.startsWith("xr-spatial-tracking")) {
             isXRSpatialTrackingInitialized = true;
@@ -214,6 +244,14 @@
         policy.m_speakerSelectionRule.allowedList.add(document.securityOrigin().data());
     if (!isDisplayCaptureInitialized)
         policy.m_displayCaptureRule.allowedList.add(document.securityOrigin().data());
+#if ENABLE(DEVICE_ORIENTATION)
+    if (!isGyroscopeInitialized)
+        policy.m_gyroscopeRule.allowedList.add(document.securityOrigin().data());
+    if (!isAccelerometerInitialized)
+        policy.m_accelerometerRule.allowedList.add(document.securityOrigin().data());
+    if (!isMagnetometerInitialized)
+        policy.m_magnetometerRule.allowedList.add(document.securityOrigin().data());
+#endif
 #if ENABLE(WEBXR)
     if (!isXRSpatialTrackingInitialized)
         policy.m_xrSpatialTrackingRule.allowedList.add(document.securityOrigin().data());
@@ -255,6 +293,14 @@
         return isAllowedByFeaturePolicy(m_syncXHRRule, origin);
     case Type::Fullscreen:
         return isAllowedByFeaturePolicy(m_fullscreenRule, origin);
+#if ENABLE(DEVICE_ORIENTATION)
+    case Type::Gyroscope:
+        return isAllowedByFeaturePolicy(m_gyroscopeRule, origin);
+    case Type::Accelerometer:
+        return isAllowedByFeaturePolicy(m_accelerometerRule, origin);
+    case Type::Magnetometer:
+        return isAllowedByFeaturePolicy(m_magnetometerRule, origin);
+#endif
 #if ENABLE(WEBXR)
     case Type::XRSpatialTracking:
         return isAllowedByFeaturePolicy(m_xrSpatialTrackingRule, origin);

Modified: trunk/Source/WebCore/html/FeaturePolicy.h (273443 => 273444)


--- trunk/Source/WebCore/html/FeaturePolicy.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/html/FeaturePolicy.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -45,6 +45,11 @@
         DisplayCapture,
         SyncXHR,
         Fullscreen,
+#if ENABLE(DEVICE_ORIENTATION)
+        Gyroscope,
+        Accelerometer,
+        Magnetometer,
+#endif
 #if ENABLE(WEBXR)
         XRSpatialTracking,
 #endif
@@ -64,7 +69,14 @@
     AllowRule m_displayCaptureRule;
     AllowRule m_syncXHRRule;
     AllowRule m_fullscreenRule;
+#if ENABLE(DEVICE_ORIENTATION)
+    AllowRule m_gyroscopeRule;
+    AllowRule m_accelerometerRule;
+    AllowRule m_magnetometerRule;
+#endif
+#if ENABLE(WEBXR)
     AllowRule m_xrSpatialTrackingRule;
+#endif
 };
 
 enum class LogFeaturePolicyFailure { No, Yes };

Modified: trunk/Source/WebCore/page/DOMWindow.cpp (273443 => 273444)


--- trunk/Source/WebCore/page/DOMWindow.cpp	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/page/DOMWindow.cpp	2021-02-24 23:17:35 UTC (rev 273444)
@@ -58,6 +58,7 @@
 #include "EventListener.h"
 #include "EventLoop.h"
 #include "EventNames.h"
+#include "FeaturePolicy.h"
 #include "FloatRect.h"
 #include "FocusController.h"
 #include "Frame.h"
@@ -446,7 +447,7 @@
     return document() ? document()->mediaQueryMatcher().matchMedia(media) : nullptr;
 }
 
-Page* DOMWindow::page()
+Page* DOMWindow::page() const
 {
     return frame() ? frame()->page() : nullptr;
 }
@@ -2005,9 +2006,9 @@
 #endif
 }
 
-bool DOMWindow::isAllowedToUseDeviceMotionOrientation(String& message) const
+bool DOMWindow::isAllowedToUseDeviceMotionOrOrientation(String& message) const
 {
-    if (!frame() || !frame()->settings().deviceOrientationEventEnabled()) {
+    if (!frame() || !document() || !frame()->settings().deviceOrientationEventEnabled()) {
         message = "API is disabled"_s;
         return false;
     }
@@ -2017,29 +2018,52 @@
         return false;
     }
 
-    if (!isSameSecurityOriginAsMainFrame()) {
-        message = "Source frame did not have the same security origin as the main page"_s;
+    return true;
+}
+
+bool DOMWindow::isAllowedToUseDeviceMotion(String& message) const
+{
+    if (!isAllowedToUseDeviceMotionOrOrientation(message))
         return false;
+
+    if (!isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::Gyroscope, *document(), LogFeaturePolicyFailure::No)
+        || !isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::Accelerometer, *document(), LogFeaturePolicyFailure::No)) {
+        message = "Third-party iframes are not allowed access to device motion unless explicitly allowed via Feature-Policy (gyroscope & accelerometer)"_s;
+        return false;
     }
+
     return true;
 }
 
-bool DOMWindow::isAllowedToAddDeviceMotionOrientationListener(String& message) const
+bool DOMWindow::isAllowedToUseDeviceOrientation(String& message) const
 {
-    String innerMessage;
-    if (!isAllowedToUseDeviceMotionOrientation(innerMessage)) {
-        message = makeString("Blocked attempt to add a device motion or orientation event listener, reason: ", innerMessage, ".");
+    if (!isAllowedToUseDeviceMotionOrOrientation(message))
         return false;
+
+    if (!isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::Gyroscope, *document(), LogFeaturePolicyFailure::No)
+        || !isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::Accelerometer, *document(), LogFeaturePolicyFailure::No)
+        || !isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::Magnetometer, *document(), LogFeaturePolicyFailure::No)) {
+        message = "Third-party iframes are not allowed access to device orientation unless explicitly allowed via Feature-Policy (gyroscope & accelerometer & magnetometer)"_s;
+        return false;
     }
 
+    return true;
+}
+
+bool DOMWindow::hasPermissionToReceiveDeviceMotionOrOrientationEvents(String& message) const
+{
     if (frame()->settings().deviceOrientationPermissionAPIEnabled()) {
-        auto accessState = document()->deviceOrientationAndMotionAccessController().accessState();
+        if (!page()) {
+            message = "No browsing context"_s;
+            return false;
+        }
+        auto accessState = document()->deviceOrientationAndMotionAccessController().accessState(*document());
         switch (accessState) {
         case DeviceOrientationOrMotionPermissionState::Denied:
-            message = "No device motion or orientation events will be fired because permission to use the API was denied."_s;
+            message = "Permission to use the API was denied"_s;
             return false;
         case DeviceOrientationOrMotionPermissionState::Prompt:
-            message = "No device motion or orientation events will be fired until permission has been requested and granted."_s;
+            message = "Permission to use the API was not yet requested"_s;
             return false;
         case DeviceOrientationOrMotionPermissionState::Granted:
             break;
@@ -2058,10 +2082,10 @@
     if (!deviceController || deviceController->hasDeviceEventListener(*this))
         return;
 
-    String errorMessage;
-    if (!isAllowedToAddDeviceMotionOrientationListener(errorMessage)) {
+    String innerMessage;
+    if (!isAllowedToUseDeviceOrientation(innerMessage) || !hasPermissionToReceiveDeviceMotionOrOrientationEvents(innerMessage)) {
         if (auto* document = this->document())
-            document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, errorMessage);
+            document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("No device orientation events will be fired, reason: ", innerMessage, "."));
         return;
     }
 
@@ -2086,11 +2110,11 @@
     if (!deviceController || deviceController->hasDeviceEventListener(*this))
         return;
 
-    String errorMessage;
-    if (!isAllowedToAddDeviceMotionOrientationListener(errorMessage)) {
+    String innerMessage;
+    if (!isAllowedToUseDeviceMotion(innerMessage) || !hasPermissionToReceiveDeviceMotionOrOrientationEvents(innerMessage)) {
         failedToRegisterDeviceMotionEventListener();
         if (auto* document = this->document())
-            document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, errorMessage);
+            document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("No device motion events will be fired, reason: ", innerMessage, "."));
         return;
     }
 

Modified: trunk/Source/WebCore/page/DOMWindow.h (273443 => 273444)


--- trunk/Source/WebCore/page/DOMWindow.h	2021-02-24 23:03:17 UTC (rev 273443)
+++ trunk/Source/WebCore/page/DOMWindow.h	2021-02-24 23:17:35 UTC (rev 273444)
@@ -366,8 +366,8 @@
     void startListeningForDeviceMotionIfNecessary();
     void stopListeningForDeviceMotionIfNecessary();
 
-    bool isAllowedToUseDeviceMotionOrientation(String& message) const;
-    bool isAllowedToAddDeviceMotionOrientationListener(String& message) const;
+    bool isAllowedToUseDeviceOrientation(String& message) const;
+    bool isAllowedToUseDeviceMotion(String& message) const;
 
     DeviceOrientationController* deviceOrientationController() const;
     DeviceMotionController* deviceMotionController() const;
@@ -410,7 +410,7 @@
     bool isLocalDOMWindow() const final { return true; }
     bool isRemoteDOMWindow() const final { return false; }
 
-    Page* page();
+    Page* page() const;
     bool allowedToChangeWindowGeometry() const;
 
     static ExceptionOr<RefPtr<Frame>> createWindow(const String& urlString, const AtomString& frameName, const WindowFeatures&, DOMWindow& activeWindow, Frame& firstFrame, Frame& openerFrame, const WTF::Function<void(DOMWindow&)>& prepareDialogFunction = nullptr);
@@ -417,6 +417,8 @@
     bool isInsecureScriptAccess(DOMWindow& activeWindow, const String& urlString);
 
 #if ENABLE(DEVICE_ORIENTATION)
+    bool isAllowedToUseDeviceMotionOrOrientation(String& message) const;
+    bool hasPermissionToReceiveDeviceMotionOrOrientationEvents(String& message) const;
     void failedToRegisterDeviceMotionEventListener();
 #endif
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to