[GTK] Add methods to add a user style sheet to the WebKit2 GTK+ API
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Apr 2013 23:06:10 +0000 (23:06 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Apr 2013 23:06:10 +0000 (23:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=99081

Reviewed by Carlos Garcia Campos, Gustavo Noronha Silva, and Benjamin Poulain.

Add methods to WebKitWebViewGroup to add and remove user style sheets.
This allows clients to inject style sheets into pages with a set of
rules for when those style sheets apply.

* UIProcess/API/gtk/WebKitWebViewGroup.cpp:
(toImmutableArray): Added this helper which converts the GList* parameters into
ImmutableArrays for use with the WebKit2 internal API.
(webkit_web_view_group_add_user_style_sheet): Added new API for adding a style sheet.
(webkit_web_view_group_remove_all_user_style_sheets): Add new API for clearing out all style sheets.
* UIProcess/API/gtk/WebKitWebViewGroup.h: Added new method declarations.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Added new API to the documentation.
* UIProcess/API/gtk/tests/TestWebKitWebViewGroup.cpp: Added a test for the new API.
(isStyleSheetInjectedForURLAtPath): Function to check whether the style sheet has been injected for a given URL.
(fillURLListFromPaths): Helper which converts paths passed via varargs into a whitelist or blacklist.
(removeOldInjectedStyleSheetsAndResetLists): Function to start afresh.
(testWebViewGroupInjectedStyleSheet): The actual test.
(serverCallback): Server callback for use with the test. We cannot use loadHTML or
loadAlternateHTML, because that checks the whitelist and blacklist against about:blank.
(beforeAll): Initialize the server and new test.
(afterAll): Clean up the server.

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/gtk/WebKitWebViewGroup.cpp
Source/WebKit2/UIProcess/API/gtk/WebKitWebViewGroup.h
Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt
Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebViewGroup.cpp

index a47018f..b4f3269 100644 (file)
@@ -1,3 +1,31 @@
+2013-04-26  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Add methods to add a user style sheet to the WebKit2 GTK+ API
+        https://bugs.webkit.org/show_bug.cgi?id=99081
+
+        Reviewed by Carlos Garcia Campos, Gustavo Noronha Silva, and Benjamin Poulain.
+
+        Add methods to WebKitWebViewGroup to add and remove user style sheets.
+        This allows clients to inject style sheets into pages with a set of
+        rules for when those style sheets apply.
+
+        * UIProcess/API/gtk/WebKitWebViewGroup.cpp:
+        (toImmutableArray): Added this helper which converts the GList* parameters into
+        ImmutableArrays for use with the WebKit2 internal API.
+        (webkit_web_view_group_add_user_style_sheet): Added new API for adding a style sheet.
+        (webkit_web_view_group_remove_all_user_style_sheets): Add new API for clearing out all style sheets.
+        * UIProcess/API/gtk/WebKitWebViewGroup.h: Added new method declarations.
+        * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Added new API to the documentation.
+        * UIProcess/API/gtk/tests/TestWebKitWebViewGroup.cpp: Added a test for the new API.
+        (isStyleSheetInjectedForURLAtPath): Function to check whether the style sheet has been injected for a given URL.
+        (fillURLListFromPaths): Helper which converts paths passed via varargs into a whitelist or blacklist.
+        (removeOldInjectedStyleSheetsAndResetLists): Function to start afresh.
+        (testWebViewGroupInjectedStyleSheet): The actual test.
+        (serverCallback): Server callback for use with the test. We cannot use loadHTML or
+        loadAlternateHTML, because that checks the whitelist and blacklist against about:blank.
+        (beforeAll): Initialize the server and new test.
+        (afterAll): Clean up the server.
+
 2013-04-26  Simon Cooper  <scooper@apple.com>
 
         Permit ~/Library or ~/Library/Preferences to be symlinks
index ac1fdae..998c5c0 100644 (file)
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "WebKitWebViewGroup.h"
 
+#include "ImmutableArray.h"
 #include "WebKitPrivate.h"
 #include "WebKitSettingsPrivate.h"
 #include "WebKitWebViewGroupPrivate.h"
@@ -221,3 +222,66 @@ void webkit_web_view_group_set_settings(WebKitWebViewGroup* group, WebKitSetting
     webkitWebViewGroupAttachSettingsToPageGroup(group);
     g_object_notify(G_OBJECT(group), "settings");
 }
+
+COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_INJECTED_CONTENT_FRAMES_ALL, WebCore::InjectInAllFrames);
+COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_INJECTED_CONTENT_FRAMES_TOP_ONLY, WebCore::InjectInTopFrameOnly);
+
+static PassRefPtr<ImmutableArray> toImmutableArray(const char* const* list)
+{
+    if (!list)
+        return 0;
+
+    Vector<RefPtr<APIObject> > entries;
+    while (*list) {
+        entries.append(WebString::createFromUTF8String(*list));
+        list++;
+    }
+    return ImmutableArray::adopt(entries);
+}
+
+/**
+ * webkit_web_view_group_add_user_style_sheet:
+ * @group: a #WebKitWebViewGroup
+ * @source: the source of the style_sheet to inject
+ * @base_uri: (allow-none): the base URI to use when processing the style_sheet contents or %NULL for about:blank
+ * @whitelist: (array zero-terminated=1) (allow-none): a whitelist of URI patterns or %NULL
+ * @blacklist: (array zero-terminated=1) (allow-none): a blacklist of URI patterns or %NULL
+ * @injected_frames: a #WebKitInjectedContentFrames describing to which frames the style_sheet should apply
+ *
+ * Inject an external style sheet into pages. It is possible to only apply the style sheet
+ * to some URIs by passing non-null values for @whitelist or @blacklist. Passing a %NULL
+ * whitelist implies that all URIs are on the whitelist. The style sheet is applied if a URI matches
+ * the whitelist and not the blacklist. URI patterns must be of the form [protocol]://[host]/[path]
+ * where the host and path components can contain the wildcard character ('*') to represent zero
+ * or more other characters.
+ */
+void webkit_web_view_group_add_user_style_sheet(WebKitWebViewGroup* group, const char* source, const char* baseURI, const char* const* whitelist, const char* const* blacklist, WebKitInjectedContentFrames injectedFrames)
+{
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW_GROUP(group));
+    g_return_if_fail(source);
+
+    RefPtr<ImmutableArray> webWhitelist = toImmutableArray(whitelist);
+    RefPtr<ImmutableArray> webBlacklist = toImmutableArray(blacklist);
+
+    // We always use UserStyleUserLevel to match the behavior of WKPageGroupAddUserStyleSheet.
+    group->priv->pageGroup->addUserStyleSheet(
+        String::fromUTF8(source),
+        String::fromUTF8(baseURI),
+        webWhitelist.get(),
+        webBlacklist.get(),
+        static_cast<WebCore::UserContentInjectedFrames>(injectedFrames),
+        WebCore::UserStyleUserLevel);
+}
+
+/**
+ * webkit_web_view_group_remove_all_user_style_sheets:
+ * @group: a #WebKitWebViewGroup
+ *
+ * Remove all style sheets previously injected into this #WebKitWebViewGroup 
+ * via webkit_web_view_group_add_user_style_sheet().
+ */
+void webkit_web_view_group_remove_all_user_style_sheets(WebKitWebViewGroup* group)
+{
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW_GROUP(group));
+    group->priv->pageGroup->removeAllUserStyleSheets();
+}
index a488ae7..7752365 100644 (file)
@@ -51,21 +51,44 @@ struct _WebKitWebViewGroupClass {
     GObjectClass parent_class;
 };
 
+/**
+ * WebKitInjectedContentFrames:
+ * @WEBKIT_INJECTED_CONTENT_FRAMES_ALL: Content will be injected into all frames.
+ * @WEBKIT_INJECTED_CONTENT_FRAMES_TOP_ONLY: Content will only be injected into the main frame.
+ *
+ * Enum values used for determining into which frames content is injected.
+ */
+typedef enum {
+    WEBKIT_INJECTED_CONTENT_FRAMES_ALL,
+    WEBKIT_INJECTED_CONTENT_FRAMES_TOP_ONLY,
+} WebKitInjectedContentFrames;
+
 WEBKIT_API GType
-webkit_web_view_group_get_type     (void);
+webkit_web_view_group_get_type                     (void);
 
 WEBKIT_API WebKitWebViewGroup *
-webkit_web_view_group_new          (const gchar        *name);
+webkit_web_view_group_new                          (const gchar                 *name);
 
 WEBKIT_API const gchar *
-webkit_web_view_group_get_name     (WebKitWebViewGroup *group);
+webkit_web_view_group_get_name                     (WebKitWebViewGroup          *group);
 
 WEBKIT_API WebKitSettings *
-webkit_web_view_group_get_settings (WebKitWebViewGroup *group);
+webkit_web_view_group_get_settings                 (WebKitWebViewGroup          *group);
+
+WEBKIT_API void
+webkit_web_view_group_set_settings                 (WebKitWebViewGroup          *group,
+                                                    WebKitSettings              *settings);
+
+WEBKIT_API void
+webkit_web_view_group_add_user_style_sheet         (WebKitWebViewGroup           *group,
+                                                    const gchar                  *source,
+                                                    const gchar                  *base_uri,
+                                                    const gchar * const          *whitelist,
+                                                    const gchar * const          *blacklist,
+                                                    WebKitInjectedContentFrames   injected_frames);
 
 WEBKIT_API void
-webkit_web_view_group_set_settings (WebKitWebViewGroup *group,
-                                    WebKitSettings     *settings);
+webkit_web_view_group_remove_all_user_style_sheets (WebKitWebViewGroup          *group);
 
 G_END_DECLS
 
index afe8028..9f26261 100644 (file)
@@ -945,10 +945,13 @@ webkit_security_manager_get_type
 <SECTION>
 <FILE>WebKitWebViewGroup</FILE>
 WebKitWebViewGroup
+WebKitInjectedContentFrames
 webkit_web_view_group_new
 webkit_web_view_group_get_name
 webkit_web_view_group_get_settings
 webkit_web_view_group_set_settings
+webkit_web_view_group_add_user_style_sheet
+webkit_web_view_group_remove_all_user_style_sheets
 
 <SUBSECTION Standard>
 WebKitWebViewGroupClass
index cbc1d23..026c5c5 100644 (file)
 
 #include "config.h"
 
+#include "WebKitTestServer.h"
 #include "WebViewTest.h"
+#include <cstdarg>
 #include <gtk/gtk.h>
 #include <webkit2/webkit2.h>
 #include <wtf/gobject/GRefPtr.h>
 
+static WebKitTestServer* kServer;
+
+// These are all here so that they can be changed easily, if necessary.
+static const char* kStyleSheetHTML = "<html><div id=\"styledElement\">Sweet stylez!</div></html>";
+static const char* kInjectedStyleSheet = "#styledElement { font-weight: bold; }";
+static const char* kStyleSheetTestScript = "getComputedStyle(document.getElementById('styledElement'))['font-weight']";
+static const char* kStyleSheetTestScriptResult = "bold";
+
 static void testWebViewGroupDefault(Test* test, gconstpointer)
 {
     // Default group is shared by all WebViews by default.
@@ -88,15 +98,109 @@ static void testWebViewGroupSettings(Test* test, gconstpointer)
     g_assert(webkit_web_view_group_get_settings(webkit_web_view_get_group(webView1.get())) == webView2Settings);
 }
 
+static bool isStyleSheetInjectedForURLAtPath(WebViewTest* test, const char* path)
+{
+    test->loadURI(kServer->getURIForPath(path).data());
+    test->waitUntilLoadFinished();
+
+    GOwnPtr<GError> error;
+    WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished(kStyleSheetTestScript, &error.outPtr());
+    g_assert(javascriptResult);
+    g_assert(!error.get());
+
+    GOwnPtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult));
+    return !g_strcmp0(resultString.get(), kStyleSheetTestScriptResult);
+}
+
+static void fillURLListFromPaths(char** list, const char* path, ...)
+{
+    va_list argumentList;
+    va_start(argumentList, path);
+
+    int i = 0;
+    while (path) {
+        // FIXME: We must use a wildcard for the host here until http://wkbug.com/112476 is fixed.
+        // Until that time patterns with port numbers in them will not properly match URLs with port numbers.
+        list[i++] = g_strdup_printf("http://*/%s*", path);
+        path = va_arg(argumentList, const char*);
+    }
+}
+
+static void removeOldInjectedStyleSheetsAndResetLists(WebKitWebViewGroup* group, char** whitelist, char** blacklist)
+{
+    webkit_web_view_group_remove_all_user_style_sheets(group);
+
+    while (*whitelist) {
+        g_free(*whitelist);
+        *whitelist = 0;
+        whitelist++;
+    }
+
+    while (*blacklist) {
+        g_free(*blacklist);
+        *blacklist = 0;
+        blacklist++;
+    }
+}
+
+static void testWebViewGroupInjectedStyleSheet(WebViewTest* test, gconstpointer)
+{
+    WebKitWebViewGroup* group = webkit_web_view_get_group(test->m_webView);
+    char* whitelist[3] = { 0, 0, 0 };
+    char* blacklist[3] = { 0, 0, 0 };
+
+    removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
+
+    // Without a whitelist or a blacklist all URLs should have the injected style sheet.
+    static const char* randomPath = "somerandompath";
+    g_assert(!isStyleSheetInjectedForURLAtPath(test, randomPath));
+    webkit_web_view_group_add_user_style_sheet(group, kInjectedStyleSheet, 0, 0, 0, WEBKIT_INJECTED_CONTENT_FRAMES_ALL);
+    g_assert(isStyleSheetInjectedForURLAtPath(test, randomPath));
+
+    removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
+
+    fillURLListFromPaths(blacklist, randomPath, 0);
+    webkit_web_view_group_add_user_style_sheet(group, kInjectedStyleSheet, 0, 0, blacklist, WEBKIT_INJECTED_CONTENT_FRAMES_ALL);
+    g_assert(!isStyleSheetInjectedForURLAtPath(test, randomPath));
+    g_assert(isStyleSheetInjectedForURLAtPath(test, "someotherrandompath"));
+
+    removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
+
+    static const char* inTheWhiteList = "inthewhitelist";
+    static const char* notInWhitelist = "notinthewhitelist";
+    static const char* inTheWhiteListAndBlackList = "inthewhitelistandblacklist";
+
+    fillURLListFromPaths(whitelist, inTheWhiteList, inTheWhiteListAndBlackList, 0);
+    fillURLListFromPaths(blacklist, inTheWhiteListAndBlackList, 0);
+    webkit_web_view_group_add_user_style_sheet(group, kInjectedStyleSheet, 0, whitelist, blacklist, WEBKIT_INJECTED_CONTENT_FRAMES_ALL);
+    g_assert(isStyleSheetInjectedForURLAtPath(test, inTheWhiteList));
+    g_assert(!isStyleSheetInjectedForURLAtPath(test, inTheWhiteListAndBlackList));
+    g_assert(!isStyleSheetInjectedForURLAtPath(test, notInWhitelist));
+
+    // It's important to clean up the environment before other tests.
+    removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
+}
+
+static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
+{
+    soup_message_set_status(message, SOUP_STATUS_OK);
+    soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, kStyleSheetHTML, strlen(kStyleSheetHTML));
+    soup_message_body_complete(message->response_body);
+}
+
 void beforeAll()
 {
+    kServer = new WebKitTestServer();
+    kServer->run(serverCallback);
+
     Test::add("WebKitWebViewGroup", "default-group", testWebViewGroupDefault);
     Test::add("WebKitWebViewGroup", "new-group", testWebViewGroupNewGroup);
     Test::add("WebKitWebView", "new-with-group", testWebViewNewWithGroup);
     Test::add("WebKitWebViewGroup", "settings", testWebViewGroupSettings);
+    WebViewTest::add("WebKitWebViewGroup", "injected-style-sheet", testWebViewGroupInjectedStyleSheet);
 }
 
 void afterAll()
 {
-
+    delete kServer;
 }