[GTK] Add WebKit2 API for isolated worlds
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 24 Aug 2013 12:02:04 +0000 (12:02 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 24 Aug 2013 12:02:04 +0000 (12:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=103377

Reviewed by Anders Carlsson.

* GNUmakefile.list.am: Add new files to compilation.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbols.
* UIProcess/API/gtk/tests/TestWebExtensions.cpp:
(testWebExtensionWindowObjectCleared):
(scriptDialogCallback):
(runJavaScriptInIsolatedWorldFinishedCallback):
(testWebExtensionIsolatedWorld):
(beforeAll):
* UIProcess/API/gtk/tests/WebExtensionTest.cpp:
(echoCallback):
(windowObjectCleared):
(getWebPage):
(methodCallCallback):
* WebProcess/InjectedBundle/API/gtk/WebKitFrame.cpp:
(webkit_frame_get_javascript_context_for_script_world): New public
method to tget the JavaScript execution context for a given script
world.
* WebProcess/InjectedBundle/API/gtk/WebKitFrame.h:
* WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp: Added.
(scriptWorlds): Global WebKitScriptWorld map.
(_WebKitScriptWorldPrivate::~_WebKitScriptWorldPrivate):
(webkitScriptWorldGet): Get the WebKitScriptWorld wrapping the
given injected bundle script world.
(webkitScriptWorldGetInjectedBundleScriptWorld): Get the injected
bundle script world wrapped by the given WebKitScriptWorld.
(webkitScriptWorldWindowObjectCleared): Emit
WebKitScriptWorld::window-object-cleared signal.
(webkitScriptWorldCreate): Create a new WebKitScriptWorld wrapping
the given injected bundle script world.
(createDefaultScriptWorld): Create the default WebKitScriptWorld
wrapping the normal world.
(webkit_script_world_get_default): Return the default WebKitScriptWorld.
(webkit_script_world_new): Create a new isolated WebKitScriptWorld.
* WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h: Added.
* WebProcess/InjectedBundle/API/gtk/WebKitScriptWorldPrivate.h: Added.
* WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp:
(didClearWindowObjectForFrame): Call webkitScriptWorldWindowObjectCleared().
(webkitWebPageCreate): Add implementation for callback
didClearWindowObjectForFrame in injected bundle loader client.
* WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h:
Include WebKitScriptWorld.h.

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

12 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/GNUmakefile.list.am
Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt
Source/WebKit2/UIProcess/API/gtk/tests/TestWebExtensions.cpp
Source/WebKit2/UIProcess/API/gtk/tests/WebExtensionTest.cpp
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitFrame.cpp
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitFrame.h
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp [new file with mode: 0644]
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h [new file with mode: 0644]
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorldPrivate.h [new file with mode: 0644]
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp
Source/WebKit2/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h

index 9968a2d..5938cc3 100644 (file)
@@ -1,5 +1,54 @@
 2013-08-24  Carlos Garcia Campos  <cgarcia@igalia.com>
 
+        [GTK] Add WebKit2 API for isolated worlds
+        https://bugs.webkit.org/show_bug.cgi?id=103377
+
+        Reviewed by Anders Carlsson.
+
+        * GNUmakefile.list.am: Add new files to compilation.
+        * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbols.
+        * UIProcess/API/gtk/tests/TestWebExtensions.cpp:
+        (testWebExtensionWindowObjectCleared):
+        (scriptDialogCallback):
+        (runJavaScriptInIsolatedWorldFinishedCallback):
+        (testWebExtensionIsolatedWorld):
+        (beforeAll):
+        * UIProcess/API/gtk/tests/WebExtensionTest.cpp:
+        (echoCallback):
+        (windowObjectCleared):
+        (getWebPage):
+        (methodCallCallback):
+        * WebProcess/InjectedBundle/API/gtk/WebKitFrame.cpp:
+        (webkit_frame_get_javascript_context_for_script_world): New public
+        method to tget the JavaScript execution context for a given script
+        world.
+        * WebProcess/InjectedBundle/API/gtk/WebKitFrame.h:
+        * WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp: Added.
+        (scriptWorlds): Global WebKitScriptWorld map.
+        (_WebKitScriptWorldPrivate::~_WebKitScriptWorldPrivate):
+        (webkitScriptWorldGet): Get the WebKitScriptWorld wrapping the
+        given injected bundle script world.
+        (webkitScriptWorldGetInjectedBundleScriptWorld): Get the injected
+        bundle script world wrapped by the given WebKitScriptWorld.
+        (webkitScriptWorldWindowObjectCleared): Emit
+        WebKitScriptWorld::window-object-cleared signal.
+        (webkitScriptWorldCreate): Create a new WebKitScriptWorld wrapping
+        the given injected bundle script world.
+        (createDefaultScriptWorld): Create the default WebKitScriptWorld
+        wrapping the normal world.
+        (webkit_script_world_get_default): Return the default WebKitScriptWorld.
+        (webkit_script_world_new): Create a new isolated WebKitScriptWorld.
+        * WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h: Added.
+        * WebProcess/InjectedBundle/API/gtk/WebKitScriptWorldPrivate.h: Added.
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp:
+        (didClearWindowObjectForFrame): Call webkitScriptWorldWindowObjectCleared().
+        (webkitWebPageCreate): Add implementation for callback
+        didClearWindowObjectForFrame in injected bundle loader client.
+        * WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h:
+        Include WebKitScriptWorld.h.
+
+2013-08-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
         [GTK] Expose WebKitFrame in WebKit2GTK+ web extensions API
         https://bugs.webkit.org/show_bug.cgi?id=119743
 
index 78c34ad..ed97788 100644 (file)
@@ -140,6 +140,7 @@ webkit2_web_extension_h_api += \
        $(WebKit2)/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.h \
        $(WebKit2)/WebProcess/InjectedBundle/API/gtk/WebKitFrame.h \
        $(WebKit2)/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.h \
+       $(WebKit2)/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h \
        $(WebKit2)/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h
 
 webkit2_built_sources += \
@@ -1063,6 +1064,9 @@ webkit2_sources += \
        Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitFrame.cpp \
        Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitFrame.h \
        Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitFramePrivate.h \
+       Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp \
+       Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h \
+       Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorldPrivate.h \
        Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp \
        Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.h \
        Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebExtensionPrivate.h \
index 29078dd..e8be61f 100644 (file)
@@ -1062,6 +1062,7 @@ WebKitFrame
 webkit_frame_is_main_frame
 webkit_frame_get_uri
 webkit_frame_get_javascript_global_context
+webkit_frame_get_javascript_context_for_script_world
 
 <SUBSECTION Standard>
 WebKitFrameClass
@@ -1076,3 +1077,23 @@ WEBKIT_FRAME_GET_CLASS
 WebKitFramePrivate
 webkit_frame_get_type
 </SECTION>
+
+<SECTION>
+<FILE>WebKitScriptWorld</FILE>
+WebKitScriptWorld
+webkit_script_world_get_default
+webkit_script_world_new
+
+<SUBSECTION Standard>
+WebKitScriptWorldClass
+WEBKIT_TYPE_SCRIPT_WORLD
+WEBKIT_SCRIPT_WORLD
+WEBKIT_IS_SCRIPT_WORLD
+WEBKIT_SCRIPT_WORLD_CLASS
+WEBKIT_IS_SCRIPT_WORLD_CLASS
+WEBKIT_SCRIPT_WORLD_GET_CLASS
+
+<SUBSECTION Private>
+WebKitScriptWorldPrivate
+webkit_script_world_get_type
+</SECTION>
index 527cc93..91cb7aa 100644 (file)
@@ -100,6 +100,81 @@ static void testWebKitWebViewProcessCrashed(WebViewTest* test, gconstpointer)
     g_main_loop_run(test->m_mainLoop);
 }
 
+static void testWebExtensionWindowObjectCleared(WebViewTest* test, gconstpointer)
+{
+    test->loadHtml("<html><header></header><body></body></html>", 0);
+    test->waitUntilLoadFinished();
+
+    GOwnPtr<GError> error;
+    WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.echo('Foo');", &error.outPtr());
+    g_assert(javascriptResult);
+    g_assert(!error.get());
+    GOwnPtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "Foo");
+}
+
+static gboolean scriptDialogCallback(WebKitWebView*, WebKitScriptDialog* dialog, char** result)
+{
+    g_assert_cmpuint(webkit_script_dialog_get_dialog_type(dialog), ==, WEBKIT_SCRIPT_DIALOG_ALERT);
+    g_assert(!*result);
+    *result = g_strdup(webkit_script_dialog_get_message(dialog));
+    return TRUE;
+}
+
+static void runJavaScriptInIsolatedWorldFinishedCallback(GDBusProxy* proxy, GAsyncResult* result, WebViewTest* test)
+{
+    g_dbus_proxy_call_finish(proxy, result, 0);
+    g_main_loop_quit(test->m_mainLoop);
+}
+
+static void testWebExtensionIsolatedWorld(WebViewTest* test, gconstpointer)
+{
+    test->loadHtml("<html><header></header><body><div id='console'></div></body></html>", 0);
+    test->waitUntilLoadFinished();
+
+    GOwnPtr<char> result;
+    gulong scriptDialogID = g_signal_connect(test->m_webView, "script-dialog", G_CALLBACK(scriptDialogCallback), &result.outPtr());
+
+    static const char *mainWorldScript =
+        "top.foo = 'Foo';\n"
+        "document.getElementById('console').innerHTML = top.foo;\n"
+        "window.open = function () { alert('Main World'); }\n"
+        "document.open(1, 2, 3);";
+    test->runJavaScriptAndWaitUntilFinished(mainWorldScript, 0);
+    g_assert_cmpstr(result.get(), ==, "Main World");
+    result.clear();
+
+    WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementById('console').innerHTML", 0);
+    g_assert(javascriptResult);
+    GOwnPtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "Foo");
+
+    static const char *isolatedWorldScript =
+        "document.getElementById('console').innerHTML = top.foo;\n"
+        "window.open = function () { alert('Isolated World'); }\n"
+        "document.open(1, 2, 3);";
+    GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
+        "/org/webkit/gtk/WebExtensionTest" , "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
+    g_dbus_proxy_call(proxy.get(),
+        "RunJavaScriptInIsolatedWorld",
+        g_variant_new("(t&s)", webkit_web_view_get_page_id(test->m_webView), isolatedWorldScript),
+        G_DBUS_CALL_FLAGS_NONE,
+        -1, 0,
+        reinterpret_cast<GAsyncReadyCallback>(runJavaScriptInIsolatedWorldFinishedCallback),
+        test);
+    g_main_loop_run(test->m_mainLoop);
+    g_assert_cmpstr(result.get(), ==, "Isolated World");
+    result.clear();
+
+    // Check that 'top.foo' defined in main world is not visible in isolated world.
+    javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementById('console').innerHTML", 0);
+    g_assert(javascriptResult);
+    valueString.set(WebViewTest::javascriptResultToCString(javascriptResult));
+    g_assert_cmpstr(valueString.get(), ==, "undefined");
+
+    g_signal_handler_disconnect(test->m_webView, scriptDialogID);
+}
+
 void beforeAll()
 {
     webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
@@ -110,6 +185,8 @@ void beforeAll()
     WebViewTest::add("WebKitWebExtension", "dom-document-title", testWebExtensionGetTitle);
     WebViewTest::add("WebKitWebExtension", "document-loaded-signal", testDocumentLoadedSignal);
     WebViewTest::add("WebKitWebView", "web-process-crashed", testWebKitWebViewProcessCrashed);
+    WebViewTest::add("WebKitWebExtension", "window-object-cleared", testWebExtensionWindowObjectCleared);
+    WebViewTest::add("WebKitWebExtension", "isolated-world", testWebExtensionIsolatedWorld);
 }
 
 void afterAll()
index 692663e..acffb4f 100644 (file)
 
 #include "config.h"
 
+#include <JavaScriptCore/JSContextRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
 #include <gio/gio.h>
 #include <stdlib.h>
 #include <string.h>
-
 #include <webkit2/webkit-web-extension.h>
 #include <wtf/gobject/GOwnPtr.h>
+#include <wtf/gobject/GRefPtr.h>
 
 static const char introspectionXML[] =
     "<node>"
@@ -35,6 +37,10 @@ static const char introspectionXML[] =
     "  </method>"
     "  <method name='AbortProcess'>"
     "  </method>"
+    "  <method name='RunJavaScriptInIsolatedWorld'>"
+    "   <arg type='t' name='pageID' direction='in'/>"
+    "   <arg type='s' name='script' direction='in'/>"
+    "  </method>"
     "  <signal name='DocumentLoaded'/>"
     "  <signal name='URIChanged'>"
     "   <arg type='s' name='uri' direction='out'/>"
@@ -93,6 +99,41 @@ static void pageCreatedCallback(WebKitWebExtension*, WebKitWebPage* webPage, gpo
     g_signal_connect(webPage, "send-request", G_CALLBACK(sendRequestCallback), 0);
 }
 
+static JSValueRef echoCallback(JSContextRef jsContext, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef*)
+{
+    if (argumentCount <= 0)
+        return JSValueMakeUndefined(jsContext);
+
+    JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(jsContext, arguments[0], 0));
+    return JSValueMakeString(jsContext, string.get());
+}
+
+static void windowObjectCleared(WebKitScriptWorld* world, WebKitWebPage* page, WebKitFrame* frame, gpointer)
+{
+    JSGlobalContextRef jsContext = webkit_frame_get_javascript_context_for_script_world(frame, world);
+    g_assert(jsContext);
+    JSObjectRef globalObject = JSContextGetGlobalObject(jsContext);
+    g_assert(globalObject);
+
+    JSRetainPtr<JSStringRef> functionName(Adopt, JSStringCreateWithUTF8CString("echo"));
+    JSObjectRef function = JSObjectMakeFunctionWithCallback(jsContext, functionName.get(), echoCallback);
+    JSObjectSetProperty(jsContext, globalObject, functionName.get(), function, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0);
+}
+
+static WebKitWebPage* getWebPage(WebKitWebExtension* extension, uint64_t pageID, GDBusMethodInvocation* invocation)
+{
+    WebKitWebPage* page = webkit_web_extension_get_page(extension, pageID);
+    if (!page) {
+        g_dbus_method_invocation_return_error(
+            invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+            "Invalid page ID: %" G_GUINT64_FORMAT, pageID);
+        return 0;
+    }
+
+    g_assert_cmpuint(webkit_web_page_get_id(page), ==, pageID);
+    return page;
+}
+
 static void methodCallCallback(GDBusConnection* connection, const char* sender, const char* objectPath, const char* interfaceName, const char* methodName, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData)
 {
     if (g_strcmp0(interfaceName, "org.webkit.gtk.WebExtensionTest"))
@@ -101,20 +142,28 @@ static void methodCallCallback(GDBusConnection* connection, const char* sender,
     if (!g_strcmp0(methodName, "GetTitle")) {
         uint64_t pageID;
         g_variant_get(parameters, "(t)", &pageID);
-
-        WebKitWebExtension* extension = WEBKIT_WEB_EXTENSION(userData);
-        WebKitWebPage* page = webkit_web_extension_get_page(extension, pageID);
-        if (!page) {
-            g_dbus_method_invocation_return_error(
-                invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
-                "Invalid page ID: %" G_GUINT64_FORMAT, pageID);
+        WebKitWebPage* page = getWebPage(WEBKIT_WEB_EXTENSION(userData), pageID, invocation);
+        if (!page)
             return;
-        }
-        g_assert_cmpuint(webkit_web_page_get_id(page), ==, pageID);
 
         WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
         GOwnPtr<char> title(webkit_dom_document_get_title(document));
         g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", title.get()));
+    } else if (!g_strcmp0(methodName, "RunJavaScriptInIsolatedWorld")) {
+        uint64_t pageID;
+        const char* script;
+        g_variant_get(parameters, "(t&s)", &pageID, &script);
+        WebKitWebPage* page = getWebPage(WEBKIT_WEB_EXTENSION(userData), pageID, invocation);
+        if (!page)
+            return;
+
+        GRefPtr<WebKitScriptWorld> world = adoptGRef(webkit_script_world_new());
+        g_assert(webkit_script_world_get_default() != world.get());
+        WebKitFrame* frame = webkit_web_page_get_main_frame(page);
+        JSGlobalContextRef jsContext = webkit_frame_get_javascript_context_for_script_world(frame, world.get());
+        JSRetainPtr<JSStringRef> jsScript(Adopt, JSStringCreateWithUTF8CString(script));
+        JSEvaluateScript(jsContext, jsScript.get(), 0, 0, 0, 0);
+        g_dbus_method_invocation_return_value(invocation, 0);
     } else if (!g_strcmp0(methodName, "AbortProcess")) {
         abort();
     }
@@ -143,6 +192,7 @@ static void busAcquiredCallback(GDBusConnection* connection, const char* name, g
         g_warning("Failed to register object: %s\n", error->message);
 
     g_signal_connect(WEBKIT_WEB_EXTENSION(userData), "page-created", G_CALLBACK(pageCreatedCallback), connection);
+    g_signal_connect(webkit_script_world_get_default(), "window-object-cleared", G_CALLBACK(windowObjectCleared), 0);
 }
 
 extern "C" void webkit_web_extension_initialize(WebKitWebExtension* extension)
index a8b21f7..1691587 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "WebKitFramePrivate.h"
 #include "WebKitPrivate.h"
+#include "WebKitScriptWorldPrivate.h"
 #include <wtf/text/CString.h>
 
 using namespace WebKit;
@@ -101,3 +102,22 @@ JSGlobalContextRef webkit_frame_get_javascript_global_context(WebKitFrame* frame
 
     return frame->priv->webFrame->jsContext();
 }
+
+/**
+ * webkit_frame_get_javascript_context_for_script_world:
+ * @frame: a #WebKitFrame
+ * @world: a #WebKitScriptWorld
+ *
+ * Gets the JavaScript execution context of @frame for the given #WebKitScriptWorld.
+ *
+ * Returns: (transfer none): the JavaScript context of @frame for @world
+ *
+ * Since: 2.2
+ */
+JSGlobalContextRef webkit_frame_get_javascript_context_for_script_world(WebKitFrame* frame, WebKitScriptWorld* world)
+{
+    g_return_val_if_fail(WEBKIT_IS_FRAME(frame), 0);
+    g_return_val_if_fail(WEBKIT_IS_SCRIPT_WORLD(world), 0);
+
+    return frame->priv->webFrame->jsContextForWorld(webkitScriptWorldGetInjectedBundleScriptWorld(world));
+}
index e345c5c..5059300 100644 (file)
@@ -27,6 +27,7 @@
 #include <JavaScriptCore/JSBase.h>
 #include <glib-object.h>
 #include <webkit2/WebKitDefines.h>
+#include <webkit2/WebKitScriptWorld.h>
 
 G_BEGIN_DECLS
 
@@ -52,16 +53,20 @@ struct _WebKitFrameClass {
 };
 
 WEBKIT_API GType
-webkit_frame_get_type                      (void);
+webkit_frame_get_type                                (void);
 
 WEBKIT_API gboolean
-webkit_frame_is_main_frame                 (WebKitFrame *frame);
+webkit_frame_is_main_frame                           (WebKitFrame       *frame);
 
 WEBKIT_API const gchar *
-webkit_frame_get_uri                       (WebKitFrame *frame);
+webkit_frame_get_uri                                 (WebKitFrame       *frame);
 
 WEBKIT_API JSGlobalContextRef
-webkit_frame_get_javascript_global_context (WebKitFrame *frame);
+webkit_frame_get_javascript_global_context           (WebKitFrame       *frame);
+
+WEBKIT_API JSGlobalContextRef
+webkit_frame_get_javascript_context_for_script_world (WebKitFrame       *frame,
+                                                      WebKitScriptWorld *world);
 
 G_END_DECLS
 
diff --git a/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp b/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp
new file mode 100644 (file)
index 0000000..dc095e0
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2013 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
+ * License as published by the Free Software Foundation; either
+ * version 2,1 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 "WebKitScriptWorld.h"
+
+#include "WebKitMarshal.h"
+#include "WebKitPrivate.h"
+#include "WebKitScriptWorldPrivate.h"
+#include <wtf/HashMap.h>
+#include <wtf/NeverDestroyed.h>
+
+using namespace WebKit;
+using namespace WebCore;
+
+enum {
+    WINDOW_OBJECT_CLEARED,
+
+    LAST_SIGNAL
+};
+
+typedef HashMap<InjectedBundleScriptWorld*, WebKitScriptWorld*> ScriptWorldMap;
+
+static ScriptWorldMap& scriptWorlds()
+{
+    static NeverDestroyed<ScriptWorldMap> map;
+    return map;
+}
+
+struct _WebKitScriptWorldPrivate {
+    ~_WebKitScriptWorldPrivate()
+    {
+        ASSERT(scriptWorlds().contains(scriptWorld.get()));
+        scriptWorlds().remove(scriptWorld.get());
+    }
+
+    RefPtr<InjectedBundleScriptWorld> scriptWorld;
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+WEBKIT_DEFINE_TYPE(WebKitScriptWorld, webkit_script_world, G_TYPE_OBJECT)
+
+static void webkit_script_world_class_init(WebKitScriptWorldClass* klass)
+{
+    /**
+     * WebKitScriptWorld::window-object-cleared:
+     * @world: the #WebKitScriptWorld on which the signal is emitted
+     * @page: a #WebKitWebPage
+     * @frame: the #WebKitFrame  to which @world belongs
+     *
+     * Emitted when the JavaScript window object in a #WebKitScriptWorld has been
+     * cleared. This is the preferred place to set custom properties on the window
+     * object using the JavaScriptCore API. You can get the window object of @frame
+     * from the JavaScript execution context of @world that is returned by
+     * webkit_frame_get_javascript_context_for_script_world().
+     *
+     * Since: 2.2
+     */
+    signals[WINDOW_OBJECT_CLEARED] = g_signal_new(
+        "window-object-cleared",
+        G_TYPE_FROM_CLASS(klass),
+        G_SIGNAL_RUN_LAST,
+        0, 0, 0,
+        webkit_marshal_VOID__OBJECT_OBJECT,
+        G_TYPE_NONE, 2,
+        WEBKIT_TYPE_WEB_PAGE,
+        WEBKIT_TYPE_FRAME);
+}
+
+WebKitScriptWorld* webkitScriptWorldGet(InjectedBundleScriptWorld* scriptWorld)
+{
+    return scriptWorlds().get(scriptWorld);
+}
+
+InjectedBundleScriptWorld* webkitScriptWorldGetInjectedBundleScriptWorld(WebKitScriptWorld* world)
+{
+    return world->priv->scriptWorld.get();
+}
+
+void webkitScriptWorldWindowObjectCleared(WebKitScriptWorld* world, WebKitWebPage* page, WebKitFrame* frame)
+{
+    g_signal_emit(world, signals[WINDOW_OBJECT_CLEARED], 0, page, frame);
+}
+
+static WebKitScriptWorld* webkitScriptWorldCreate(PassRefPtr<InjectedBundleScriptWorld> scriptWorld)
+{
+    WebKitScriptWorld* world = WEBKIT_SCRIPT_WORLD(g_object_new(WEBKIT_TYPE_SCRIPT_WORLD, NULL));
+    world->priv->scriptWorld = scriptWorld;
+
+    ASSERT(!scriptWorlds().contains(world->priv->scriptWorld.get()));
+    scriptWorlds().add(world->priv->scriptWorld.get(), world);
+
+    return world;
+}
+
+static gpointer createDefaultScriptWorld(gpointer)
+{
+    return webkitScriptWorldCreate(InjectedBundleScriptWorld::normalWorld());
+}
+
+/**
+ * webkit_script_world_get_default:
+ *
+ * Get the default #WebKitScriptWorld. This is the normal script world
+ * where all scripts are executed by default.
+ * You can get the JavaScript execution context of a #WebKitScriptWorld
+ * for a given #WebKitFrame with webkit_frame_get_javascript_context_for_script_world().
+ *
+ * Returns: (transfer none): the default #WebKitScriptWorld
+ *
+ * Since: 2.2
+ */
+WebKitScriptWorld* webkit_script_world_get_default(void)
+{
+    static GOnce onceInit = G_ONCE_INIT;
+    return WEBKIT_SCRIPT_WORLD(g_once(&onceInit, createDefaultScriptWorld, 0));
+}
+
+/**
+ * webkit_script_world_new:
+ *
+ * Creates a new isolated #WebKitScriptWorld. Scripts executed in
+ * isolated worlds have access to the DOM but not to other variable
+ * or functions created by the page.
+ * You can get the JavaScript execution context of a #WebKitScriptWorld
+ * for a given #WebKitFrame with webkit_frame_get_javascript_context_for_script_world().
+ *
+ * Returns: (transfer full): a new isolated #WebKitScriptWorld
+ *
+ * Since: 2.2
+ */
+WebKitScriptWorld* webkit_script_world_new(void)
+{
+    return webkitScriptWorldCreate(InjectedBundleScriptWorld::create());
+}
diff --git a/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h b/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h
new file mode 100644 (file)
index 0000000..cb0673e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 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
+ * License as published by the Free Software Foundation; either
+ * version 2,1 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_WEB_EXTENSION_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#error "Only <webkit2/webkit-web-extension.h> can be included directly."
+#endif
+
+#ifndef WebKitScriptWorld_h
+#define WebKitScriptWorld_h
+
+#include <glib-object.h>
+#include <webkit2/WebKitDefines.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_SCRIPT_WORLD            (webkit_script_world_get_type())
+#define WEBKIT_SCRIPT_WORLD(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_SCRIPT_WORLD, WebKitScriptWorld))
+#define WEBKIT_IS_SCRIPT_WORLD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_SCRIPT_WORLD))
+#define WEBKIT_SCRIPT_WORLD_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_SCRIPT_WORLD, WebKitScriptWorldClass))
+#define WEBKIT_IS_SCRIPT_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_SCRIPT_WORLD))
+#define WEBKIT_SCRIPT_WORLD_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_SCRIPT_WORLD, WebKitScriptWorldClass))
+
+typedef struct _WebKitScriptWorld        WebKitScriptWorld;
+typedef struct _WebKitScriptWorldClass   WebKitScriptWorldClass;
+typedef struct _WebKitScriptWorldPrivate WebKitScriptWorldPrivate;
+
+struct _WebKitScriptWorld {
+    GObject parent;
+
+    WebKitScriptWorldPrivate *priv;
+};
+
+struct _WebKitScriptWorldClass {
+    GObjectClass parent_class;
+
+    void (*_webkit_reserved0) (void);
+    void (*_webkit_reserved1) (void);
+    void (*_webkit_reserved2) (void);
+    void (*_webkit_reserved3) (void);
+};
+
+WEBKIT_API GType
+webkit_script_world_get_type    (void);
+
+WEBKIT_API WebKitScriptWorld *
+webkit_script_world_get_default (void);
+
+WEBKIT_API WebKitScriptWorld *
+webkit_script_world_new         (void);
+
+G_END_DECLS
+
+#endif
diff --git a/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorldPrivate.h b/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorldPrivate.h
new file mode 100644 (file)
index 0000000..3f3c3ff
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef WebKitScriptWorldPrivate_h
+#define WebKitScriptWorldPrivate_h
+
+#include "InjectedBundleScriptWorld.h"
+#include "WebKitFrame.h"
+#include "WebKitScriptWorld.h"
+#include "WebKitWebPage.h"
+
+WebKitScriptWorld* webkitScriptWorldGet(WebKit::InjectedBundleScriptWorld*);
+void webkitScriptWorldWindowObjectCleared(WebKitScriptWorld*, WebKitWebPage*, WebKitFrame*);
+WebKit::InjectedBundleScriptWorld* webkitScriptWorldGetInjectedBundleScriptWorld(WebKitScriptWorld*);
+
+#endif // WebKitScriptWorldPrivate_h
index dbec2c3..e998a23 100644 (file)
@@ -30,6 +30,7 @@
 #include "WebKitFramePrivate.h"
 #include "WebKitMarshal.h"
 #include "WebKitPrivate.h"
+#include "WebKitScriptWorldPrivate.h"
 #include "WebKitURIRequestPrivate.h"
 #include "WebKitURIResponsePrivate.h"
 #include "WebKitWebPagePrivate.h"
@@ -143,6 +144,12 @@ static void willDestroyFrame(WKBundlePageRef, WKBundleFrameRef frame, const void
     webFrameMap().remove(toImpl(frame));
 }
 
+static void didClearWindowObjectForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKBundleScriptWorldRef wkWorld, const void* clientInfo)
+{
+    if (WebKitScriptWorld* world = webkitScriptWorldGet(toImpl(wkWorld)))
+        webkitScriptWorldWindowObjectCleared(world, WEBKIT_WEB_PAGE(clientInfo), webkitFrameGetOrCreate(toImpl(frame)));
+}
+
 static void didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, bool pageLoadIsProvisional, const void*)
 {
     ImmutableDictionary::MapType message;
@@ -319,7 +326,7 @@ WebKitWebPage* webkitWebPageCreate(WebPage* webPage)
         0, // didRemoveFrameFromHierarchy
         0, // didDisplayInsecureContentForFrame
         0, // didRunInsecureContentForFrame
-        0, // didClearWindowObjectForFrame
+        didClearWindowObjectForFrame,
         0, // didCancelClientRedirectForFrame
         0, // willPerformClientRedirectForFrame
         0, // didHandleOnloadEventsForFrame
index 1de975a..cf22e09 100644 (file)
@@ -23,6 +23,7 @@
 #define __WEBKIT_WEB_EXTENSION_H_INSIDE__
 
 #include <webkit2/WebKitFrame.h>
+#include <webkit2/WebKitScriptWorld.h>
 #include <webkit2/WebKitURIRequest.h>
 #include <webkit2/WebKitURIResponse.h>
 #include <webkit2/WebKitWebExtension.h>