Diff
Modified: trunk/Source/_javascript_Core/API/glib/JSCDefines.h (295525 => 295526)
--- trunk/Source/_javascript_Core/API/glib/JSCDefines.h 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/_javascript_Core/API/glib/JSCDefines.h 2022-06-14 17:09:19 UTC (rev 295526)
@@ -23,7 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION)
+#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
Modified: trunk/Source/WebKit/Shared/API/APISerializedScriptValue.h (295525 => 295526)
--- trunk/Source/WebKit/Shared/API/APISerializedScriptValue.h 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/WebKit/Shared/API/APISerializedScriptValue.h 2022-06-14 17:09:19 UTC (rev 295526)
@@ -64,6 +64,10 @@
static RefPtr<SerializedScriptValue> createFromNSObject(id);
#endif
+#if USE(GLIB)
+ static RefPtr<SerializedScriptValue> createFromGVariant(GVariant*);
+#endif
+
IPC::DataReference dataReference() const { return m_serializedScriptValue->wireBytes(); }
WebCore::SerializedScriptValue& internalRepresentation() { return m_serializedScriptValue.get(); }
Modified: trunk/Source/WebKit/SourcesGTK.txt (295525 => 295526)
--- trunk/Source/WebKit/SourcesGTK.txt 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/WebKit/SourcesGTK.txt 2022-06-14 17:09:19 UTC (rev 295526)
@@ -121,6 +121,7 @@
UIProcess/API/C/gtk/WKView.cpp
UIProcess/API/glib/APIContentRuleListStoreGLib.cpp @no-unify
+UIProcess/API/glib/APISerializedScriptValueGLib.cpp @no-unify
UIProcess/API/glib/IconDatabase.cpp @no-unify
UIProcess/API/glib/InputMethodFilter.cpp @no-unify
UIProcess/API/glib/WebKitApplicationInfo.cpp @no-unify
Modified: trunk/Source/WebKit/SourcesWPE.txt (295525 => 295526)
--- trunk/Source/WebKit/SourcesWPE.txt 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/WebKit/SourcesWPE.txt 2022-06-14 17:09:19 UTC (rev 295526)
@@ -114,6 +114,7 @@
UIProcess/API/C/wpe/WKView.cpp
UIProcess/API/glib/APIContentRuleListStoreGLib.cpp @no-unify
+UIProcess/API/glib/APISerializedScriptValueGLib.cpp @no-unify
UIProcess/API/glib/IconDatabase.cpp @no-unify
UIProcess/API/glib/InputMethodFilter.cpp @no-unify
UIProcess/API/glib/WebKitApplicationInfo.cpp @no-unify
Added: trunk/Source/WebKit/UIProcess/API/glib/APISerializedScriptValueGLib.cpp (0 => 295526)
--- trunk/Source/WebKit/UIProcess/API/glib/APISerializedScriptValueGLib.cpp (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/glib/APISerializedScriptValueGLib.cpp 2022-06-14 17:09:19 UTC (rev 295526)
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * 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 "APISerializedScriptValue.h"
+
+#include <_javascript_Core/APICast.h>
+#include <_javascript_Core/JSBase.h>
+#include <_javascript_Core/JSContextPrivate.h>
+#include <_javascript_Core/JSGlobalObjectInlines.h>
+#include <_javascript_Core/JSRemoteInspector.h>
+#include <jsc/JSCContextPrivate.h>
+#include <jsc/JSCValuePrivate.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RunLoop.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+
+namespace API {
+
+static constexpr auto sharedJSContextMaxIdleTime = 10_s;
+
+class SharedJSContext {
+public:
+ SharedJSContext()
+ : m_timer(RunLoop::main(), this, &SharedJSContext::releaseContextIfNecessary)
+ {
+ }
+
+ JSCContext* ensureContext()
+ {
+ m_lastUseTime = MonotonicTime::now();
+ if (!m_context) {
+ bool previous = JSRemoteInspectorGetInspectionEnabledByDefault();
+ JSRemoteInspectorSetInspectionEnabledByDefault(false);
+ m_context = adoptGRef(jsc_context_new());
+ JSRemoteInspectorSetInspectionEnabledByDefault(previous);
+
+ m_timer.startOneShot(sharedJSContextMaxIdleTime);
+ }
+ return m_context.get();
+ }
+
+ void releaseContextIfNecessary()
+ {
+ auto idleTime = MonotonicTime::now() - m_lastUseTime;
+ if (idleTime < sharedJSContextMaxIdleTime) {
+ // We lazily restart the timer if needed every 10 seconds instead of doing so every time ensureContext()
+ // is called, for performance reasons.
+ m_timer.startOneShot(sharedJSContextMaxIdleTime - idleTime);
+ return;
+ }
+ m_context.clear();
+ }
+
+private:
+ GRefPtr<JSCContext> m_context;
+ RunLoop::Timer<SharedJSContext> m_timer;
+ MonotonicTime m_lastUseTime;
+};
+
+static SharedJSContext& sharedContext()
+{
+ static NeverDestroyed<SharedJSContext> sharedContext;
+ return sharedContext.get();
+}
+
+static GRefPtr<JSCValue> valueFromGVariant(JSCContext* context, GVariant* variant)
+{
+ if (g_variant_is_container(variant)) {
+ auto result = adoptGRef(jsc_value_new_object(context, nullptr, nullptr));
+ GVariantIter iter;
+ g_variant_iter_init(&iter, variant);
+ const char* key;
+ GVariant* value;
+ while (g_variant_iter_loop(&iter, "{&sv}", &key, &value)) {
+ if (!key)
+ continue;
+ auto jsValue = valueFromGVariant(context, value);
+ if (jsValue)
+ jsc_value_object_set_property(result.get(), key, jsValue.get());
+ }
+ return result;
+ }
+
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_uint32(variant)));
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT32))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_int32(variant)));
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT64))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_uint64(variant)));
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT64))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_int64(variant)));
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT16))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_int16(variant)));
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT16))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_uint16(variant)));
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_DOUBLE))
+ return adoptGRef(jsc_value_new_number(context, g_variant_get_double(variant)));
+
+ if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING))
+ return adoptGRef(jsc_value_new_string(context, g_variant_get_string(variant, nullptr)));
+
+ g_warning("Unhandled %s GVariant for conversion to JSCValue", g_variant_get_type_string(variant));
+ return nullptr;
+}
+
+static RefPtr<WebCore::SerializedScriptValue> coreValueFromGVariant(GVariant* variant)
+{
+ if (!variant)
+ return nullptr;
+
+ ASSERT(RunLoop::isMain());
+ auto* context = sharedContext().ensureContext();
+ auto value = valueFromGVariant(context, variant);
+ if (!value)
+ return nullptr;
+
+ auto globalObject = toJS(jscContextGetJSContext(context));
+ ASSERT(globalObject);
+ JSC::JSLockHolder lock(globalObject);
+
+ return WebCore::SerializedScriptValue::create(*globalObject, toJS(globalObject, jscValueGetJSValue(value.get())));
+}
+
+RefPtr<SerializedScriptValue> SerializedScriptValue::createFromGVariant(GVariant* object)
+{
+ auto coreValue = coreValueFromGVariant(object);
+ if (!coreValue)
+ return nullptr;
+ return create(coreValue.releaseNonNull());
+}
+
+}; // namespace API
Modified: trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp (295525 => 295526)
--- trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp 2022-06-14 17:09:19 UTC (rev 295526)
@@ -3994,6 +3994,119 @@
});
}
+/*
+ * webkit_web_view_run_async_javascript_function_in_world:
+ * @web_view: a #WebKitWebView
+ * @body: the _javascript_ function body
+ * @arguments: a #GVariant with format `{&sv}` storing the function arguments. Function argument values must be one of the following types, or contain only the following GVariant types: number, string, array, and dictionary.
+ * @world_name (nullable): the name of a #WebKitScriptWorld, if no name is provided, the default world is used.
+ * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously run @body in the script world with name @world_name of the current page context in
+ * @web_view. If WebKitSettings:enable-_javascript_ is FALSE, this method will do nothing. This API
+ * differs from webkit_web_view_run_javascript_in_world() in that the _javascript_ function can return a
+ * Promise and its result will be properly passed to the callback.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * webkit_web_view_run_javascript_in_world_finish() to get the result of the operation.
+ *
+ * For instance here is a dummy example that shows how to pass arguments to a JS function that
+ * returns a Promise that resolves with the passed argument:
+ *
+ * ```c
+ * static void
+ * web_view_javascript_finished (GObject *object,
+ * GAsyncResult *result,
+ * gpointer user_data)
+ * {
+ * WebKitJavascriptResult *js_result;
+ * JSCValue *value;
+ * GError *error = NULL;
+ *
+ * js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
+ * if (!js_result) {
+ * g_warning ("Error running _javascript_: %s", error->message);
+ * g_error_free (error);
+ * return;
+ * }
+ *
+ * value = webkit_javascript_result_get_js_value (js_result);
+ * if (jsc_value_is_number (value)) {
+ * gint32 int_value = jsc_value_to_string (value);
+ * JSCException *exception = jsc_context_get_exception (jsc_value_get_context (value));
+ * if (exception)
+ * g_warning ("Error running _javascript_: %s", jsc_exception_get_message (exception));
+ * else
+ * g_print ("Script result: %d\n", int_value);
+ * g_free (str_value);
+ * } else {
+ * g_warning ("Error running _javascript_: unexpected return value");
+ * }
+ * webkit_javascript_result_unref (js_result);
+ * }
+ *
+ * static void
+ * web_view_evaluate_promise (WebKitWebView *web_view)
+ * {
+ * GVariantDict dict;
+ * g_variant_dict_init (&dict, NULL);
+ * g_variant_dict_insert (&dict, "count", "u", 42);
+ * GVariant *args = g_variant_dict_end (&dict);
+ * const gchar *body = "return new Promise((resolve) => { resolve(count); });";
+ * webkit_web_view_run_async_javascript_function_in_world (web_view, body, arguments, NULL, NULL, web_view_javascript_finished, NULL);
+ * }
+ * ```
+ *
+ * Since: 2.38
+ */
+void webkit_web_view_run_async_javascript_function_in_world(WebKitWebView* webView, const gchar* body, GVariant* arguments, const char* worldName, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+ g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
+ g_return_if_fail(body);
+ g_return_if_fail(worldName);
+
+ auto task = adoptGRef(g_task_new(webView, cancellable, callback, userData));
+ auto world = API::ContentWorld::sharedWorldWithName(String::fromUTF8(worldName ? worldName : ""));
+ bool hasInvalidArgument = false;
+ auto argumentsMap = WebCore::ArgumentWireBytesMap { };
+
+ if (arguments) {
+ GVariantIter iter;
+ g_variant_iter_init(&iter, arguments);
+ const char* key;
+ GVariant* value;
+ while (g_variant_iter_loop(&iter, "{&sv}", &key, &value)) {
+ if (!key)
+ continue;
+ auto serializedValue = API::SerializedScriptValue::createFromGVariant(value);
+ if (!serializedValue) {
+ hasInvalidArgument = true;
+ break;
+ }
+ argumentsMap.set(String::fromUTF8(key), serializedValue->internalRepresentation().wireBytes());
+ }
+ }
+
+ if (hasInvalidArgument) {
+ ExceptionDetails exceptionDetails;
+ exceptionDetails.message = "Function argument values must be one of the following types, or contain only the following GVariant types: number, string, array, and dictionary"_s;
+ webkitWebViewRunJavaScriptCallback(nullptr, exceptionDetails, task.get());
+ return;
+ }
+
+ getPage(webView).runJavaScriptInFrameInScriptWorld({ String::fromUTF8(body), URL { }, RunAsAsyncFunction::Yes, WTFMove(argumentsMap), ForceUserGesture::Yes }, std::nullopt, world.get(), [task = WTFMove(task)](auto&& result) {
+ RefPtr<API::SerializedScriptValue> serializedScriptValue;
+ ExceptionDetails exceptionDetails;
+ if (result.has_value())
+ serializedScriptValue = WTFMove(result.value());
+ else
+ exceptionDetails = WTFMove(result.error());
+ webkitWebViewRunJavaScriptCallback(serializedScriptValue.get(), exceptionDetails, task.get());
+ });
+}
+
/**
* webkit_web_view_run_javascript_in_world_finish:
* @web_view: a #WebKitWebView
Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebView.h (295525 => 295526)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebView.h 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebView.h 2022-06-14 17:09:19 UTC (rev 295526)
@@ -491,6 +491,15 @@
GError **error);
WEBKIT_API void
+webkit_web_view_run_async_javascript_function_in_world (WebKitWebView *web_view,
+ const gchar *body,
+ GVariant *arguments,
+ const char *world_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+WEBKIT_API void
webkit_web_view_run_javascript_from_gresource (WebKitWebView *web_view,
const gchar *resource,
GCancellable *cancellable,
Modified: trunk/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h (295525 => 295526)
--- trunk/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Source/WebKit/UIProcess/API/wpe/WebKitWebView.h 2022-06-14 17:09:19 UTC (rev 295526)
@@ -474,6 +474,15 @@
GError **error);
WEBKIT_API void
+webkit_web_view_run_async_javascript_function_in_world (WebKitWebView *web_view,
+ const gchar *body,
+ GVariant *arguments,
+ const char *world_name,
+ GCancellable* cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+WEBKIT_API void
webkit_web_view_run_javascript_from_gresource (WebKitWebView *web_view,
const gchar *resource,
GCancellable *cancellable,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp (295525 => 295526)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp 2022-06-14 17:09:19 UTC (rev 295526)
@@ -319,6 +319,125 @@
g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 2.5);
}
+static void testWebViewRunAsyncFunctions(WebViewTest* test, gconstpointer)
+{
+ GUniqueOutPtr<GError> error;
+
+ WebKitJavascriptResult* _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise((resolve) => { resolve(42); });", nullptr, "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+ g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(_javascript_Result), ==, 42);
+
+ GVariantDict dict;
+ g_variant_dict_init(&dict, nullptr);
+ g_variant_dict_insert(&dict, "count", "u", 42);
+ auto* args = g_variant_dict_end(&dict);
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise((resolve) => { resolve(count); });", args, "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+ g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(_javascript_Result), ==, 42);
+
+ g_variant_dict_init(&dict, nullptr);
+ g_variant_dict_insert(&dict, "motto", "s", "Never gonna give you up");
+ args = g_variant_dict_end(&dict);
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise((resolve) => { resolve(motto); });", args, "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+ GUniquePtr<char> valueString(WebViewTest::_javascript_ResultToCString(_javascript_Result));
+ g_assert_cmpstr(valueString.get(), ==, "Never gonna give you up");
+
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise(function(resolve, reject) { setTimeout(function(){ reject('Rejected!') }, 0); })", nullptr, "", &error.outPtr());
+ g_assert_null(_javascript_Result);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+ g_assert_true(g_strstr_len(error->message, strlen(error->message), "Rejected!") != nullptr);
+
+ g_variant_dict_init(&dict, nullptr);
+ g_variant_dict_insert(&dict, "countt", "u", 42);
+ args = g_variant_dict_end(&dict);
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise((resolve) => { resolve(count); });", args, "", &error.outPtr());
+ g_assert_null(_javascript_Result);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+
+ g_variant_dict_init(&dict, nullptr);
+ g_variant_dict_insert(&dict, "count", "u", 42);
+ args = g_variant_dict_end(&dict);
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return count", args, "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+ g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(_javascript_Result), ==, 42);
+
+ {
+ // Set a value in main world.
+ WebKitJavascriptResult* _javascript_Result = test->runJavaScriptInWorldAndWaitUntilFinished("a = 25;", "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+ g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(_javascript_Result), ==, 25);
+
+ // Read back value from main world.
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return a", nullptr, "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+ g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(_javascript_Result), ==, 25);
+
+ // Values of the main world are not available in the isolated one.
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return a", nullptr, "WebExtensionTestScriptWorld", &error.outPtr());
+ g_assert_null(_javascript_Result);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+
+ // Running a script in a world that doesn't exist should fail.
+ _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return a", nullptr, "InvalidScriptWorld", &error.outPtr());
+ g_assert_null(_javascript_Result);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+ }
+
+ {
+ // Disable JS support and expect an error when attempting to evaluate JS code.
+ WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings));
+ g_assert_nonnull(defaultSettings);
+ g_assert_true(webkit_settings_get_enable_javascript(defaultSettings));
+
+ GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_", FALSE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+
+ WebKitJavascriptResult* _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise((resolve) => { resolve(42); });", nullptr, "", &error.outPtr());
+ g_assert_null(_javascript_Result);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_", TRUE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+ }
+
+ {
+ // Disable JS markup support and expect no error when attempting to evaluate JS code.
+ WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings));
+ g_assert_nonnull(defaultSettings);
+ g_assert_true(webkit_settings_get_enable_javascript_markup(defaultSettings));
+
+ GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_-markup", FALSE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+
+ WebKitJavascriptResult* _javascript_Result = test->runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished("return new Promise((resolve) => { resolve(42); });", nullptr, "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_-markup", TRUE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+ }
+}
+
static void testWebViewRunJavaScript(WebViewTest* test, gconstpointer)
{
static const char* html = "<html><body><a id='WebKitLink' href='' title='WebKitGTK Title'>WebKitGTK Website</a></body></html>";
@@ -420,6 +539,47 @@
_javascript_Result = test->runJavaScriptInWorldAndWaitUntilFinished("a", "InvalidScriptWorld", &error.outPtr());
g_assert_null(_javascript_Result);
g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+
+ {
+ // Disable JS support and expect an error when attempting to evaluate JS code.
+ WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings));
+ g_assert_nonnull(defaultSettings);
+ g_assert_true(webkit_settings_get_enable_javascript(defaultSettings));
+
+ GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_", FALSE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+
+ WebKitJavascriptResult* _javascript_Result = test->runJavaScriptInWorldAndWaitUntilFinished("console.log(\"Hi\");", "", &error.outPtr());
+ g_assert_null(_javascript_Result);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
+
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_", TRUE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+ }
+
+ {
+ // Disable JS markup support and expect no error when attempting to evaluate JS code.
+ WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings));
+ g_assert_nonnull(defaultSettings);
+ g_assert_true(webkit_settings_get_enable_javascript_markup(defaultSettings));
+
+ GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_-markup", FALSE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+
+ WebKitJavascriptResult* _javascript_Result = test->runJavaScriptInWorldAndWaitUntilFinished("console.log(\"Hi\");", "", &error.outPtr());
+ g_assert_nonnull(_javascript_Result);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(_javascript_Result)));
+ g_assert_no_error(error.get());
+
+ g_object_set(G_OBJECT(newSettings.get()), "enable-_javascript_-markup", TRUE, NULL);
+ webkit_web_view_set_settings(test->m_webView, newSettings.get());
+ }
}
class FullScreenClientTest: public WebViewTest {
@@ -1731,6 +1891,7 @@
WebViewTest::add("WebKitWebView", "settings", testWebViewSettings);
WebViewTest::add("WebKitWebView", "zoom-level", testWebViewZoomLevel);
WebViewTest::add("WebKitWebView", "run-_javascript_", testWebViewRunJavaScript);
+ WebViewTest::add("WebKitWebView", "run-async-js-functions", testWebViewRunAsyncFunctions);
#if ENABLE(FULLSCREEN_API)
FullScreenClientTest::add("WebKitWebView", "fullscreen", testWebViewFullScreen);
#endif
Modified: trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp (295525 => 295526)
--- trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp 2022-06-14 17:09:19 UTC (rev 295526)
@@ -364,6 +364,18 @@
return m_javascriptResult;
}
+WebKitJavascriptResult* WebViewTest::runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished(const char* body, GVariant* arguments, const char* world, GError** error)
+{
+ if (m_javascriptResult)
+ webkit_javascript_result_unref(m_javascriptResult);
+ m_javascriptResult = 0;
+ m_javascriptError = error;
+ webkit_web_view_run_async_javascript_function_in_world(m_webView, body, arguments, world, nullptr, reinterpret_cast<GAsyncReadyCallback>(runJavaScriptInWorldReadyCallback), this);
+ g_main_loop_run(m_mainLoop);
+
+ return m_javascriptResult;
+}
+
WebKitJavascriptResult* WebViewTest::runJavaScriptWithoutForcedUserGesturesAndWaitUntilFinished(const char* _javascript_, GError** error)
{
if (m_javascriptResult)
Modified: trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.h (295525 => 295526)
--- trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.h 2022-06-14 17:07:46 UTC (rev 295525)
+++ trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.h 2022-06-14 17:09:19 UTC (rev 295526)
@@ -76,6 +76,7 @@
WebKitJavascriptResult* runJavaScriptAndWaitUntilFinished(const char* _javascript_, GError**, WebKitWebView* = nullptr);
WebKitJavascriptResult* runJavaScriptFromGResourceAndWaitUntilFinished(const char* resource, GError**);
WebKitJavascriptResult* runJavaScriptInWorldAndWaitUntilFinished(const char* _javascript_, const char* world, GError**);
+ WebKitJavascriptResult* runAsyncJavaScriptFunctionInWorldAndWaitUntilFinished(const char* body, GVariant* arguments, const char* world, GError**);
WebKitJavascriptResult* runJavaScriptWithoutForcedUserGesturesAndWaitUntilFinished(const char* _javascript_, GError**);
// _javascript_ result helpers.