Title: [289612] trunk
Revision
289612
Author
[email protected]
Date
2022-02-11 01:49:20 -0800 (Fri, 11 Feb 2022)

Log Message

Add support to query camera and microphone permissions
https://bugs.webkit.org/show_bug.cgi?id=236138

Reviewed by Eric Carlson.

LayoutTests/imported/w3c:

* web-platform-tests/permissions/nfc-permission-expected.txt:
* web-platform-tests/permissions/test-background-fetch-permission-expected.txt:

Source/WebCore:

Update queryPermission to be async as it may require to check to UIProcess.
Covered by API test.

* Modules/permissions/PermissionController.h:
* Modules/permissions/Permissions.cpp:

Source/WebKit:

Add new SPI to query for permission (without requesting anything to user).
Use this to implement camera/microphone permission.
In case of permisssion persistently denied, only expose it if web page already called getUserMedia.
In case of permission not persistently set, compute the permission state according past getUserMedia requests.
Also add geolocation mapping as applications might want to support it and it makes existing WPT tests happy.
Add C API as well so that WTR can control permission querying.

Covered by API test.

* Headers.cmake:
* Shared/API/APIObject.h:
* Shared/API/c/WKBase.h:
* Sources.txt:
* UIProcess/API/APIUIClient.h:
* UIProcess/API/C/WKAPICast.h:
* UIProcess/API/C/WKPage.cpp:
(WKPageSetPageUIClient):
* UIProcess/API/C/WKPageUIClient.h:
* UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h:
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
* UIProcess/Cocoa/UIDelegate.h:
* UIProcess/Cocoa/UIDelegate.mm:
* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
* UIProcess/UserMediaPermissionRequestManagerProxy.h:
* UIProcess/WebPageProxy.cpp:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebCoreSupport/WebPermissionController.cpp:
* WebProcess/WebCoreSupport/WebPermissionController.h:

Tools:

* TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm:
(-[UserMediaCaptureUIDelegate _webView:queryPermission:forOrigin:completionHandler:]):
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit/GetUserMedia.mm:
* TestWebKitAPI/Tests/WebKit/getUserMediaPermission.html: Added.
* TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h:
* TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm:
* WebKitTestRunner/TestController.cpp:
(WTR::queryPermission):
(WTR::TestController::createWebViewWithOptions):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (289611 => 289612)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1,3 +1,13 @@
+2022-02-11  Youenn Fablet  <[email protected]>
+
+        Add support to query camera and microphone permissions
+        https://bugs.webkit.org/show_bug.cgi?id=236138
+
+        Reviewed by Eric Carlson.
+
+        * web-platform-tests/permissions/nfc-permission-expected.txt:
+        * web-platform-tests/permissions/test-background-fetch-permission-expected.txt:
+
 2022-02-11  Diego Pino Garcia  <[email protected]>
 
         [WPE] Several WPT offscreen canvas tests are failing after r287846

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/permissions/nfc-permission-expected.txt (289611 => 289612)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/permissions/nfc-permission-expected.txt	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/permissions/nfc-permission-expected.txt	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1,3 +1,3 @@
 
-PASS Test Web NFC Permission.
+FAIL Test Web NFC Permission. promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/permissions/test-background-fetch-permission-expected.txt (289611 => 289612)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/permissions/test-background-fetch-permission-expected.txt	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/permissions/test-background-fetch-permission-expected.txt	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1,3 +1,3 @@
 
-PASS Test Background Fetch Permission.
+FAIL Test Background Fetch Permission. promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
 

Modified: trunk/Source/WebCore/ChangeLog (289611 => 289612)


--- trunk/Source/WebCore/ChangeLog	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebCore/ChangeLog	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1,3 +1,16 @@
+2022-02-11  Youenn Fablet  <[email protected]>
+
+        Add support to query camera and microphone permissions
+        https://bugs.webkit.org/show_bug.cgi?id=236138
+
+        Reviewed by Eric Carlson.
+
+        Update queryPermission to be async as it may require to check to UIProcess.
+        Covered by API test.
+
+        * Modules/permissions/PermissionController.h:
+        * Modules/permissions/Permissions.cpp:
+
 2022-02-11  Myles C. Maxfield  <[email protected]>
 
         Tab characters and ch units do not obey synthetic bold width adjustments correctly

Modified: trunk/Source/WebCore/Modules/permissions/PermissionController.h (289611 => 289612)


--- trunk/Source/WebCore/Modules/permissions/PermissionController.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebCore/Modules/permissions/PermissionController.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -38,8 +38,7 @@
 class PermissionController : public ThreadSafeRefCounted<PermissionController> {
 public:
     virtual ~PermissionController() = default;
-    virtual PermissionState query(ClientOrigin&&, PermissionDescriptor&&) = 0;
-    virtual void request(ClientOrigin&&, PermissionDescriptor&&, CompletionHandler<void(PermissionState)>&&) = 0;
+    virtual void query(WebCore::ClientOrigin&&, PermissionDescriptor&&, CompletionHandler<void(std::optional<PermissionState>)>&&) = 0;
     virtual void addObserver(PermissionObserver&) = 0;
     virtual void removeObserver(PermissionObserver&) = 0;
 protected:
@@ -51,8 +50,7 @@
     static Ref<DummyPermissionController> create() { return adoptRef(*new DummyPermissionController); }
 private:
     DummyPermissionController() = default;
-    PermissionState query(ClientOrigin&&, PermissionDescriptor&&) final { return PermissionState::Denied; }
-    void request(ClientOrigin&&, PermissionDescriptor&&, CompletionHandler<void(PermissionState)>&& completionHandler) final { completionHandler(PermissionState::Denied); }
+    void query(WebCore::ClientOrigin&&, PermissionDescriptor&&, CompletionHandler<void(std::optional<PermissionState>)>&& callback) final { callback({ }); }
     void addObserver(PermissionObserver&) final { }
     void removeObserver(PermissionObserver&) final { }
 };

Modified: trunk/Source/WebCore/Modules/permissions/Permissions.cpp (289611 => 289612)


--- trunk/Source/WebCore/Modules/permissions/Permissions.cpp	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebCore/Modules/permissions/Permissions.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -111,8 +111,19 @@
 
     auto* origin = context->securityOrigin();
     auto originData = origin ? origin->data() : SecurityOriginData { };
-    auto permissionState = m_controller->query(ClientOrigin { context->topOrigin().data(), originData }, PermissionDescriptor { parameterDescriptor });
-    promise.resolve(PermissionStatus::create(*context, permissionState, parameterDescriptor));
+    m_controller->query(ClientOrigin { context->topOrigin().data(), originData }, PermissionDescriptor { parameterDescriptor }, [this, protectedThis = Ref { *this }, parameterDescriptor, promise = WTFMove(promise)](auto permissionState) mutable {
+        auto context = m_navigator ? m_navigator->scriptExecutionContext() : nullptr;
+        if (!context || !context->globalObject())
+            return;
+
+        context->postTask([parameterDescriptor, promise = WTFMove(promise),  permissionState = WTFMove(permissionState)](auto& context) mutable {
+            if (!permissionState) {
+                promise.reject(Exception { NotSupportedError });
+                return;
+            }
+            promise.resolve(PermissionStatus::create(context, *permissionState, parameterDescriptor));
+        });
+    });
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (289611 => 289612)


--- trunk/Source/WebKit/ChangeLog	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/ChangeLog	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1,3 +1,41 @@
+2022-02-11  Youenn Fablet  <[email protected]>
+
+        Add support to query camera and microphone permissions
+        https://bugs.webkit.org/show_bug.cgi?id=236138
+
+        Reviewed by Eric Carlson.
+
+        Add new SPI to query for permission (without requesting anything to user).
+        Use this to implement camera/microphone permission.
+        In case of permisssion persistently denied, only expose it if web page already called getUserMedia.
+        In case of permission not persistently set, compute the permission state according past getUserMedia requests.
+        Also add geolocation mapping as applications might want to support it and it makes existing WPT tests happy.
+        Add C API as well so that WTR can control permission querying.
+
+        Covered by API test.
+
+        * Headers.cmake:
+        * Shared/API/APIObject.h:
+        * Shared/API/c/WKBase.h:
+        * Sources.txt:
+        * UIProcess/API/APIUIClient.h:
+        * UIProcess/API/C/WKAPICast.h:
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageSetPageUIClient):
+        * UIProcess/API/C/WKPageUIClient.h:
+        * UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h:
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+        * UIProcess/Cocoa/UIDelegate.h:
+        * UIProcess/Cocoa/UIDelegate.mm:
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
+        * UIProcess/WebPageProxy.cpp:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebCoreSupport/WebPermissionController.cpp:
+        * WebProcess/WebCoreSupport/WebPermissionController.h:
+
 2022-02-11  Carlos Garcia Campos  <[email protected]>
 
         [WPE][GTK] BubblewrapLauncher leaks D-Bus proxy sockets

Modified: trunk/Source/WebKit/Headers.cmake (289611 => 289612)


--- trunk/Source/WebKit/Headers.cmake	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/Headers.cmake	2022-02-11 09:49:20 UTC (rev 289612)
@@ -99,6 +99,7 @@
     UIProcess/API/C/WKProcessTerminationReason.h
     UIProcess/API/C/WKProtectionSpace.h
     UIProcess/API/C/WKProtectionSpaceTypes.h
+    UIProcess/API/C/WKQueryPermissionResultCallback.h
     UIProcess/API/C/WKResourceCacheManager.h
     UIProcess/API/C/WKSessionStateRef.h
     UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h

Modified: trunk/Source/WebKit/Shared/API/APIObject.h (289611 => 289612)


--- trunk/Source/WebKit/Shared/API/APIObject.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/Shared/API/APIObject.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -187,6 +187,7 @@
 #endif
 
         MediaKeySystemPermissionCallback,
+        QueryPermissionResultCallback,
 
         // Bundle types
         Bundle,

Modified: trunk/Source/WebKit/Shared/API/c/WKBase.h (289611 => 289612)


--- trunk/Source/WebKit/Shared/API/c/WKBase.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/Shared/API/c/WKBase.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -144,6 +144,7 @@
 typedef const struct OpaqueWKSpeechRecognitionPermissionCallback* WKSpeechRecognitionPermissionCallbackRef;
 typedef const struct OpaqueWKMediaKeySystemPermissionRequest* WKMediaKeySystemPermissionRequestRef;
 typedef const struct OpaqueWKMediaKeySystemPermissionCallback* WKMediaKeySystemPermissionCallbackRef;
+typedef const struct OpaqueWKQueryPermissionResultCallback* WKQueryPermissionResultCallbackRef;
 
 /* WebKit2 Bundle types */
 

Modified: trunk/Source/WebKit/Sources.txt (289611 => 289612)


--- trunk/Source/WebKit/Sources.txt	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/Sources.txt	2022-02-11 09:49:20 UTC (rev 289612)
@@ -529,6 +529,7 @@
 UIProcess/API/C/WKNotificationPermissionRequest.cpp
 UIProcess/API/C/WKOpenPanelParametersRef.cpp
 UIProcess/API/C/WKOpenPanelResultListener.cpp
+UIProcess/API/C/WKQueryPermissionResultCallback.cpp
 UIProcess/API/C/WKPage.cpp
 UIProcess/API/C/WKPageConfigurationRef.cpp
 UIProcess/API/C/WKPageGroup.cpp

Modified: trunk/Source/WebKit/UIProcess/API/APIUIClient.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/API/APIUIClient.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/API/APIUIClient.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -33,6 +33,7 @@
 #include <WebCore/CookieConsentDecisionResult.h>
 #include <WebCore/FloatRect.h>
 #include <WebCore/ModalContainerTypes.h>
+#include <WebCore/PermissionState.h>
 #include <wtf/CompletionHandler.h>
 
 #if PLATFORM(COCOA)
@@ -222,6 +223,8 @@
 
     virtual void decidePolicyForMediaKeySystemPermissionRequest(WebKit::WebPageProxy& page, API::SecurityOrigin& origin, const WTF::String& keySystem, CompletionHandler<void(bool)>&& completionHandler) { page.requestMediaKeySystemPermissionByDefaultAction(origin.securityOrigin(), WTFMove(completionHandler)); }
 
+    virtual void queryPermission(const WTF::String& permissionName, API::SecurityOrigin& origin, CompletionHandler<void(std::optional<WebCore::PermissionState>)>&& completionHandler) { completionHandler({ }); }
+
 #if ENABLE(WEBXR) && PLATFORM(COCOA)
     virtual void requestPermissionOnXRSessionFeatures(WebKit::WebPageProxy&, const WebCore::SecurityOriginData&, PlatformXR::SessionMode, const PlatformXR::Device::FeatureList& granted, const PlatformXR::Device::FeatureList& /* consentRequired */, const PlatformXR::Device::FeatureList& /* consentOptional */, CompletionHandler<void(std::optional<PlatformXR::Device::FeatureList>&&)>&& completionHandler) { completionHandler(granted); }    
     virtual void startXRSession(WebKit::WebPageProxy&, CompletionHandler<void(RetainPtr<id>)>&& completionHandler) { completionHandler(nil); }

Modified: trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -79,6 +79,7 @@
 class GeolocationPermissionRequest;
 class MediaKeySystemPermissionCallback;
 class NotificationPermissionRequest;
+class QueryPermissionResultCallback;
 class SpeechRecognitionPermissionCallback;
 class UserMediaPermissionCheckProxy;
 class UserMediaPermissionRequestProxy;
@@ -136,6 +137,7 @@
 WK_ADD_API_MAPPING(WKIconDatabaseRef, WebIconDatabase)
 WK_ADD_API_MAPPING(WKInspectorRef, WebInspectorUIProxy)
 WK_ADD_API_MAPPING(WKMediaKeySystemPermissionCallbackRef, MediaKeySystemPermissionCallback)
+WK_ADD_API_MAPPING(WKQueryPermissionResultCallbackRef, QueryPermissionResultCallback)
 WK_ADD_API_MAPPING(WKMessageListenerRef, API::MessageListener)
 WK_ADD_API_MAPPING(WKNavigationActionRef, API::NavigationAction)
 WK_ADD_API_MAPPING(WKNavigationDataRef, API::NavigationData)

Modified: trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -65,6 +65,7 @@
 #include "NotificationPermissionRequest.h"
 #include "PageClient.h"
 #include "PrintInfo.h"
+#include "QueryPermissionResultCallback.h"
 #include "SpeechRecognitionPermissionRequest.h"
 #include "WKAPICast.h"
 #include "WKPagePolicyClientInternal.h"
@@ -118,7 +119,7 @@
 };
 
 template<> struct ClientTraits<WKPageUIClientBase> {
-    typedef std::tuple<WKPageUIClientV0, WKPageUIClientV1, WKPageUIClientV2, WKPageUIClientV3, WKPageUIClientV4, WKPageUIClientV5, WKPageUIClientV6, WKPageUIClientV7, WKPageUIClientV8, WKPageUIClientV9, WKPageUIClientV10, WKPageUIClientV11, WKPageUIClientV12, WKPageUIClientV13, WKPageUIClientV14, WKPageUIClientV15, WKPageUIClientV16, WKPageUIClientV17> Versions;
+    typedef std::tuple<WKPageUIClientV0, WKPageUIClientV1, WKPageUIClientV2, WKPageUIClientV3, WKPageUIClientV4, WKPageUIClientV5, WKPageUIClientV6, WKPageUIClientV7, WKPageUIClientV8, WKPageUIClientV9, WKPageUIClientV10, WKPageUIClientV11, WKPageUIClientV12, WKPageUIClientV13, WKPageUIClientV14, WKPageUIClientV15, WKPageUIClientV16, WKPageUIClientV17, WKPageUIClientV18> Versions;
 };
 
 #if ENABLE(CONTEXT_MENUS)
@@ -2190,6 +2191,15 @@
 
             m_client.decidePolicyForMediaKeySystemPermissionRequest(toAPI(&page), toAPI(&origin), toAPI(API::String::create(keySystem).ptr()), toAPI(MediaKeySystemPermissionCallback::create(WTFMove(completionHandler)).ptr()));
         }
+
+        void queryPermission(const WTF::String& permissionName, API::SecurityOrigin& origin, CompletionHandler<void(std::optional<WebCore::PermissionState>)>&& completionHandler) final
+        {
+            if (!m_client.queryPermission) {
+                completionHandler({ });
+                return;
+            }
+            m_client.queryPermission(toAPI(API::String::create(permissionName).ptr()), toAPI(&origin), toAPI(QueryPermissionResultCallback::create(WTFMove(completionHandler)).ptr()));
+        }
     };
 
     toImpl(pageRef)->setUIClient(makeUnique<UIClient>(wkClient));

Modified: trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -140,7 +140,7 @@
 typedef void (*WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback)(WKPageRef page, WKSecurityOriginRef topOrigin, WKSpeechRecognitionPermissionCallbackRef callback);
 
 typedef void (*WKPageDecidePolicyForMediaKeySystemPermissionRequestCallback)(WKPageRef page, WKSecurityOriginRef topOrigin, WKStringRef keySystem, WKMediaKeySystemPermissionCallbackRef callback);
-
+typedef void (*WKQueryPermissionCallback)(WKStringRef permissionName, WKSecurityOriginRef topOrigin, WKQueryPermissionResultCallbackRef callback);
 // Deprecated
 typedef WKPageRef (*WKPageCreateNewPageCallback_deprecatedForUseWithV0)(WKPageRef page, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton mouseButton, const void* clientInfo);
 typedef void      (*WKPageMouseDidMoveOverElementCallback_deprecatedForUseWithV0)(WKPageRef page, WKEventModifiers modifiers, WKTypeRef userData, const void *clientInfo);
@@ -1696,9 +1696,127 @@
 
     // Version 17.
     WKPageRequestWebAuthenticationNoGestureCallback                     requestWebAuthenticationNoGesture;
-
 } WKPageUIClientV17;
 
+typedef struct WKPageUIClientV18 {
+    WKPageUIClientBase                                                  base;
+
+    // Version 0.
+    WKPageCreateNewPageCallback_deprecatedForUseWithV0                  createNewPage_deprecatedForUseWithV0;
+    WKPageUIClientCallback                                              showPage;
+    WKPageUIClientCallback                                              close;
+    WKPageTakeFocusCallback                                             takeFocus;
+    WKPageFocusCallback                                                 focus;
+    WKPageUnfocusCallback                                               unfocus;
+    WKPageRunJavaScriptAlertCallback_deprecatedForUseWithV0             runJavaScriptAlert_deprecatedForUseWithV0;
+    WKPageRunJavaScriptConfirmCallback_deprecatedForUseWithV0           runJavaScriptConfirm_deprecatedForUseWithV0;
+    WKPageRunJavaScriptPromptCallback_deprecatedForUseWithV0            runJavaScriptPrompt_deprecatedForUseWithV0;
+    WKPageSetStatusTextCallback                                         setStatusText;
+    WKPageMouseDidMoveOverElementCallback_deprecatedForUseWithV0        mouseDidMoveOverElement_deprecatedForUseWithV0;
+    WKPageMissingPluginButtonClickedCallback_deprecatedForUseWithV0     missingPluginButtonClicked_deprecatedForUseWithV0;
+    WKPageDidNotHandleKeyEventCallback                                  didNotHandleKeyEvent;
+    WKPageDidNotHandleWheelEventCallback                                didNotHandleWheelEvent;
+    WKPageGetToolbarsAreVisibleCallback                                 toolbarsAreVisible;
+    WKPageSetToolbarsAreVisibleCallback                                 setToolbarsAreVisible;
+    WKPageGetMenuBarIsVisibleCallback                                   menuBarIsVisible;
+    WKPageSetMenuBarIsVisibleCallback                                   setMenuBarIsVisible;
+    WKPageGetStatusBarIsVisibleCallback                                 statusBarIsVisible;
+    WKPageSetStatusBarIsVisibleCallback                                 setStatusBarIsVisible;
+    WKPageGetIsResizableCallback                                        isResizable;
+    WKPageSetIsResizableCallback                                        setIsResizable;
+    WKPageGetWindowFrameCallback                                        getWindowFrame;
+    WKPageSetWindowFrameCallback                                        setWindowFrame;
+    WKPageRunBeforeUnloadConfirmPanelCallback_deprecatedForUseWithV6    runBeforeUnloadConfirmPanel_deprecatedForUseWithV6;
+    WKPageUIClientCallback                                              didDraw;
+    WKPageUIClientCallback                                              pageDidScroll;
+    WKPageExceededDatabaseQuotaCallback                                 exceededDatabaseQuota;
+    WKPageRunOpenPanelCallback                                          runOpenPanel;
+    WKPageDecidePolicyForGeolocationPermissionRequestCallback           decidePolicyForGeolocationPermissionRequest;
+    WKPageHeaderHeightCallback                                          headerHeight;
+    WKPageFooterHeightCallback                                          footerHeight;
+    WKPageDrawHeaderCallback                                            drawHeader;
+    WKPageDrawFooterCallback                                            drawFooter;
+    WKPagePrintFrameCallback                                            printFrame;
+    WKPageUIClientCallback                                              runModal;
+    void*                                                               unused1; // Used to be didCompleteRubberBandForMainFrame
+    WKPageSaveDataToFileInDownloadsFolderCallback                       saveDataToFileInDownloadsFolder;
+    void*                                                               shouldInterruptJavaScript_unavailable;
+
+    // Version 1.
+    WKPageCreateNewPageCallback_deprecatedForUseWithV1                  createNewPage_deprecatedForUseWithV1;
+    WKPageMouseDidMoveOverElementCallback                               mouseDidMoveOverElement;
+    WKPageDecidePolicyForNotificationPermissionRequestCallback          decidePolicyForNotificationPermissionRequest;
+    WKPageUnavailablePluginButtonClickedCallback_deprecatedForUseWithV1 unavailablePluginButtonClicked_deprecatedForUseWithV1;
+
+    // Version 2.
+    WKPageShowColorPickerCallback                                       showColorPicker;
+    WKPageHideColorPickerCallback                                       hideColorPicker;
+    WKPageUnavailablePluginButtonClickedCallback                        unavailablePluginButtonClicked;
+
+    // Version 3.
+    WKPagePinnedStateDidChangeCallback                                  pinnedStateDidChange;
+
+    // Version 4.
+    void*                                                               unused2; // Used to be didBeginTrackingPotentialLongMousePress.
+    void*                                                               unused3; // Used to be didRecognizeLongMousePress.
+    void*                                                               unused4; // Used to be didCancelTrackingPotentialLongMousePress.
+    WKPageIsPlayingAudioDidChangeCallback                               isPlayingAudioDidChange;
+
+    // Version 5.
+    WKPageDecidePolicyForUserMediaPermissionRequestCallback             decidePolicyForUserMediaPermissionRequest;
+    WKPageDidClickAutoFillButtonCallback                                didClickAutoFillButton;
+    WKPageRunJavaScriptAlertCallback_deprecatedForUseWithV5             runJavaScriptAlert_deprecatedForUseWithV5;
+    WKPageRunJavaScriptConfirmCallback_deprecatedForUseWithV5           runJavaScriptConfirm_deprecatedForUseWithV5;
+    WKPageRunJavaScriptPromptCallback_deprecatedForUseWithV5            runJavaScriptPrompt_deprecatedForUseWithV5;
+    void*                                                               unused5; // Used to be mediaSessionMetadataDidChange.
+
+    // Version 6.
+    WKPageCreateNewPageCallback                                         createNewPage;
+    WKPageRunJavaScriptAlertCallback                                    runJavaScriptAlert;
+    WKPageRunJavaScriptConfirmCallback                                  runJavaScriptConfirm;
+    WKPageRunJavaScriptPromptCallback                                   runJavaScriptPrompt;
+    WKCheckUserMediaPermissionCallback                                  checkUserMediaPermissionForOrigin;
+
+    // Version 7.
+    WKPageRunBeforeUnloadConfirmPanelCallback                           runBeforeUnloadConfirmPanel;
+    WKFullscreenMayReturnToInlineCallback                               fullscreenMayReturnToInline;
+
+    // Version 8.
+    WKRequestPointerLockCallback                                        requestPointerLock;
+    WKDidLosePointerLockCallback                                        didLosePointerLock;
+
+    // Version 9.
+    WKHandleAutoplayEventCallback                                       handleAutoplayEvent;
+
+    // Version 10.
+    WKHasVideoInPictureInPictureDidChangeCallback                       hasVideoInPictureInPictureDidChange;
+    WKDidExceedBackgroundResourceLimitWhileInForegroundCallback         didExceedBackgroundResourceLimitWhileInForeground;
+
+    // Version 11.
+    WKPageDidResignInputElementStrongPasswordAppearanceCallback         didResignInputElementStrongPasswordAppearance;
+
+    // Version 12.
+    WKPageRequestStorageAccessConfirmCallback                           requestStorageAccessConfirm;
+
+    // Version 13.
+    WKPageShouldAllowDeviceOrientationAndMotionAccessCallback           shouldAllowDeviceOrientationAndMotionAccess;
+
+    // Version 14.
+    WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+
+    // Version 15.
+    WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
+
+    // Version 16.
+    WKPageDecidePolicyForMediaKeySystemPermissionRequestCallback        decidePolicyForMediaKeySystemPermissionRequest;
+
+    // Version 17.
+    WKPageRequestWebAuthenticationNoGestureCallback                     requestWebAuthenticationNoGesture;
+
+    // Version 18.
+    WKQueryPermissionCallback                                           queryPermission;
+} WKPageUIClientV18;
+
 #ifdef __cplusplus
 }
 #endif

Copied: trunk/Source/WebKit/UIProcess/API/C/WKQueryPermissionResultCallback.cpp (from rev 289611, trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h) (0 => 289612)


--- trunk/Source/WebKit/UIProcess/API/C/WKQueryPermissionResultCallback.cpp	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/C/WKQueryPermissionResultCallback.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WKQueryPermissionResultCallback.h"
+
+#include "QueryPermissionResultCallback.h"
+#include "WKAPICast.h"
+
+using namespace WebKit;
+
+WKTypeID WKQueryPermissionResultCallbackGetTypeID()
+{
+    return toAPI(QueryPermissionResultCallback::APIType);
+}
+
+void WKQueryPermissionResultCallbackCompleteWithDenied(WKQueryPermissionResultCallbackRef callback)
+{
+    return toImpl(callback)->setPermission(WebCore::PermissionState::Denied);
+}
+
+void WKQueryPermissionResultCallbackCompleteWithGranted(WKQueryPermissionResultCallbackRef callback)
+{
+    return toImpl(callback)->setPermission(WebCore::PermissionState::Granted);
+}
+
+void WKQueryPermissionResultCallbackCompleteWithPrompt(WKQueryPermissionResultCallbackRef callback)
+{
+    return toImpl(callback)->setPermission(WebCore::PermissionState::Prompt);
+}

Copied: trunk/Source/WebKit/UIProcess/API/C/WKQueryPermissionResultCallback.h (from rev 289611, trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h) (0 => 289612)


--- trunk/Source/WebKit/UIProcess/API/C/WKQueryPermissionResultCallback.h	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/C/WKQueryPermissionResultCallback.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <WebKit/WKBase.h>
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+WK_EXPORT WKTypeID WKQueryPermissionResultCallbackGetTypeID(void);
+
+WK_EXPORT void WKQueryPermissionResultCallbackCompleteWithDenied(WKQueryPermissionResultCallbackRef callback);
+WK_EXPORT void WKQueryPermissionResultCallbackCompleteWithGranted(WKQueryPermissionResultCallbackRef callback);
+WK_EXPORT void WKQueryPermissionResultCallbackCompleteWithPrompt(WKQueryPermissionResultCallbackRef callback);
+
+#ifdef __cplusplus
+}
+#endif

Modified: trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -27,7 +27,7 @@
 
 #include <WebKit/WKBase.h>
 
-#ifdef __cplusplus
+#ifdef __cplusplus 
 extern "C" {
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -161,7 +161,7 @@
 - (void)_webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures completionHandler:(void (^)(WKWebView *webView))completionHandler WK_API_AVAILABLE(macos(10.13), ios(11.0));
 - (void)_webView:(WKWebView *)webView requestGeolocationPermissionForFrame:(WKFrameInfo *)frame decisionHandler:(void (^)(BOOL allowed))decisionHandler WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
 - (void)_webView:(WKWebView *)webView requestGeolocationPermissionForOrigin:(WKSecurityOrigin*)origin initiatedByFrame:(WKFrameInfo *)frame decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
-
+- (void)_webView:(WKWebView *)webView queryPermission:(NSString*)name forOrigin:(WKSecurityOrigin*)origin completionHandler:(void (^)(WKPermissionDecision permissionState))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_webView:(WKWebView *)webView runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler WK_API_AVAILABLE(macos(10.13), ios(11.0));
 - (void)_webView:(WKWebView *)webView editorStateDidChange:(NSDictionary *)editorState WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
 

Modified: trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -173,6 +173,7 @@
         void requestWebAuthenticationNoGesture(API::SecurityOrigin&, CompletionHandler<void(bool)>&&) final;
 #endif
         void decidePolicyForSpeechRecognitionPermissionRequest(WebPageProxy&, API::SecurityOrigin&, CompletionHandler<void(bool)>&&) final;
+        void queryPermission(const String&, API::SecurityOrigin&, CompletionHandler<void(std::optional<WebCore::PermissionState>)>&&) final;
         void didEnableInspectorBrowserDomain(WebPageProxy&) final;
         void didDisableInspectorBrowserDomain(WebPageProxy&) final;
 

Modified: trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1742,6 +1742,43 @@
     }).get()];
 }
 
+void UIDelegate::UIClient::queryPermission(const String& permissionName, API::SecurityOrigin& origin, CompletionHandler<void(std::optional<WebCore::PermissionState>)>&& callback)
+{
+    if (!m_uiDelegate) {
+        callback(WebCore::PermissionState::Prompt);
+        return;
+    }
+
+    auto delegate = (id <WKUIDelegatePrivate>)m_uiDelegate->m_delegate.get();
+    if (!delegate) {
+        callback(WebCore::PermissionState::Prompt);
+        return;
+    }
+
+    if (![delegate respondsToSelector:@selector(_webView:queryPermission:forOrigin:completionHandler:)]) {
+        callback(WebCore::PermissionState::Prompt);
+        return;
+    }
+
+    auto checker = CompletionHandlerCallChecker::create(delegate, @selector(_webView:queryPermission:forOrigin:completionHandler:));
+    [delegate _webView:m_uiDelegate->m_webView.get().get() queryPermission:permissionName forOrigin:wrapper(origin) completionHandler:makeBlockPtr([callback = WTFMove(callback), checker = WTFMove(checker)](WKPermissionDecision permissionState) mutable {
+        if (checker->completionHandlerHasBeenCalled())
+            return;
+        checker->didCallCompletionHandler();
+        switch (permissionState) {
+        case WKPermissionDecisionPrompt:
+            callback(WebCore::PermissionState::Prompt);
+            break;
+        case WKPermissionDecisionGrant:
+            callback(WebCore::PermissionState::Granted);
+            break;
+        case WKPermissionDecisionDeny:
+            callback(WebCore::PermissionState::Denied);
+            break;
+        }
+    }).get()];
+}
+
 void UIDelegate::UIClient::didEnableInspectorBrowserDomain(WebPageProxy&)
 {
     if (!m_uiDelegate)

Copied: trunk/Source/WebKit/UIProcess/QueryPermissionResultCallback.h (from rev 289611, trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h) (0 => 289612)


--- trunk/Source/WebKit/UIProcess/QueryPermissionResultCallback.h	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/QueryPermissionResultCallback.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "APIObject.h"
+#include <WebCore/PermissionState.h>
+#include <wtf/CompletionHandler.h>
+
+namespace WebKit {
+
+class QueryPermissionResultCallback : public API::ObjectImpl<API::Object::Type::QueryPermissionResultCallback> {
+public:
+    static Ref<QueryPermissionResultCallback> create(CompletionHandler<void(std::optional<WebCore::PermissionState>)>&& completionHandler)
+    {
+        return adoptRef(*new QueryPermissionResultCallback(WTFMove(completionHandler)));
+    }
+    ~QueryPermissionResultCallback()
+    {
+        if (m_completionHandler)
+            m_completionHandler({ });
+    }
+    void setPermission(WebCore::PermissionState permission) { m_completionHandler(permission); }
+
+private:
+    explicit QueryPermissionResultCallback(CompletionHandler<void(std::optional<WebCore::PermissionState>)>&& completionHandler)
+        : m_completionHandler(WTFMove(completionHandler))
+    { }
+
+    CompletionHandler<void(std::optional<WebCore::PermissionState>)> m_completionHandler;
+};
+
+} // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -24,6 +24,7 @@
 #include "APIUIClient.h"
 #include "DeviceIdHashSaltStorage.h"
 #include "Logging.h"
+#include "MediaPermissionUtilities.h"
 #include "UserMediaPermissionRequestManager.h"
 #include "UserMediaProcessManager.h"
 #include "WebAutomationSession.h"
@@ -339,7 +340,7 @@
             continue;
         if (!grantedRequest->topLevelDocumentSecurityOrigin().isSameSchemeHostPort(topLevelDocumentOrigin))
             continue;
-        if (grantedRequest->frameID() != frameID)
+        if (frameID && grantedRequest->frameID() != frameID)
             continue;
 
         if (grantedRequest->requiresVideoCapture())
@@ -671,7 +672,36 @@
     m_page.uiClient().decidePolicyForUserMediaPermissionRequest(m_page, *frame, WTFMove(apiRequestingOrigin), WTFMove(apiTopOrigin), request.get());
 }
 
+bool UserMediaPermissionRequestManagerProxy::shouldChangeDeniedToPromptForCamera(const ClientOrigin& origin) const
+{
+    if (!SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort(origin.topOrigin.securityOrigin().get()))
+        return true;
 
+    return !anyOf(m_deniedRequests, [](auto& request) { return request.isVideoDenied; })
+        && !anyOf(m_pregrantedRequests, [](auto& request) { return request->requiresVideoCapture(); })
+        && !anyOf(m_grantedRequests, [](auto& request) { return request->requiresVideoCapture(); });
+}
+
+bool UserMediaPermissionRequestManagerProxy::shouldChangeDeniedToPromptForMicrophone(const ClientOrigin& origin) const
+{
+    if (!SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort(origin.topOrigin.securityOrigin().get()))
+        return true;
+
+    return !anyOf(m_deniedRequests, [](auto& request) { return request.isAudioDenied; })
+        && !anyOf(m_pregrantedRequests, [](auto& request) { return request->requiresAudioCapture(); })
+        && !anyOf(m_grantedRequests, [](auto& request) { return request->requiresAudioCapture(); });
+}
+
+bool UserMediaPermissionRequestManagerProxy::shouldChangePromptToGrantForCamera(const ClientOrigin& origin) const
+{
+    return searchForGrantedRequest({ }, origin.clientOrigin.securityOrigin().get(), origin.topOrigin.securityOrigin().get(), false, true);
+}
+
+bool UserMediaPermissionRequestManagerProxy::shouldChangePromptToGrantForMicrophone(const ClientOrigin& origin) const
+{
+    return searchForGrantedRequest({ }, origin.clientOrigin.securityOrigin().get(), origin.topOrigin.securityOrigin().get(), true, false);
+}
+
 #if !PLATFORM(COCOA)
 void UserMediaPermissionRequestManagerProxy::requestSystemValidation(const WebPageProxy&, UserMediaPermissionRequestProxy&, CompletionHandler<void(bool)>&& callback)
 {

Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -22,6 +22,8 @@
 #include "UserMediaPermissionCheckProxy.h"
 #include "UserMediaPermissionRequestProxy.h"
 #include <WebCore/MediaProducer.h>
+#include <WebCore/PermissionDescriptor.h>
+#include <WebCore/PermissionState.h>
 #include <WebCore/RealtimeMediaSourceCenter.h>
 #include <WebCore/RealtimeMediaSourceFactory.h>
 #include <WebCore/SecurityOrigin.h>
@@ -35,6 +37,7 @@
 
 namespace WebCore {
 class CaptureDevice;
+struct ClientOrigin;
 struct MediaConstraints;
 struct MediaStreamRequest;
 class SecurityOrigin;
@@ -111,6 +114,13 @@
         bool isScreenCaptureDenied;
     };
 
+    std::optional<WebCore::PermissionState> filterPermissionQuery(const WebCore::ClientOrigin&, const WebCore::PermissionDescriptor&, WebCore::PermissionState);
+
+    bool shouldChangeDeniedToPromptForCamera(const WebCore::ClientOrigin&) const;
+    bool shouldChangeDeniedToPromptForMicrophone(const WebCore::ClientOrigin&) const;
+    bool shouldChangePromptToGrantForCamera(const WebCore::ClientOrigin&) const;
+    bool shouldChangePromptToGrantForMicrophone(const WebCore::ClientOrigin&) const;
+
 private:
 #if !RELEASE_LOG_DISABLED
     const Logger& logger() const final;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -8640,10 +8640,46 @@
     m_geolocationPermissionRequestManager.revokeAuthorizationToken(authorizationToken);
 }
 
-void WebPageProxy::requestPermission(const ClientOrigin&, const PermissionDescriptor&, CompletionHandler<void(PermissionState)>&& completionHandler)
+void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const PermissionDescriptor& descriptor, CompletionHandler<void(std::optional<PermissionState>, bool shouldCache)>&& completionHandler)
 {
-    // FIXME: Show a prompt for user input.
-    completionHandler(PermissionState::Granted);
+    bool shouldChangeDeniedToPrompt = true;
+    bool shouldChangePromptToGrant = false;
+    String name;
+    if (descriptor.name == PermissionName::Camera) {
+#if ENABLE(MEDIA_STREAM)
+        name = "camera"_s;
+        shouldChangeDeniedToPrompt = userMediaPermissionRequestManager().shouldChangeDeniedToPromptForCamera(clientOrigin);
+        shouldChangePromptToGrant = userMediaPermissionRequestManager().shouldChangePromptToGrantForCamera(clientOrigin);
+#endif
+    } else if (descriptor.name == PermissionName::Microphone) {
+#if ENABLE(MEDIA_STREAM)
+        name = "microphone"_s;
+        shouldChangeDeniedToPrompt = userMediaPermissionRequestManager().shouldChangeDeniedToPromptForMicrophone(clientOrigin);
+        shouldChangePromptToGrant = userMediaPermissionRequestManager().shouldChangePromptToGrantForMicrophone(clientOrigin);
+#endif
+    } else if (descriptor.name == PermissionName::Geolocation) {
+#if ENABLE(GEOLOCATION)
+        name = "geolocation"_s;
+#endif
+    }
+
+    if (name.isNull()) {
+        completionHandler({ }, false);
+        return;
+    }
+
+    auto origin = API::SecurityOrigin::create(clientOrigin.topOrigin);
+    m_uiClient->queryPermission(name, origin, [clientOrigin, shouldChangeDeniedToPrompt, shouldChangePromptToGrant, completionHandler = WTFMove(completionHandler)](auto result) mutable {
+        if (!result) {
+            completionHandler({ }, false);
+            return;
+        }
+        if (*result == PermissionState::Denied && shouldChangeDeniedToPrompt)
+            result = PermissionState::Prompt;
+        else if (*result == PermissionState::Prompt && shouldChangePromptToGrant)
+            result = PermissionState::Granted;
+        completionHandler(*result, false);
+    });
 }
 
 #if ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -2206,7 +2206,7 @@
 
     void requestGeolocationPermissionForFrame(GeolocationIdentifier, FrameInfoData&&);
     void revokeGeolocationAuthorizationToken(const String& authorizationToken);
-    void requestPermission(const WebCore::ClientOrigin&, const WebCore::PermissionDescriptor&, CompletionHandler<void(WebCore::PermissionState)>&&);
+    void queryPermission(const WebCore::ClientOrigin&, const WebCore::PermissionDescriptor&, CompletionHandler<void(std::optional<WebCore::PermissionState>, bool shouldCache)>&&);
 
 #if PLATFORM(GTK) || PLATFORM(WPE)
     void sendMessageToWebView(UserMessage&&);

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in (289611 => 289612)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2022-02-11 09:49:20 UTC (rev 289612)
@@ -609,7 +609,7 @@
     ModelElementSetIsMuted(struct WebKit::ModelIdentifier modelIdentifier, bool isMuted) -> (bool success) Async
 #endif
 
-    requestPermission(struct WebCore::ClientOrigin origin, struct WebCore::PermissionDescriptor descriptor) -> (enum:uint8_t WebCore::PermissionState state) Async
+    QueryPermission(struct WebCore::ClientOrigin origin, struct WebCore::PermissionDescriptor descriptor) -> (std::optional<WebCore::PermissionState> state, bool shouldCache) Async
 
 #if ENABLE(APPLE_PAY_AMS_UI)
     StartApplePayAMSUISession(URL originatingURL, struct WebCore::ApplePayAMSUIRequest request) -> (std::optional<bool> result) Async

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (289611 => 289612)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2022-02-11 09:49:20 UTC (rev 289612)
@@ -838,6 +838,8 @@
 		410F0D4C2701EFF900F96DFC /* GPUProcessConnectionInitializationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 410F0D4B2701EFEA00F96DFC /* GPUProcessConnectionInitializationParameters.h */; };
 		411A8DDB20DDD1AC0060D34F /* WKMockMediaDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		411B22641E371BA6004F7363 /* LibWebRTCNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 411B22621E371244004F7363 /* LibWebRTCNetwork.h */; };
+		411B89C927B2B75D00F9EBD3 /* WKQueryPermissionResultCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 411B89C727B2B75C00F9EBD3 /* WKQueryPermissionResultCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		411B89CC27B2B89800F9EBD3 /* QueryPermissionResultCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 411B89CB27B2B89600F9EBD3 /* QueryPermissionResultCallback.h */; };
 		41287D4E225D1ECB009A3E26 /* WebSocketTaskCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41287D4B225C05C4009A3E26 /* WebSocketTaskCocoa.mm */; };
 		413075AC1DE85F370039EC69 /* NetworkRTCMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4130759B1DE84FB00039EC69 /* NetworkRTCMonitor.h */; };
 		413075AD1DE85F580039EC69 /* LibWebRTCSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 413075A01DE85EE70039EC69 /* LibWebRTCSocket.h */; };
@@ -4070,6 +4072,9 @@
 		411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMockMediaDevice.h; sourceTree = "<group>"; };
 		411A8DDA20DDB6050060D34F /* WKMockMediaDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKMockMediaDevice.cpp; sourceTree = "<group>"; };
 		411B22621E371244004F7363 /* LibWebRTCNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCNetwork.h; path = Network/webrtc/LibWebRTCNetwork.h; sourceTree = "<group>"; };
+		411B89C727B2B75C00F9EBD3 /* WKQueryPermissionResultCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKQueryPermissionResultCallback.h; sourceTree = "<group>"; };
+		411B89C827B2B75D00F9EBD3 /* WKQueryPermissionResultCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKQueryPermissionResultCallback.cpp; sourceTree = "<group>"; };
+		411B89CB27B2B89600F9EBD3 /* QueryPermissionResultCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QueryPermissionResultCallback.h; sourceTree = "<group>"; };
 		41287D4B225C05C4009A3E26 /* WebSocketTaskCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebSocketTaskCocoa.mm; sourceTree = "<group>"; };
 		41287D4C225C05C5009A3E26 /* WebSocketTaskCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketTaskCocoa.h; sourceTree = "<group>"; };
 		41287D4D225C161F009A3E26 /* WebSocketTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketTask.h; sourceTree = "<group>"; };
@@ -11041,6 +11046,7 @@
 				83048AE51ACA45DC0082C832 /* ProcessThrottlerClient.h */,
 				4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */,
 				4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */,
+				411B89CB27B2B89600F9EBD3 /* QueryPermissionResultCallback.h */,
 				1A0C227C2451130A00ED614D /* QuickLookThumbnailingSoftLink.h */,
 				1A0C227D2451130A00ED614D /* QuickLookThumbnailingSoftLink.mm */,
 				1AEE57232409F142002005D6 /* QuickLookThumbnailLoader.h */,
@@ -11397,6 +11403,8 @@
 				512F58F312A88A5400629530 /* WKProtectionSpace.cpp */,
 				512F58F412A88A5400629530 /* WKProtectionSpace.h */,
 				518ACAE912AEE6BB00B04B83 /* WKProtectionSpaceTypes.h */,
+				411B89C827B2B75D00F9EBD3 /* WKQueryPermissionResultCallback.cpp */,
+				411B89C727B2B75C00F9EBD3 /* WKQueryPermissionResultCallback.h */,
 				33367638130C99DC006C9DE2 /* WKResourceCacheManager.cpp */,
 				33367639130C99DC006C9DE2 /* WKResourceCacheManager.h */,
 				1ADE46B01954EC61000F7985 /* WKSessionStateRef.cpp */,
@@ -13342,6 +13350,7 @@
 				EB36B16827A7B4500050E00D /* PushService.h in Headers */,
 				EBA8D3B527A5E33F00CB7900 /* PushServiceConnection.h in Headers */,
 				A1E688701F6E2BAB007006A6 /* QuarantineSPI.h in Headers */,
+				411B89CC27B2B89800F9EBD3 /* QueryPermissionResultCallback.h in Headers */,
 				1A0C227E2451130A00ED614D /* QuickLookThumbnailingSoftLink.h in Headers */,
 				1AEE57252409F142002005D6 /* QuickLookThumbnailLoader.h in Headers */,
 				93B631F327ABAD8000443A44 /* QuotaIncreaseRequestIdentifier.h in Headers */,
@@ -14098,6 +14107,7 @@
 				512F58FC12A88A5400629530 /* WKProtectionSpace.h in Headers */,
 				5272D4C91E735F0900EB4290 /* WKProtectionSpaceNS.h in Headers */,
 				518ACAEA12AEE6BB00B04B83 /* WKProtectionSpaceTypes.h in Headers */,
+				411B89C927B2B75D00F9EBD3 /* WKQueryPermissionResultCallback.h in Headers */,
 				F4D5F51F206087A10038BBA8 /* WKQuickboardViewControllerDelegate.h in Headers */,
 				F4975CF22624B80A003C626E /* WKQuickLookPreviewController.h in Headers */,
 				1AD01BCD1905D54900C9C45F /* WKReloadFrameErrorRecoveryAttempter.h in Headers */,

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.cpp (289611 => 289612)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.cpp	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -43,19 +43,11 @@
 {
 }
 
-WebCore::PermissionState WebPermissionController::query(WebCore::ClientOrigin&& origin, WebCore::PermissionDescriptor&& descriptor)
+void WebPermissionController::query(WebCore::ClientOrigin&& origin, WebCore::PermissionDescriptor&& descriptor, CompletionHandler<void(std::optional<WebCore::PermissionState>)>&& completionHandler)
 {
     if (!m_page)
-        return WebCore::PermissionState::Denied;
+        return completionHandler({ });
 
-    return queryCache(WTFMove(origin), WTFMove(descriptor));
-}
-
-void WebPermissionController::request(WebCore::ClientOrigin&& origin, WebCore::PermissionDescriptor&& descriptor, CompletionHandler<void(WebCore::PermissionState)>&& completionHandler)
-{
-    if (!m_page)
-        return completionHandler(WebCore::PermissionState::Denied);
-
     auto cachedResult = queryCache(origin, descriptor);
     if (cachedResult != WebCore::PermissionState::Prompt)
         return completionHandler(cachedResult);
@@ -112,13 +104,14 @@
         }
 
         currentRequest.isWaitingForReply = true;
-        m_page->sendWithAsyncReply(Messages::WebPageProxy::requestPermission(currentRequest.origin, currentRequest.descriptor), [this, weakThis = WeakPtr { *this }](auto state) {
+        m_page->sendWithAsyncReply(Messages::WebPageProxy::QueryPermission(currentRequest.origin, currentRequest.descriptor), [this, weakThis = WeakPtr { *this }](auto state, bool shouldCache) {
             if (!weakThis)
                 return;
 
             auto takenRequest = m_requests.takeFirst();
             takenRequest.completionHandler(state);
-            updateCache(takenRequest.origin, takenRequest.descriptor, state);
+            if (shouldCache && state)
+                updateCache(takenRequest.origin, takenRequest.descriptor, *state);
 
             tryProcessingRequests();
         });

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.h (289611 => 289612)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -43,8 +43,7 @@
     explicit WebPermissionController(WebPage&);
 
     // WebCore::PermissionController
-    WebCore::PermissionState query(WebCore::ClientOrigin&&, WebCore::PermissionDescriptor&&) final;
-    void request(WebCore::ClientOrigin&&, WebCore::PermissionDescriptor&&, CompletionHandler<void(WebCore::PermissionState)>&&) final;
+    void query(WebCore::ClientOrigin&&, WebCore::PermissionDescriptor&&, CompletionHandler<void(std::optional<WebCore::PermissionState>)>&&) final;
     void addObserver(WebCore::PermissionObserver&) final;
     void removeObserver(WebCore::PermissionObserver&) final;
 
@@ -62,7 +61,7 @@
     struct PermissionRequest {
         WebCore::ClientOrigin origin;
         WebCore::PermissionDescriptor descriptor;
-        CompletionHandler<void(WebCore::PermissionState)> completionHandler;
+        CompletionHandler<void(std::optional<WebCore::PermissionState>)> completionHandler;
         bool isWaitingForReply { false };
     };
     Deque<PermissionRequest> m_requests;

Modified: trunk/Tools/ChangeLog (289611 => 289612)


--- trunk/Tools/ChangeLog	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Tools/ChangeLog	2022-02-11 09:49:20 UTC (rev 289612)
@@ -1,3 +1,21 @@
+2022-02-11  Youenn Fablet  <[email protected]>
+
+        Add support to query camera and microphone permissions
+        https://bugs.webkit.org/show_bug.cgi?id=236138
+
+        Reviewed by Eric Carlson.
+
+        * TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm:
+        (-[UserMediaCaptureUIDelegate _webView:queryPermission:forOrigin:completionHandler:]):
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit/GetUserMedia.mm:
+        * TestWebKitAPI/Tests/WebKit/getUserMediaPermission.html: Added.
+        * TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h:
+        * TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::queryPermission):
+        (WTR::TestController::createWebViewWithOptions):
+
 2022-02-10  Commit Queue  <[email protected]>
 
         Unreviewed, reverting r289525.

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (289611 => 289612)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2022-02-11 09:49:20 UTC (rev 289612)
@@ -54,6 +54,7 @@
 		074994421EA5034B000DA44F /* ondevicechange.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 4A410F4D19AF7BEF002EBAB6 /* ondevicechange.html */; };
 		074994421EA5034B000DA45E /* getUserMediaAudioVideoCapture.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 4A410F4D19AF7BEF002EBAC5 /* getUserMediaAudioVideoCapture.html */; };
 		074994521EA5034B000DA44E /* getUserMedia2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 41BAF4E225AC9DB800D82F32 /* getUserMedia2.html */; };
+		074994521EA5034B000DA46E /* getUserMediaPermission.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 4198524F27AD7B70005477B7 /* getUserMediaPermission.html */; };
 		075A9CF526177218006DFA3A /* MediaSessionCoordinatorTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 075A9CF426177217006DFA3A /* MediaSessionCoordinatorTest.mm */; };
 		076E507F1F4513D6006E9F5A /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076E507E1F45031E006E9F5A /* Logging.cpp */; };
 		077A5AF3230638A600A7105C /* AccessibilityTestPlugin.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0746645822FF630500E3451A /* AccessibilityTestPlugin.mm */; };
@@ -1367,6 +1368,7 @@
 				074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */,
 				074994521EA5034B000DA44E /* getUserMedia2.html in Copy Resources */,
 				074994421EA5034B000DA45E /* getUserMediaAudioVideoCapture.html in Copy Resources */,
+				074994521EA5034B000DA46E /* getUserMediaPermission.html in Copy Resources */,
 				F46A095B1ED8A6E600D4AA55 /* gif-and-file-input.html in Copy Resources */,
 				573255A522139BC700396AE8 /* helloworld.webarchive in Copy Resources */,
 				9B4F8FA7159D52DD002D9F94 /* HTMLCollectionNamedItem.html in Copy Resources */,
@@ -1971,6 +1973,7 @@
 		41882F0221010A70002FF288 /* ProcessPreWarming.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProcessPreWarming.mm; sourceTree = "<group>"; };
 		418FCBD52707066100F96ECA /* PushAPI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PushAPI.mm; sourceTree = "<group>"; };
 		41973B5C1AF22875006C7B36 /* SharedBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SharedBuffer.cpp; sourceTree = "<group>"; };
+		4198524F27AD7B70005477B7 /* getUserMediaPermission.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = getUserMediaPermission.html; sourceTree = "<group>"; };
 		41BAF4E225AC9DB800D82F32 /* getUserMedia2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = getUserMedia2.html; sourceTree = "<group>"; };
 		41E67A8425D16E83007B0A4C /* STUNMessageParsingTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = STUNMessageParsingTest.cpp; sourceTree = "<group>"; };
 		44077BB0231449D200179E2D /* DataDetectorsTestIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataDetectorsTestIOS.mm; sourceTree = "<group>"; };
@@ -4702,6 +4705,7 @@
 				4A410F4D19AF7BEF002EBAB5 /* getUserMedia.html */,
 				41BAF4E225AC9DB800D82F32 /* getUserMedia2.html */,
 				4A410F4D19AF7BEF002EBAC5 /* getUserMediaAudioVideoCapture.html */,
+				4198524F27AD7B70005477B7 /* getUserMediaPermission.html */,
 				BCBD372E125ABBE600D2C29F /* icon.png */,
 				1CC80CE92474F1F7004DC489 /* idempotent-mode-autosizing-only-honors-percentages.html */,
 				CE3524F51B142BBB0028A7C5 /* input-focus-blur.html */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm (289611 => 289612)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm	2022-02-11 09:49:20 UTC (rev 289612)
@@ -972,6 +972,91 @@
     [delegate waitUntilPrompted];
 }
 
+
+static _WKExperimentalFeature *permissionsAPIEnabledExperimentalFeature()
+{
+    static RetainPtr<_WKExperimentalFeature> theFeature;
+    if (theFeature)
+        return theFeature.get();
+
+    NSArray *features = [WKPreferences _experimentalFeatures];
+    for (_WKExperimentalFeature *feature in features) {
+        if ([feature.key isEqual:@"PermissionsAPIEnabled"]) {
+            theFeature = feature;
+            break;
+        }
+    }
+    return theFeature.get();
+}
+
+TEST(WebKit2, CapturePermission)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto processPoolConfig = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+    initializeMediaCaptureConfiguration(configuration.get());
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:permissionsAPIEnabledExperimentalFeature()];
+
+    auto messageHandler = adoptNS([[GUMMessageHandler alloc] init]);
+    [[configuration.get() userContentController] addScriptMessageHandler:messageHandler.get() name:@"gum"];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get() processPoolConfiguration:processPoolConfig.get()]);
+    auto delegate = adoptNS([[UserMediaCaptureUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    done = false;
+    [webView loadTestPageNamed:@"getUserMediaPermission"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [delegate setAudioDecision:WKPermissionDecisionPrompt];
+    [delegate setVideoDecision:WKPermissionDecisionPrompt];
+    [webView stringByEvaluatingJavaScript:@"checkPermission('microphone', 'prompt')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView stringByEvaluatingJavaScript:@"checkPermission('camera', 'prompt')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [delegate setAudioDecision:WKPermissionDecisionGrant];
+    [delegate setVideoDecision:WKPermissionDecisionGrant];
+    [webView stringByEvaluatingJavaScript:@"checkPermission('microphone', 'granted')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    [webView stringByEvaluatingJavaScript:@"checkPermission('camera', 'granted')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Although Deny, we expect prompt is exposed since we do not trust the page to call getUserMedia.
+    [delegate setAudioDecision:WKPermissionDecisionDeny];
+    [delegate setVideoDecision:WKPermissionDecisionDeny];
+    [webView stringByEvaluatingJavaScript:@"checkPermission('microphone', 'prompt')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    [webView stringByEvaluatingJavaScript:@"checkPermission('camera', 'prompt')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Now that we getUserMedia has been called, we can go with deny.
+    [webView stringByEvaluatingJavaScript:@"captureVideo()"];
+    [delegate waitUntilPrompted];
+    [webView stringByEvaluatingJavaScript:@"checkPermission('microphone', 'prompt')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    [webView stringByEvaluatingJavaScript:@"checkPermission('camera', 'denied')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView stringByEvaluatingJavaScript:@"captureAudio()"];
+    [delegate waitUntilPrompted];
+    [webView stringByEvaluatingJavaScript:@"checkPermission('microphone', 'denied')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    [webView stringByEvaluatingJavaScript:@"checkPermission('camera', 'denied')"];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
 } // namespace TestWebKitAPI
 
 #endif // ENABLE(MEDIA_STREAM)

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit/getUserMediaPermission.html (0 => 289612)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/getUserMediaPermission.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/getUserMediaPermission.html	2022-02-11 09:49:20 UTC (rev 289612)
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script>
+            let stream = null;
+
+            function stop()
+            {
+                stream.getTracks().forEach(track => { track.stop() });
+            }
+
+            function captureAudio()
+            {
+                navigator.mediaDevices.getUserMedia({audio: true}).then(s => stream = s);
+            }
+
+            function captureVideo()
+            {
+                navigator.mediaDevices.getUserMedia({video: true}).then(s => stream = s);
+            }
+
+            function checkPermission(name, expected) {
+                navigator.permissions.query({ name }).then((status) => {
+                    window.webkit.messageHandlers.gum.postMessage(expected == status.state  ? "PASS" : ("FAILED, expected " + expected + " but got " + status.state));
+                }, error => window.webkit.messageHandlers.gum.postMessage("Permission query failed with " + error));
+            }
+
+        </script>
+    <head>
+
+    <body _onload_="window.webkit.messageHandlers.gum.postMessage('PASS')">
+    </body>
+</html>

Modified: trunk/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h (289611 => 289612)


--- trunk/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h	2022-02-11 09:49:20 UTC (rev 289612)
@@ -50,6 +50,7 @@
 - (void)webView:(WKWebView *)webView requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame type:(WKMediaCaptureType)type decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler;
 - (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler;
 - (void)_webView:(WKWebView *)webView requestDisplayCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame withSystemAudio:(BOOL)withSystemAudio decisionHandler:(void (^)(WKDisplayCapturePermissionDecision decision))decisionHandler;
+- (void)_webView:(WKWebView *)webView queryPermission:(NSString*) name forOrigin:(WKSecurityOrigin *)origin completionHandler:(void (^)(WKPermissionDecision state))completionHandler;
 
 @end
 

Modified: trunk/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm (289611 => 289612)


--- trunk/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm	2022-02-11 09:49:20 UTC (rev 289612)
@@ -72,6 +72,19 @@
     _getDisplayMediaDecision = decision;
 }
 
+- (void)_webView:(WKWebView *)webView queryPermission:(NSString*) name forOrigin:(WKSecurityOrigin *)origin completionHandler:(void (^)(WKPermissionDecision state))completionHandler {
+    if ([name isEqualToString:@"camera"]) {
+        completionHandler(_videoDecision);
+        return;
+    }
+    if ([name isEqualToString:@"microphone"]) {
+        completionHandler(_audioDecision);
+        return;
+    }
+    ASSERT_NOT_REACHED();
+    completionHandler(WKPermissionDecisionDeny);
+}
+
 - (void)webView:(WKWebView *)webView requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame type:(WKMediaCaptureType)type decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler {
     ++_numberOfPrompts;
     _wasPrompted = true;

Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (289611 => 289612)


--- trunk/Tools/WebKitTestRunner/TestController.cpp	2022-02-11 09:16:53 UTC (rev 289611)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp	2022-02-11 09:49:20 UTC (rev 289612)
@@ -63,6 +63,7 @@
 #include <WebKit/WKPluginInformation.h>
 #include <WebKit/WKPreferencesRefPrivate.h>
 #include <WebKit/WKProtectionSpace.h>
+#include <WebKit/WKQueryPermissionResultCallback.h>
 #include <WebKit/WKRetainPtr.h>
 #include <WebKit/WKSecurityOriginRef.h>
 #include <WebKit/WKSpeechRecognitionPermissionCallback.h>
@@ -359,6 +360,11 @@
     m_isMediaKeySystemPermissionGranted = granted;
 }
 
+static void queryPermission(WKStringRef, WKSecurityOriginRef, WKQueryPermissionResultCallbackRef callback)
+{
+    WKQueryPermissionResultCallbackCompleteWithPrompt(callback);
+}
+
 void TestController::closeOtherPage(WKPageRef page, PlatformWebView* view)
 {
     WKPageClose(page);
@@ -733,8 +739,8 @@
     WKHTTPCookieStoreDeleteAllCookies(WKWebsiteDataStoreGetHTTPCookieStore(websiteDataStore()), nullptr, nullptr);
 
     platformCreateWebView(configuration.get(), options);
-    WKPageUIClientV16 pageUIClient = {
-        { 16, m_mainWebView.get() },
+    WKPageUIClientV18 pageUIClient = {
+        { 18, m_mainWebView.get() },
         0, // createNewPage_deprecatedForUseWithV0
         0, // showPage
         0, // close
@@ -809,7 +815,9 @@
         shouldAllowDeviceOrientationAndMotionAccess,
         runWebAuthenticationPanel,
         decidePolicyForSpeechRecognitionPermissionRequest,
-        decidePolicyForMediaKeySystemPermissionRequest
+        decidePolicyForMediaKeySystemPermissionRequest,
+        nullptr, // requestWebAuthenticationNoGesture
+        queryPermission
     };
     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to