[GTK] Support script message handlers WebKitUserContentManager
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Oct 2014 19:04:19 +0000 (19:04 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Oct 2014 19:04:19 +0000 (19:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133730

Patch by Adrian Perez de Castro <aperez@igalia.com> on 2014-10-31
Reviewed by Carlos Garcia Campos.

Support user script message handlers in WebKitUserContentManager.
This needs building with ENABLE_USER_MESSAGE_HANDLERS, for which
an option is added to the CMake build files. The option is disabled
globally by default, and the WebKitGTK port enables it. On the API
level, two new methods to register and unregister names are provided
in the "window.webkit" namespace, and on message reception the
"WebKitUserContentManager::script-message-received" signal is
emitted, using the registered names as signal detail.

.:

* Source/cmake/OptionsGTK.cmake: For the GTK port, enable the
ENABLE_USER_MESSAGE_HANDLERS feature by default.
* Source/cmake/WebKitFeatures.cmake: Add feature description for
ENABLE_USER_MESSAGE_HANDLERS, disabled by default.

Source/WebCore:

* CMakeLists.txt: Conditionally add the needed files to the build
when the ENABLE_USER_MESSAGE_HANDLERS feature is enabled.

Source/WebKit2:

* UIProcess/API/gtk/WebKitJavascriptResult.cpp: Add a new private
function to construct a WebKitJavascriptResult directly from a
WebCore::SerializedScriptValue.
(_WebKitJavascriptResult::_WebKitJavascriptResult): Ditto.
(webkitJavascriptResultCreate): Ditto.
* UIProcess/API/gtk/WebKitJavascriptResultPrivate.h: Ditto.
* UIProcess/API/gtk/WebKitUserContentManager.cpp:
(webkit_user_content_manager_class_init): Install the
"script-message-received" signal.
(webkit_user_content_manager_register_script_message_handler):
Added.
(webkit_user_content_manager_unregister_script_message_handler):
Added.
* UIProcess/API/gtk/WebKitUserContentManager.h: Added the new
public API methods.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Ditto.
* UIProcess/API/gtk/docs/webkit2gtk.types: Add
webkit_user_content_manager_get_type() to the list in order to make
gtk-doc to generate documentation for signals.

Tools:

* TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp:
Add test case for user script message handlers.
(scriptMessageReceived):
(testUserContentManagerScriptMessageReceived):
(beforeAll):

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

16 files changed:
ChangeLog
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/gtk/WebKitJavascriptResult.cpp
Source/WebKit2/UIProcess/API/gtk/WebKitJavascriptResultPrivate.h
Source/WebKit2/UIProcess/API/gtk/WebKitUserContentManager.cpp
Source/WebKit2/UIProcess/API/gtk/WebKitUserContentManager.h
Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp
Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt
Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types
Source/cmake/OptionsGTK.cmake
Source/cmake/WebKitFeatures.cmake
Source/cmakeconfig.h.cmake
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp

index a3f2257..0071a34 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2014-10-31  Adrian Perez de Castro  <aperez@igalia.com>
+
+        [GTK] Support script message handlers WebKitUserContentManager
+        https://bugs.webkit.org/show_bug.cgi?id=133730
+
+        Reviewed by Carlos Garcia Campos.
+
+        Support user script message handlers in WebKitUserContentManager.
+        This needs building with ENABLE_USER_MESSAGE_HANDLERS, for which
+        an option is added to the CMake build files. The option is disabled
+        globally by default, and the WebKitGTK port enables it. On the API
+        level, two new methods to register and unregister names are provided
+        in the "window.webkit" namespace, and on message reception the
+        "WebKitUserContentManager::script-message-received" signal is
+        emitted, using the registered names as signal detail.
+
+        * Source/cmake/OptionsGTK.cmake: For the GTK port, enable the
+        ENABLE_USER_MESSAGE_HANDLERS feature by default.
+        * Source/cmake/WebKitFeatures.cmake: Add feature description for
+        ENABLE_USER_MESSAGE_HANDLERS, disabled by default.
+
 2014-10-29  Raphael Kubo da Costa  <rakuco@FreeBSD.org>
 
         [GTK] Bump libsoup's minimum version to 2.42.0.
index 1b12878..0a9a05d 100644 (file)
@@ -3107,6 +3107,21 @@ if (ENABLE_WEB_REPLAY)
     )
 endif ()
 
+if (ENABLE_USER_MESSAGE_HANDLERS)
+    list(APPEND WebCore_IDL_FILES
+        page/UserMessageHandler.idl
+        page/UserMessageHandlersNamespace.idl
+        page/WebKitNamespace.idl
+    )
+    list(APPEND WebCore_SOURCES
+        bindings/js/JSUserMessageHandlersNamespaceCustom.cpp
+        page/UserMessageHandler.cpp
+        page/UserMessageHandlerDescriptor.cpp
+        page/UserMessageHandlersNamespace.cpp
+        page/WebKitNamespace.cpp
+    )
+endif ()
+
 set(WebCoreTestSupport_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/platform/mock"
     "${WEBCORE_DIR}/testing"
index 3bc24f1..e71df49 100644 (file)
@@ -1,3 +1,22 @@
+2014-10-31  Adrian Perez de Castro  <aperez@igalia.com>
+
+        [GTK] Support script message handlers WebKitUserContentManager
+        https://bugs.webkit.org/show_bug.cgi?id=133730
+
+        Reviewed by Carlos Garcia Campos.
+
+        Support user script message handlers in WebKitUserContentManager.
+        This needs building with ENABLE_USER_MESSAGE_HANDLERS, for which
+        an option is added to the CMake build files. The option is disabled
+        globally by default, and the WebKitGTK port enables it. On the API
+        level, two new methods to register and unregister names are provided
+        in the "window.webkit" namespace, and on message reception the
+        "WebKitUserContentManager::script-message-received" signal is
+        emitted, using the registered names as signal detail.
+
+        * CMakeLists.txt: Conditionally add the needed files to the build
+        when the ENABLE_USER_MESSAGE_HANDLERS feature is enabled.
+
 2014-10-31  Andrzej Badowski  <a.badowski@samsung.com>
 
         [ATK] Improve AccessibilityTableCell's determineAccessibilityRole function.
index 4c916f9..618eaf2 100644 (file)
@@ -1,3 +1,39 @@
+2014-10-31  Adrian Perez de Castro  <aperez@igalia.com>
+
+        [GTK] Support script message handlers WebKitUserContentManager
+        https://bugs.webkit.org/show_bug.cgi?id=133730
+
+        Reviewed by Carlos Garcia Campos.
+
+        Support user script message handlers in WebKitUserContentManager.
+        This needs building with ENABLE_USER_MESSAGE_HANDLERS, for which
+        an option is added to the CMake build files. The option is disabled
+        globally by default, and the WebKitGTK port enables it. On the API
+        level, two new methods to register and unregister names are provided
+        in the "window.webkit" namespace, and on message reception the
+        "WebKitUserContentManager::script-message-received" signal is
+        emitted, using the registered names as signal detail.
+
+        * UIProcess/API/gtk/WebKitJavascriptResult.cpp: Add a new private
+        function to construct a WebKitJavascriptResult directly from a
+        WebCore::SerializedScriptValue.
+        (_WebKitJavascriptResult::_WebKitJavascriptResult): Ditto.
+        (webkitJavascriptResultCreate): Ditto.
+        * UIProcess/API/gtk/WebKitJavascriptResultPrivate.h: Ditto.
+        * UIProcess/API/gtk/WebKitUserContentManager.cpp:
+        (webkit_user_content_manager_class_init): Install the
+        "script-message-received" signal.
+        (webkit_user_content_manager_register_script_message_handler):
+        Added.
+        (webkit_user_content_manager_unregister_script_message_handler):
+        Added.
+        * UIProcess/API/gtk/WebKitUserContentManager.h: Added the new
+        public API methods.
+        * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Ditto.
+        * UIProcess/API/gtk/docs/webkit2gtk.types: Add
+        webkit_user_content_manager_get_type() to the list in order to make
+        gtk-doc to generate documentation for signals.
+
 2014-10-31  Martin Hock  <mhock@apple.com>
 
         Unreviewed, iOS build fix since 175406.
index 9bbd3f4..7b935a7 100644 (file)
 using namespace WebKit;
 
 struct _WebKitJavascriptResult {
-    _WebKitJavascriptResult(WebKitWebView* view, WebSerializedScriptValue* serializedScriptValue)
+    _WebKitJavascriptResult(WebKitWebView* view, WebCore::SerializedScriptValue& serializedScriptValue)
         : webView(view)
         , referenceCount(1)
     {
-        value = serializedScriptValue->deserialize(webkit_web_view_get_javascript_global_context(view), 0);
+        value = serializedScriptValue.deserialize(webkit_web_view_get_javascript_global_context(view), nullptr);
     }
 
     GRefPtr<WebKitWebView> webView;
@@ -42,7 +42,7 @@ struct _WebKitJavascriptResult {
 
 G_DEFINE_BOXED_TYPE(WebKitJavascriptResult, webkit_javascript_result, webkit_javascript_result_ref, webkit_javascript_result_unref)
 
-WebKitJavascriptResult* webkitJavascriptResultCreate(WebKitWebView* webView, WebSerializedScriptValue* serializedScriptValue)
+WebKitJavascriptResult* webkitJavascriptResultCreate(WebKitWebView* webView, WebCore::SerializedScriptValue& serializedScriptValue)
 {
     WebKitJavascriptResult* result = g_slice_new(WebKitJavascriptResult);
     new (result) WebKitJavascriptResult(webView, serializedScriptValue);
index e47e94c..23e2e79 100644 (file)
 #ifndef WebKitJavascriptResultPrivate_h
 #define WebKitJavascriptResultPrivate_h
 
+#include <WebCore/SerializedScriptValue.h>
 #include "WebKitJavascriptResult.h"
 #include "WebKitPrivate.h"
 #include "WebKitWebView.h"
 
-WebKitJavascriptResult* webkitJavascriptResultCreate(WebKitWebView*, WebKit::WebSerializedScriptValue*);
+WebKitJavascriptResult* webkitJavascriptResultCreate(WebKitWebView*, WebCore::SerializedScriptValue&);
 
 #endif // WebKitJavascriptResultPrivate_h
index 5ed7999..544f1c0 100644 (file)
 #include "config.h"
 #include "WebKitUserContentManager.h"
 
+#include "WebKitJavascriptResultPrivate.h"
 #include "WebKitPrivate.h"
 #include "WebKitUserContentManagerPrivate.h"
 #include "WebKitUserContentPrivate.h"
+#include "WebKitWebContextPrivate.h"
+#include "WebScriptMessageHandler.h"
+#include "WebSerializedScriptValue.h"
 #include <wtf/gobject/GRefPtr.h>
 
 using namespace WebCore;
@@ -59,8 +63,39 @@ struct _WebKitUserContentManagerPrivate {
 
 WEBKIT_DEFINE_TYPE(WebKitUserContentManager, webkit_user_content_manager, G_TYPE_OBJECT)
 
-static void webkit_user_content_manager_class_init(WebKitUserContentManagerClass*)
+enum {
+    SCRIPT_MESSAGE_RECEIVED,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static void webkit_user_content_manager_class_init(WebKitUserContentManagerClass* klass)
 {
+    GObjectClass* gObjectClass = G_OBJECT_CLASS(klass);
+
+    /**
+     * WebKitUserContentManager::script-message-received:
+     * @manager: the #WebKitUserContentManager
+     * @js_result: the #WebKitJavascriptResult holding the value received from the JavaScript world.
+     *
+     * This signal is emitted when JavaScript in a web view calls
+     * <code>window.webkit.messageHandlers.&lt;name&gt;.postMessage()</code>, after registering
+     * <code>&lt;name&gt;</code> using
+     * webkit_user_content_manager_register_script_message_handler()
+     *
+     * Since: 2.8
+     */
+    signals[SCRIPT_MESSAGE_RECEIVED] =
+        g_signal_new(
+            "script-message-received",
+            G_TYPE_FROM_CLASS(gObjectClass),
+            static_cast<GSignalFlags>(G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED),
+            0, nullptr, nullptr,
+            g_cclosure_marshal_VOID__BOXED,
+            G_TYPE_NONE, 1,
+            WEBKIT_TYPE_JAVASCRIPT_RESULT);
 }
 
 /**
@@ -141,6 +176,90 @@ void webkit_user_content_manager_remove_all_scripts(WebKitUserContentManager* ma
     manager->priv->userContentController->removeAllUserScripts();
 }
 
+class ScriptMessageClientGtk final : public WebScriptMessageHandler::Client {
+public:
+    ScriptMessageClientGtk(WebKitUserContentManager* manager, const char* handlerName)
+        : m_handlerName(g_quark_from_string(handlerName))
+        , m_manager(manager)
+    {
+    }
+
+    virtual void didPostMessage(WebPageProxy& page, WebFrameProxy&, WebCore::SerializedScriptValue& serializedScriptValue)
+    {
+        WebKitJavascriptResult* jsResult = webkitJavascriptResultCreate(WEBKIT_WEB_VIEW(page.viewWidget()), serializedScriptValue);
+        g_signal_emit(m_manager, signals[SCRIPT_MESSAGE_RECEIVED], m_handlerName, jsResult);
+        webkit_javascript_result_unref(jsResult);
+    }
+
+    virtual ~ScriptMessageClientGtk() { }
+
+private:
+    GQuark m_handlerName;
+    WebKitUserContentManager* m_manager;
+};
+
+/**
+ * webkit_user_content_manager_register_script_message_handler:
+ * @manager: A #WebKitUserContentManager
+ * @name: Name of the script message channel
+ *
+ * Registers a new user script message handler. After it is registered,
+ * scripts can use `window.webkit.messageHandlers.&lt;name&gt;.postMessage(value)`
+ * to send messages. Those messages are received by connecting handlers
+ * to the #WebKitUserContentManager::script-message-received signal. The
+ * handler name is used as the detail of the signal. To avoid race
+ * conditions between registering the handler name, and starting to
+ * receive the signals, it is recommended to connect to the signal
+ * *before* registering the handler name:
+ *
+ * <informalexample><programlisting>
+ * WebKitWebView *view = webkit_web_view_new ();
+ * WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager ();
+ * g_signal_connect (manager, "script-message-received::foobar",
+ *                   G_CALLBACK (handle_script_message), NULL);
+ * webkit_user_content_manager_register_script_message_handler (manager, "foobar");
+ * </programlisting></informalexample>
+ *
+ * Registering a script message handler will fail if the requested
+ * name has been already registered before.
+ *
+ * Returns: %TRUE if message handler was registered successfully, or %FALSE otherwise.
+ *
+ * Since: 2.8
+ */
+gboolean webkit_user_content_manager_register_script_message_handler(WebKitUserContentManager* manager, const char* name)
+{
+    g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_MANAGER(manager), FALSE);
+    g_return_val_if_fail(name, FALSE);
+
+    RefPtr<WebScriptMessageHandler> handler =
+        WebScriptMessageHandler::create(std::make_unique<ScriptMessageClientGtk>(manager, name), String::fromUTF8(name));
+    return manager->priv->userContentController->addUserScriptMessageHandler(handler.get());
+}
+
+/**
+ * webkit_user_content_manager_unregister_script_message_handler:
+ * @manager: A #WebKitUserContentManager
+ * @name: Name of the script message channel
+ *
+ * Unregisters a previously registered message handler.
+ *
+ * Note that this does *not* disconnect handlers for the
+ * #WebKitUserContentManager::script-message-received signal,
+ * they will be kept connected, but the signal will not be emitted
+ * unless the handler name is registered again.
+ *
+ * See also webkit_user_content_manager_register_script_message_handler()
+ *
+ * Since: 2.8
+ */
+void webkit_user_content_manager_unregister_script_message_handler(WebKitUserContentManager* manager, const char* name)
+{
+    g_return_if_fail(WEBKIT_IS_USER_CONTENT_MANAGER(manager));
+    g_return_if_fail(name);
+    manager->priv->userContentController->removeUserMessageHandlerForName(String::fromUTF8(name));
+}
+
 WebUserContentControllerProxy* webkitUserContentManagerGetUserContentControllerProxy(WebKitUserContentManager* manager)
 {
     return manager->priv->userContentController.get();
index b605f7f..86d24a1 100644 (file)
@@ -60,16 +60,23 @@ struct _WebKitUserContentManagerClass {
 
 
 WEBKIT_API GType
-webkit_user_content_manager_get_type                (void);
+webkit_user_content_manager_get_type                          (void);
 
 WEBKIT_API WebKitUserContentManager *
-webkit_user_content_manager_new                     (void);
+webkit_user_content_manager_new                               (void);
 
 WEBKIT_API void
-webkit_user_content_manager_add_style_sheet         (WebKitUserContentManager *manager,
-                                                     WebKitUserStyleSheet     *stylesheet);
+webkit_user_content_manager_add_style_sheet                   (WebKitUserContentManager *manager,
+                                                               WebKitUserStyleSheet     *stylesheet);
 WEBKIT_API void
-webkit_user_content_manager_remove_all_style_sheets (WebKitUserContentManager *manager);
+webkit_user_content_manager_remove_all_style_sheets           (WebKitUserContentManager *manager);
+
+WEBKIT_API gboolean
+webkit_user_content_manager_register_script_message_handler   (WebKitUserContentManager *manager,
+                                                               const gchar              *name);
+WEBKIT_API void
+webkit_user_content_manager_unregister_script_message_handler (WebKitUserContentManager *manager,
+                                                               const gchar              *name);
 
 WEBKIT_API void
 webkit_user_content_manager_add_script              (WebKitUserContentManager *manager,
index a359fde..f62de41 100644 (file)
@@ -57,6 +57,7 @@
 #include "WebKitWebViewBasePrivate.h"
 #include "WebKitWebViewPrivate.h"
 #include "WebKitWindowPropertiesPrivate.h"
+#include "WebSerializedScriptValue.h"
 #include <JavaScriptCore/APICast.h>
 #include <WebCore/CertificateInfo.h>
 #include <WebCore/DragIcon.h>
@@ -2778,7 +2779,8 @@ static void webkitWebViewRunJavaScriptCallback(WebSerializedScriptValue* wkSeria
     }
 
     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task));
-    g_task_return_pointer(task, webkitJavascriptResultCreate(webView, wkSerializedScriptValue),
+    g_task_return_pointer(task, webkitJavascriptResultCreate(webView,
+        *static_cast<WebCore::SerializedScriptValue*>(wkSerializedScriptValue->internalRepresentation())),
         reinterpret_cast<GDestroyNotify>(webkit_javascript_result_unref));
 }
 
index 50265e4..6be7039 100644 (file)
@@ -106,6 +106,8 @@ webkit_user_content_manager_add_style_sheet
 webkit_user_content_manager_remove_all_style_sheets
 webkit_user_content_manager_add_script
 webkit_user_content_manager_remove_all_scripts
+webkit_user_content_manager_register_script_message_handler
+webkit_user_content_manager_unregister_script_message_handler
 
 <SUBSECTION Standard>
 WEBKIT_IS_USER_CONTENT_MANAGER
index 2446dc2..375d15b 100644 (file)
@@ -27,3 +27,4 @@ webkit_authentication_request_get_type
 webkit_credential_get_type
 webkit_frame_get_type
 webkit_certificate_info_get_type
+webkit_user_content_manager_get_type
index 9801c9d..a75b90e 100644 (file)
@@ -145,6 +145,7 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SUBTLE_CRYPTO OFF)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_TEMPLATE_ELEMENT ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_TOUCH_EVENTS ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_USERSELECT_ALL ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_USER_MESSAGE_HANDLERS ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_VIBRATION OFF)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_VIDEO ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_VIDEO_TRACK ON)
index 19a0987..21d59e2 100644 (file)
@@ -132,6 +132,7 @@ macro(WEBKIT_OPTION_BEGIN)
     WEBKIT_OPTION_DEFINE(ENABLE_TOUCH_SLIDER "Toggle Touch Slider support" OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_TOUCH_ICON_LOADING "Toggle Touch Icon Loading Support" OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_USERSELECT_ALL "Toggle user-select:all support" OFF)
+    WEBKIT_OPTION_DEFINE(ENABLE_USER_MESSAGE_HANDLERS "Toggle user script message handler support" OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_USER_TIMING "Toggle User Timing support" OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_VIBRATION "Toggle Vibration API support" OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_VIDEO "Toggle Video support" OFF)
index b240fd9..d1efe66 100644 (file)
 #cmakedefine01 ENABLE_TOUCH_SLIDER
 #cmakedefine01 ENABLE_TOUCH_ICON_LOADING
 #cmakedefine01 ENABLE_USERSELECT_ALL
+#cmakedefine01 ENABLE_USER_MESSAGE_HANDLERS
 #cmakedefine01 ENABLE_USER_TIMING
 #cmakedefine01 ENABLE_VIBRATION
 #cmakedefine01 ENABLE_VIDEO
index 5df54a7..6426431 100644 (file)
@@ -1,3 +1,25 @@
+2014-10-31  Adrian Perez de Castro  <aperez@igalia.com>
+
+        [GTK] Support script message handlers WebKitUserContentManager
+        https://bugs.webkit.org/show_bug.cgi?id=133730
+
+        Reviewed by Carlos Garcia Campos.
+
+        Support user script message handlers in WebKitUserContentManager.
+        This needs building with ENABLE_USER_MESSAGE_HANDLERS, for which
+        an option is added to the CMake build files. The option is disabled
+        globally by default, and the WebKitGTK port enables it. On the API
+        level, two new methods to register and unregister names are provided
+        in the "window.webkit" namespace, and on message reception the
+        "WebKitUserContentManager::script-message-received" signal is
+        emitted, using the registered names as signal detail.
+
+        * TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp:
+        Add test case for user script message handlers.
+        (scriptMessageReceived):
+        (testUserContentManagerScriptMessageReceived):
+        (beforeAll):
+
 2014-10-30  Matthew Hanson  <matthew_hanson@apple.com>
 
         bisect-builds should support WebKit clients other than Safari
index 6bc7e67..a31f3ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Igalia S.L.
+ * Copyright (C) 2013-2014 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@
 #include <gtk/gtk.h>
 #include <webkit2/webkit2.h>
 #include <wtf/gobject/GRefPtr.h>
+#include <wtf/gobject/GUniquePtr.h>
 
 class UserContentManagerTest : public WebViewTest {
 public:
@@ -212,6 +213,134 @@ static void testUserContentManagerInjectedScript(UserContentManagerTest* test, g
     removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
 }
 
+class UserScriptMessageTest : public UserContentManagerTest {
+public:
+    MAKE_GLIB_TEST_FIXTURE(UserScriptMessageTest);
+
+    UserScriptMessageTest()
+        : UserContentManagerTest()
+        , m_userScriptMessage(nullptr)
+    {
+    }
+
+    ~UserScriptMessageTest()
+    {
+        if (m_userScriptMessage)
+            webkit_javascript_result_unref(m_userScriptMessage);
+    }
+
+    bool registerHandler(const char* handlerName)
+    {
+        return webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), handlerName);
+    }
+
+    void unregisterHandler(const char* handlerName)
+    {
+        webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), handlerName);
+    }
+
+    static void scriptMessageReceived(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* jsResult, UserScriptMessageTest* test)
+    {
+        g_signal_handlers_disconnect_by_func(userContentManager, reinterpret_cast<gpointer>(scriptMessageReceived), test);
+        g_main_loop_quit(test->m_mainLoop);
+
+        g_assert(!test->m_userScriptMessage);
+        test->m_userScriptMessage = webkit_javascript_result_ref(jsResult);
+    }
+
+    WebKitJavascriptResult* postMessageAndWaitUntilReceived(const char* handlerName, const char* javascriptValueAsText)
+    {
+        if (m_userScriptMessage) {
+            webkit_javascript_result_unref(m_userScriptMessage);
+            m_userScriptMessage = nullptr;
+        }
+
+        GUniquePtr<char> signalName(g_strdup_printf("script-message-received::%s", handlerName));
+        g_signal_connect(m_userContentManager.get(), signalName.get(), G_CALLBACK(scriptMessageReceived), this);
+
+        GUniquePtr<char> javascriptSnippet(g_strdup_printf("window.webkit.messageHandlers.%s.postMessage(%s);", handlerName, javascriptValueAsText));
+        webkit_web_view_run_javascript(m_webView, javascriptSnippet.get(), nullptr, nullptr, nullptr);
+        g_main_loop_run(m_mainLoop);
+
+        g_assert(m_userScriptMessage);
+        return m_userScriptMessage;
+    }
+
+private:
+    WebKitJavascriptResult* m_userScriptMessage;
+};
+
+static void testUserContentManagerScriptMessageReceived(UserScriptMessageTest* test, gconstpointer)
+{
+    g_assert(test->registerHandler("msg"));
+
+    // Trying to register the same handler a second time must fail.
+    g_assert(!test->registerHandler("msg"));
+
+    test->loadHtml("<html></html>", nullptr);
+    test->waitUntilLoadFinished();
+
+    // Check that the "window.webkit.messageHandlers" namespace exists.
+    GUniqueOutPtr<GError> error;
+    WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers ? 'y' : 'n';", &error.outPtr());
+    g_assert(javascriptResult);
+    g_assert(!error.get());
+    GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "y");
+
+    // Check that the "document.webkit.messageHandlers.msg" namespace exists.
+    javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.msg ? 'y' : 'n';", &error.outPtr());
+    g_assert(javascriptResult);
+    g_assert(!error.get());
+    valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "y");
+
+    valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("msg", "'user message'")));
+    g_assert_cmpstr(valueString.get(), ==, "user message");
+
+    // Messages should arrive despite of other handlers being registered.
+    g_assert(test->registerHandler("anotherHandler"));
+
+    // Check that the "document.webkit.messageHandlers.msg" namespace still exists.
+    javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.msg ? 'y' : 'n';", &error.outPtr());
+    g_assert(javascriptResult);
+    g_assert(!error.get());
+    valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "y");
+
+    // Check that the "document.webkit.messageHandlers.anotherHandler" namespace exists.
+    javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.anotherHandler ? 'y' : 'n';", &error.outPtr());
+    g_assert(javascriptResult);
+    g_assert(!error.get());
+    valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "y");
+
+    valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("msg", "'handler: msg'")));
+    g_assert_cmpstr(valueString.get(), ==, "handler: msg");
+
+    valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("anotherHandler", "'handler: anotherHandler'")));
+    g_assert_cmpstr(valueString.get(), ==, "handler: anotherHandler");
+
+    // Unregistering a handler and re-registering again under the same name should work.
+    test->unregisterHandler("msg");
+
+    // FIXME: Enable after https://bugs.webkit.org/show_bug.cgi?id=138142 gets fixed.
+#if 0
+    javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.msg.postMessage('42');", &error.outPtr());
+    g_assert(!javascriptResult);
+    g_assert(error.get());
+
+    // Re-registering a handler that has been unregistered must work
+    g_assert(test->registerHandler("msg"));
+    message = test->postMessageAndWaitUntilReceived("msg", "'handler: msg'");
+    valueString.reset(WebViewTest::javascriptResultToCString(message));
+    webkit_javascript_result_unref(message);
+    g_assert_cmpstr(valueString.get(), ==, "handler: msg");
+#endif
+
+    test->unregisterHandler("anotherHandler");
+}
+
 static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
 {
     soup_message_set_status(message, SOUP_STATUS_OK);
@@ -227,6 +356,7 @@ void beforeAll()
     Test::add("WebKitWebView", "new-with-user-content-manager", testWebViewNewWithUserContentManager);
     UserContentManagerTest::add("WebKitUserContentManager", "injected-style-sheet", testUserContentManagerInjectedStyleSheet);
     UserContentManagerTest::add("WebKitUserContentManager", "injected-script", testUserContentManagerInjectedScript);
+    UserScriptMessageTest::add("WebKitUserContentManager", "script-message-received", testUserContentManagerScriptMessageReceived);
 }
 
 void afterAll()