diff --git a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml index d925e0028081b..baa9addf75f84 100644 --- a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml +++ b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml @@ -1140,7 +1140,7 @@ PermissionsAPIEnabled: WebKitLegacy: default: false WebKit: - "PLATFORM(COCOA)" : true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)" : true default: false WebCore: default: false diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index 5cf6fcc28fb5b..7080aafb176a9 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -196,6 +196,7 @@ set(WPE_API_INSTALLED_HEADERS ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitOptionMenu.h ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitOptionMenuItem.h ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPermissionRequest.h + ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPermissionStateQuery.h ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPlugin.h ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPolicyDecision.h ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitRectangle.h diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt index dc22908b2f276..8bc69ea61028b 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -163,6 +163,7 @@ UIProcess/API/glib/WebKitNotificationProvider.cpp @no-unify UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify UIProcess/API/glib/WebKitOptionMenuItem.cpp @no-unify UIProcess/API/glib/WebKitPermissionRequest.cpp @no-unify +UIProcess/API/glib/WebKitPermissionStateQuery.cpp @no-unify UIProcess/API/glib/WebKitPlugin.cpp @no-unify UIProcess/API/glib/WebKitPointerLockPermissionRequest.cpp @no-unify UIProcess/API/glib/WebKitPolicyDecision.cpp @no-unify diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt index 79fa705d8250c..72eda3608d7d0 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -155,6 +155,7 @@ UIProcess/API/glib/WebKitNotificationProvider.cpp @no-unify UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify UIProcess/API/glib/WebKitOptionMenuItem.cpp @no-unify UIProcess/API/glib/WebKitPermissionRequest.cpp @no-unify +UIProcess/API/glib/WebKitPermissionStateQuery.cpp @no-unify UIProcess/API/glib/WebKitPlugin.cpp @no-unify UIProcess/API/glib/WebKitPolicyDecision.cpp @no-unify UIProcess/API/glib/WebKitPrivate.cpp @no-unify diff --git a/Source/WebKit/UIProcess/API/glib/WebKitPermissionStateQuery.cpp b/Source/WebKit/UIProcess/API/glib/WebKitPermissionStateQuery.cpp new file mode 100644 index 0000000000000..921c9e676afac --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitPermissionStateQuery.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2022 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebKitPermissionStateQuery.h" + +#include "APISecurityOrigin.h" +#include "WebKitPermissionStateQueryPrivate.h" +#include "WebKitSecurityOriginPrivate.h" +#include + +/** + * WebKitPermissionStateQuery: + * @See_also: #WebKitWebView + * + * This query represents a user's choice to allow or deny access to "powerful features" of the + * platform, as specified in the [Permissions W3C + * Specification](https://w3c.github.io/permissions/). + * + * When signalled by the #WebKitWebView through the `query-permission-state` signal, the application + * has to eventually respond, via `webkit_permission_state_query_finish()`, whether it grants, + * denies or requests a dedicated permission prompt for the given query. + * + * When a #WebKitPermissionStateQuery is not handled by the user, the user-agent is instructed to + * `prompt` the user for the given permission. + */ + +struct _WebKitPermissionStateQuery { + explicit _WebKitPermissionStateQuery(const WTF::String& permissionName, API::SecurityOrigin& origin, CompletionHandler)>&& completionHandler) + : permissionName(permissionName.utf8()) + , securityOrigin(webkitSecurityOriginCreate(origin.securityOrigin().isolatedCopy())) + , completionHandler(WTFMove(completionHandler)) + { + } + + ~_WebKitPermissionStateQuery() + { + // Fallback to Prompt response unless the completion handler was already called. + if (completionHandler) + completionHandler(WebCore::PermissionState::Prompt); + + webkit_security_origin_unref(securityOrigin); + } + + CString permissionName; + WebKitSecurityOrigin* securityOrigin; + CompletionHandler)> completionHandler; + int referenceCount { 1 }; +}; + +G_DEFINE_BOXED_TYPE(WebKitPermissionStateQuery, webkit_permission_state_query, webkit_permission_state_query_ref, webkit_permission_state_query_unref) + +WebKitPermissionStateQuery* webkitPermissionStateQueryCreate(const WTF::String& permissionName, API::SecurityOrigin& origin, CompletionHandler)>&& completionHandler) +{ + WebKitPermissionStateQuery* query = static_cast(fastMalloc(sizeof(WebKitPermissionStateQuery))); + new (query) WebKitPermissionStateQuery(permissionName, origin, WTFMove(completionHandler)); + return query; +} + +/** + * webkit_permission_state_query_ref: + * @query: a #WebKitPermissionStateQuery + * + * Atomically increments the reference count of @query by one. + * + * This function is MT-safe and may be called from any thread. + * + * Returns: The passed #WebKitPermissionStateQuery + * + * Since: 2.40 + */ +WebKitPermissionStateQuery* webkit_permission_state_query_ref(WebKitPermissionStateQuery* query) +{ + g_return_val_if_fail(query, nullptr); + + g_atomic_int_inc(&query->referenceCount); + return query; +} + +/** + * webkit_permission_state_query_unref: + * @query: a #WebKitPermissionStateQuery + * + * Atomically decrements the reference count of @query by one. + * + * If the reference count drops to 0, all memory allocated by #WebKitPermissionStateQuery is + * released. This function is MT-safe and may be called from any thread. + * + * Since: 2.40 + */ +void webkit_permission_state_query_unref(WebKitPermissionStateQuery* query) +{ + g_return_if_fail(query); + + if (g_atomic_int_dec_and_test(&query->referenceCount)) { + query->~WebKitPermissionStateQuery(); + fastFree(query); + } +} + +/** + * webkit_permission_state_query_get_name: + * @query: a #WebKitPermissionStateQuery + * + * Get the permission name for which access is being queried. + * + * Returns: the permission name for @query + * + * Since: 2.40 + */ +const gchar* +webkit_permission_state_query_get_name(WebKitPermissionStateQuery* query) +{ + g_return_val_if_fail(query, nullptr); + + return query->permissionName.data(); +} + +/** + * webkit_permission_state_query_get_security_origin: + * @query: a #WebKitPermissionStateQuery + * + * Get the permission origin for which access is being queried. + * + * Returns: (transfer none): A #WebKitSecurityOrigin representing the origin from which the + * @query was emitted. + * + * Since: 2.40 + */ +WebKitSecurityOrigin * +webkit_permission_state_query_get_security_origin(WebKitPermissionStateQuery* query) +{ + g_return_val_if_fail(query, nullptr); + + return query->securityOrigin; +} + +/** + * webkit_permission_state_query_finish: + * @query: a #WebKitPermissionStateQuery + * @state: a #WebKitPermissionState + * + * Notify the web-engine of the selected permission state for the given query. This function should + * only be called as a response to the `WebKitWebView::query-permission-state` signal. + * + * Since: 2.40 + */ +void +webkit_permission_state_query_finish(WebKitPermissionStateQuery* query, WebKitPermissionState state) +{ + g_return_if_fail(query); + g_return_if_fail(query->completionHandler); + + switch (state) { + case WEBKIT_PERMISSION_STATE_GRANTED: + query->completionHandler(WebCore::PermissionState::Granted); + break; + case WEBKIT_PERMISSION_STATE_DENIED: + query->completionHandler(WebCore::PermissionState::Denied); + break; + case WEBKIT_PERMISSION_STATE_PROMPT: + query->completionHandler(WebCore::PermissionState::Prompt); + break; + } +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitPermissionStateQueryPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitPermissionStateQueryPrivate.h new file mode 100644 index 0000000000000..502e0ed44bb03 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitPermissionStateQueryPrivate.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "APISecurityOrigin.h" +#include "WebKitPermissionStateQuery.h" +#include +#include +#include + +WebKitPermissionStateQuery* webkitPermissionStateQueryCreate(const WTF::String& permissionName, API::SecurityOrigin&, CompletionHandler)>&&); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp index de9103ae41248..71e21d08924a3 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp @@ -29,6 +29,7 @@ #include "WebKitMediaKeySystemPermissionRequestPrivate.h" #include "WebKitNavigationActionPrivate.h" #include "WebKitNotificationPermissionRequestPrivate.h" +#include "WebKitPermissionStateQueryPrivate.h" #include "WebKitPointerLockPermissionRequestPrivate.h" #include "WebKitURIRequestPrivate.h" #include "WebKitUserMediaPermissionRequestPrivate.h" @@ -378,6 +379,13 @@ class UIClient : public API::UIClient { } #endif + void queryPermission(const WTF::String& permissionName, API::SecurityOrigin& origin, CompletionHandler)>&& completionHandler) final + { + auto* query = webkitPermissionStateQueryCreate(permissionName, origin, WTFMove(completionHandler)); + webkitWebViewPermissionStateQuery(m_webView, query); + webkit_permission_state_query_unref(query); + } + WebKitWebView* m_webView; #if ENABLE(POINTER_LOCK) WebKitPointerLockPermissionRequest* m_pointerLockPermissionRequest { nullptr }; diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index 12c68734ca5ea..23cbe87377b87 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -52,6 +52,7 @@ #include "WebKitJavascriptResultPrivate.h" #include "WebKitNavigationClient.h" #include "WebKitNotificationPrivate.h" +#include "WebKitPermissionStateQueryPrivate.h" #include "WebKitPrivate.h" #include "WebKitResponsePolicyDecision.h" #include "WebKitScriptDialogPrivate.h" @@ -71,11 +72,11 @@ #include "WebPageMessages.h" #include #include -#include #include #include #include #include +#include #include #include #include @@ -170,6 +171,8 @@ enum { USER_MESSAGE_RECEIVED, + QUERY_PERMISSION_STATE, + LAST_SIGNAL }; @@ -2396,6 +2399,33 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_USER_MESSAGE); + + /** + * WebKitWebView::query-permission-state: + * @web_view: the #WebKitWebView on which the signal is emitted + * @query: the #WebKitPermissionStateQuery + * + * This signal allows the User-Agent to respond to permission requests for powerful features, as + * specified by the [Permissions W3C Specification](https://w3c.github.io/permissions/). + * You can reply to the query using webkit_permission_state_query_finish(). + * + * You can handle the query asynchronously by calling webkit_permission_state_query_ref() on + * @query and returning %TRUE. If the last reference of @query is removed and the query has not + * been handled, the query result will be set to %WEBKIT_QUERY_PERMISSION_PROMPT. + * + * Returns: %TRUE if the message was handled, or %FALSE otherwise. + * + * Since: 2.40 + */ + signals[QUERY_PERMISSION_STATE] = g_signal_new( + "query-permission-state", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, query_permission_state), + g_signal_accumulator_true_handled, nullptr /* accumulator data */, + g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 1, /* number of parameters */ + WEBKIT_TYPE_PERMISSION_STATE_QUERY); } static void webkitWebViewCompleteAuthenticationRequest(WebKitWebView* webView) @@ -2992,6 +3022,12 @@ bool webkitWebViewShowOptionMenu(WebKitWebView* webView, const IntRect& rect, We } #endif +void webkitWebViewPermissionStateQuery(WebKitWebView* webView, WebKitPermissionStateQuery* query) +{ + gboolean result; + g_signal_emit(webView, signals[QUERY_PERMISSION_STATE], 0, query, &result); +} + #if PLATFORM(WPE) /** * webkit_web_view_get_backend: diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h index fbab1afe9ca09..c2fcc20ffe4e7 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h @@ -95,6 +95,7 @@ void webkitWebViewMediaCaptureStateDidChange(WebKitWebView*, WebCore::MediaProdu void webkitWebViewSelectionDidChange(WebKitWebView*); void webkitWebViewRequestInstallMissingMediaPlugins(WebKitWebView*, WebKit::InstallMissingMediaPluginsPermissionRequest&); WebKitWebsiteDataManager* webkitWebViewGetWebsiteDataManager(WebKitWebView*); +void webkitWebViewPermissionStateQuery(WebKitWebView*, WebKitPermissionStateQuery*); #if PLATFORM(GTK) bool webkitWebViewEmitRunColorChooser(WebKitWebView*, WebKitColorChooserRequest*); diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitAutocleanups.h b/Source/WebKit/UIProcess/API/gtk/WebKitAutocleanups.h index 25df7d0785cf8..424811884e007 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitAutocleanups.h +++ b/Source/WebKit/UIProcess/API/gtk/WebKitAutocleanups.h @@ -90,6 +90,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (WebKitUserStyleSheet, webkit_user_style_sheet_unr G_DEFINE_AUTOPTR_CLEANUP_FUNC (WebKitUserContentFilter, webkit_user_content_filter_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (WebKitWebsiteData, webkit_website_data_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (WebKitWebViewSessionState, webkit_web_view_session_state_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (WebKitPermissionStateQuery, webkit_permission_state_query_unref) #endif /* __GI_SCANNER__ */ #endif /* G_DEFINE_AUTOPTR_CLEANUP_FUNC */ diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitPermissionStateQuery.h b/Source/WebKit/UIProcess/API/wpe/WebKitPermissionStateQuery.h new file mode 100644 index 0000000000000..dd564e8fa874c --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitPermissionStateQuery.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if !defined(__WEBKIT_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef WebKitPermissionStateQuery_h +#define WebKitPermissionStateQuery_h + +#include +#include +#include + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_PERMISSION_STATE_QUERY (webkit_permission_state_query_get_type()) + +typedef struct _WebKitPermissionStateQuery WebKitPermissionStateQuery; + +/** + * WebKitPermissionState: + * @WEBKIT_PERMISSION_STATE_GRANTED: Access to the feature is granted. + * @WEBKIT_PERMISSION_STATE_DENIED: Access to the feature is denied. + * @WEBKIT_PERMISSION_STATE_PROMPT: Access to the feature has to be requested via user prompt. + * + * Enum values representing query permission results. + * + * Since: 2.40 + */ +typedef enum { + WEBKIT_PERMISSION_STATE_GRANTED, + WEBKIT_PERMISSION_STATE_DENIED, + WEBKIT_PERMISSION_STATE_PROMPT, +} WebKitPermissionState; + +WEBKIT_API GType +webkit_permission_state_query_get_type (void); + +WEBKIT_API WebKitPermissionStateQuery * +webkit_permission_state_query_ref (WebKitPermissionStateQuery *query); + +WEBKIT_API void +webkit_permission_state_query_unref (WebKitPermissionStateQuery *query); + +WEBKIT_API const gchar * +webkit_permission_state_query_get_name (WebKitPermissionStateQuery *query); + +WEBKIT_API WebKitSecurityOrigin * +webkit_permission_state_query_get_security_origin (WebKitPermissionStateQuery *query); + +WEBKIT_API void +webkit_permission_state_query_finish (WebKitPermissionStateQuery *query, + WebKitPermissionState state); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h index b120111e6b609..06b61a947a2bf 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -288,13 +289,15 @@ struct _WebKitWebViewClass { WebKitOptionMenu *menu, WebKitRectangle *rectangle); + gboolean (* query_permission_state) (WebKitWebView *web_view, + WebKitPermissionStateQuery *query); + /*< private >*/ void (*_webkit_reserved0) (void); void (*_webkit_reserved1) (void); void (*_webkit_reserved2) (void); void (*_webkit_reserved3) (void); void (*_webkit_reserved4) (void); - void (*_webkit_reserved5) (void); }; WEBKIT_API GType diff --git a/Source/WebKit/UIProcess/API/wpe/webkit.h b/Source/WebKit/UIProcess/API/wpe/webkit.h index c2221efc00618..184cb74757015 100644 --- a/Source/WebKit/UIProcess/API/wpe/webkit.h +++ b/Source/WebKit/UIProcess/API/wpe/webkit.h @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include diff --git a/Tools/TestWebKitAPI/Tests/WebKitGLib/TestUIClient.cpp b/Tools/TestWebKitAPI/Tests/WebKitGLib/TestUIClient.cpp index a754c94dfa973..1ac290f39346a 100644 --- a/Tools/TestWebKitAPI/Tests/WebKitGLib/TestUIClient.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKitGLib/TestUIClient.cpp @@ -257,6 +257,32 @@ class UIClientTest: public WebViewTest { g_main_loop_quit(test->m_mainLoop); } + static gboolean queryPermissionStateCallback(WebKitWebView*, WebKitPermissionStateQuery* query, UIClientTest* test) + { + if (!g_strcmp0(test->m_expectedQueryPermissionReply, "prompt-default")) + return FALSE; + + WebKitPermissionState state = WEBKIT_PERMISSION_STATE_PROMPT; + + if (!g_strcmp0(test->m_expectedQueryPermissionReply, "granted")) + state = WEBKIT_PERMISSION_STATE_GRANTED; + if (!g_strcmp0(test->m_expectedQueryPermissionReply, "denied")) + state = WEBKIT_PERMISSION_STATE_DENIED; + + g_assert_cmpstr(webkit_permission_state_query_get_name(query), ==, "screen-wake-lock"); + + GUniquePtr origin(webkit_security_origin_to_string(webkit_permission_state_query_get_security_origin(query))); + g_assert_cmpstr(origin.get(), ==, "https://foo.com"); + + webkit_permission_state_query_finish(query, state); + return TRUE; + } + + static void queryPermissionResultMessageReceivedCallback(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* javascriptResult, UIClientTest* test) + { + test->m_queryPermissionResult.reset(WebViewTest::javascriptResultToCString(javascriptResult)); + g_main_loop_quit(test->m_mainLoop); + } static void displayCaptureChanged(WebKitWebView* webView, GParamSpec*, UIClientTest* test) { @@ -327,8 +353,11 @@ class UIClientTest: public WebViewTest { g_signal_connect(m_webView, "script-dialog", G_CALLBACK(scriptDialog), this); g_signal_connect(m_webView, "mouse-target-changed", G_CALLBACK(mouseTargetChanged), this); g_signal_connect(m_webView, "permission-request", G_CALLBACK(permissionRequested), this); + g_signal_connect(m_webView, "query-permission-state", G_CALLBACK(queryPermissionStateCallback), this); webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "permission"); + webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "queryPermission"); g_signal_connect(m_userContentManager.get(), "script-message-received::permission", G_CALLBACK(permissionResultMessageReceivedCallback), this); + g_signal_connect(m_userContentManager.get(), "script-message-received::queryPermission", G_CALLBACK(queryPermissionResultMessageReceivedCallback), this); } ~UIClientTest() @@ -336,6 +365,7 @@ class UIClientTest: public WebViewTest { g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); g_signal_handlers_disconnect_matched(m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "permission"); + webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "queryPermission"); } static void tryWebViewCloseCallback(UIClientTest* test) @@ -368,6 +398,13 @@ class UIClientTest: public WebViewTest { return m_permissionResult.get(); } + const char* waitUntilQueryPermissionResultMessageReceived() + { + m_queryPermissionResult = nullptr; + g_main_loop_run(m_mainLoop); + return m_queryPermissionResult.get(); + } + void setExpectedWindowProperties(const WindowProperties& windowProperties) { m_windowProperties = windowProperties; @@ -469,6 +506,7 @@ class UIClientTest: public WebViewTest { bool m_scriptDialogConfirmed; bool m_delayedScriptDialogs { false }; bool m_allowPermissionRequests; + const char* m_expectedQueryPermissionReply; gboolean m_verifyMediaTypes; gboolean m_expectedAudioMedia; gboolean m_expectedVideoMedia; @@ -478,6 +516,7 @@ class UIClientTest: public WebViewTest { GRefPtr m_mouseTargetHitTestResult; unsigned m_mouseTargetModifiers; GUniquePtr m_permissionResult; + GUniquePtr m_queryPermissionResult; bool m_waitingForMouseTargetChange { false }; #if PLATFORM(GTK) @@ -964,6 +1003,51 @@ static void testWebViewMediaKeySystemPermissionRequests(UIClientTest* test, gcon } #endif +static void testWebViewQueryPermissionRequests(UIClientTest* test, gconstpointer) +{ + test->showInWindow(); + static const char* queryHTML = + "" + " " + " " + ""; + + // Test granting a permission state query. + test->m_expectedQueryPermissionReply = "granted"; + test->loadHtml(queryHTML, "https://foo.com/bar"); + const gchar* result = test->waitUntilQueryPermissionResultMessageReceived(); + g_assert_cmpstr(result, ==, test->m_expectedQueryPermissionReply); + + // Test requesting a user prompt for the given permission type. + test->m_expectedQueryPermissionReply = "prompt"; + test->loadHtml(queryHTML, "https://foo.com/bar"); + result = test->waitUntilQueryPermissionResultMessageReceived(); + g_assert_cmpstr(result, ==, test->m_expectedQueryPermissionReply); + + // Test denying a permission state query. + test->m_expectedQueryPermissionReply = "denied"; + test->loadHtml(queryHTML, "https://foo.com/bar"); + result = test->waitUntilQueryPermissionResultMessageReceived(); + g_assert_cmpstr(result, ==, test->m_expectedQueryPermissionReply); + + // Test returning FALSE from the signal handler, we should then expect the state to be `prompt`. + test->m_expectedQueryPermissionReply = "prompt-default"; + test->loadHtml(queryHTML, "https://foo.com/bar"); + result = test->waitUntilQueryPermissionResultMessageReceived(); + g_assert_cmpstr(result, ==, "prompt"); +} + #if ENABLE(MEDIA_STREAM) static void testWebViewUserMediaEnumerateDevicesPermissionCheck(UIClientTest* test, gconstpointer) { @@ -1472,6 +1556,7 @@ void beforeAll() #if ENABLE(ENCRYPTED_MEDIA) UIClientTest::add("WebKitWebView", "mediaKeySystem-permission-requests", testWebViewMediaKeySystemPermissionRequests); #endif + UIClientTest::add("WebKitWebView", "query-permission-requests", testWebViewQueryPermissionRequests); #if ENABLE(MEDIA_STREAM) UIClientTest::add("WebKitWebView", "usermedia-enumeratedevices-permission-check", testWebViewUserMediaEnumerateDevicesPermissionCheck); UIClientTest::add("WebKitWebView", "usermedia-permission-requests", testWebViewUserMediaPermissionRequests);