]> spindle.queued.net Git - midori/commitdiff
Faster Base64-concatenating CSS and stylesheet URI support
authorChristian Dywan <christian@twotoasts.de>
Tue, 8 Nov 2011 21:48:39 +0000 (22:48 +0100)
committerChristian Dywan <christian@twotoasts.de>
Tue, 8 Nov 2011 21:48:39 +0000 (22:48 +0100)
It is important to retain user-stylesheet-uri separate from
the value set at runtime and restore it to the config file.

Fixes: https://bugs.launchpad.net/midori/+bug/883879
midori/main.c
midori/midori-websettings.c

index 8b722977ffea0fb662a9ef876a7ddc405be0930e..e51838b17714934ff3a278cf7485174fe6ac843b 100644 (file)
@@ -202,6 +202,19 @@ settings_save_to_file (MidoriWebSettings* settings,
         {
             gchar* string;
             const gchar* def_string = G_PARAM_SPEC_STRING (pspec)->default_value;
+            if (!strcmp (property, "user-stylesheet-uri"))
+            {
+                const gchar* user_stylesheet_uri = g_object_get_data (G_OBJECT (settings), property);
+                if (user_stylesheet_uri)
+                {
+                    g_key_file_set_string (key_file, "settings", property,
+                        user_stylesheet_uri);
+                }
+                else
+                    g_key_file_remove_key (key_file, "settings", property, NULL);
+                continue;
+            }
+
             g_object_get (settings, property, &string, NULL);
             if (!string)
                 string = g_strdup ("");
index b6794a5577e03a1a3eca8f073b52d124e2b34a5f..285652d89423fc2bb3cc6a3d677211889850a325 100644 (file)
@@ -91,6 +91,7 @@ struct _MidoriWebSettings
     gboolean enforce_font_family;
     gboolean flash_window_on_bg_tabs;
     gchar* user_stylesheet_uri;
+    gchar* user_stylesheet_uri_cached;
     GHashTable* user_stylesheets;
 };
 
@@ -1122,7 +1123,7 @@ midori_web_settings_init (MidoriWebSettings* web_settings)
     web_settings->http_proxy = NULL;
     web_settings->open_popups_in_tabs = TRUE;
     web_settings->kinetic_scrolling = TRUE;
-    web_settings->user_stylesheet_uri = NULL;
+    web_settings->user_stylesheet_uri = web_settings->user_stylesheet_uri_cached = NULL;
     web_settings->user_stylesheets = NULL;
 
     g_signal_connect (web_settings, "notify::default-encoding",
@@ -1147,6 +1148,7 @@ midori_web_settings_finalize (GObject* object)
     katze_assign (web_settings->http_proxy, NULL);
     katze_assign (web_settings->ident_string, NULL);
     katze_assign (web_settings->user_stylesheet_uri, NULL);
+    katze_assign (web_settings->user_stylesheet_uri_cached, NULL);
     if (web_settings->user_stylesheets != NULL)
         g_hash_table_destroy (web_settings->user_stylesheets);
 
@@ -1273,6 +1275,14 @@ generate_ident_string (MidoriWebSettings* web_settings,
     }
 }
 
+static void
+midori_web_settings_process_stylesheets (MidoriWebSettings* settings,
+                                         gint               delta_len);
+
+static void
+base64_space_pad (gchar* base64,
+                  guint  len);
+
 static void
 midori_web_settings_set_property (GObject*      object,
                                   guint         prop_id,
@@ -1535,15 +1545,25 @@ midori_web_settings_set_property (GObject*      object,
         web_settings->flash_window_on_bg_tabs = g_value_get_boolean (value);
         break;
     case PROP_USER_STYLESHEET_URI:
-        if ((web_settings->user_stylesheet_uri = g_value_dup_string (value)))
         {
-            gchar* css = g_strdup_printf ("@import url(\"%s\"\n);",
-                                          web_settings->user_stylesheet_uri);
-            midori_web_settings_add_style (web_settings, "user-stylesheet-uri", css);
-            g_free (css);
+            gint old_len = web_settings->user_stylesheet_uri_cached
+                ? strlen (web_settings->user_stylesheet_uri_cached) : 0;
+            gint new_len = 0;
+            if ((web_settings->user_stylesheet_uri = g_value_dup_string (value)))
+            {
+                gchar* import = g_strdup_printf ("@import url(\"%s\");",
+                    web_settings->user_stylesheet_uri);
+                gchar* encoded = g_base64_encode ((const guchar*)import, strlen (import));
+                new_len = strlen (encoded);
+                base64_space_pad (encoded, new_len);
+                g_free (import);
+                katze_assign (web_settings->user_stylesheet_uri_cached, encoded);
+            }
+            /* Make original user-stylesheet-uri available to main.c */
+            g_object_set_data (G_OBJECT (web_settings), "user-stylesheet-uri",
+                web_settings->user_stylesheet_uri);
+            midori_web_settings_process_stylesheets (web_settings, new_len - old_len);
         }
-        else
-            midori_web_settings_remove_style (web_settings, "user-stylesheet-uri");
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1807,7 +1827,8 @@ midori_web_settings_get_property (GObject*    object,
         g_value_set_boolean (value, web_settings->flash_window_on_bg_tabs);
         break;
     case PROP_USER_STYLESHEET_URI:
-        g_value_set_string (value, web_settings->user_stylesheet_uri);
+        g_value_take_string (value, katze_object_get_string (web_settings,
+            "WebKitWebSettings::user-stylesheet-uri"));
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1834,29 +1855,54 @@ midori_web_settings_new (void)
 }
 
 static void
-midori_web_settings_process_stylesheets (MidoriWebSettings* settings)
+midori_web_settings_process_stylesheets (MidoriWebSettings* settings,
+                                         gint               delta_len)
 {
     GHashTableIter it;
-    GString* css = g_string_new ("");
-    gchar* base64;
+    GString* css;
     gchar* encoded;
-    gpointer key;
     gpointer value;
+    static guint length = 0;
 
-    g_hash_table_iter_init (&it, settings->user_stylesheets);
-    while (g_hash_table_iter_next (&it, &key, &value))
-        g_string_append_printf (css, "%s\n", (const gchar*) value);
+    g_return_if_fail ((gint)length >= -delta_len);
 
-    /* data: uri prefix from Source/WebCore/page/Page.cpp:700 in WebKit */
-    encoded = g_base64_encode ((guchar*)css->str, css->len);
-    base64 = g_strdup_printf ("data:text/css;charset=utf-8;base64,%s", encoded);
-    g_object_set (settings, "WebKitWebSettings::user-stylesheet-uri", base64, NULL);
+    length += delta_len;
+
+    /* Precalculate size to avoid re-allocations */
+    css = g_string_sized_new (length);
+
+    if (settings->user_stylesheet_uri_cached != NULL)
+        g_string_append (css, settings->user_stylesheet_uri_cached);
+
+    if (settings->user_stylesheets != NULL)
+    {
+        g_hash_table_iter_init (&it, settings->user_stylesheets);
+        while (g_hash_table_iter_next (&it, NULL, &value))
+            g_string_append (css, (gchar*)value);
+    }
 
+    /* data: uri prefix from Source/WebCore/page/Page.cpp:700 in WebKit */
+    encoded = g_strconcat ("data:text/css;charset=utf-8;base64,", css->str, NULL);
+    g_object_set (G_OBJECT (settings), "WebKitWebSettings::user-stylesheet-uri", encoded, NULL);
     g_free (encoded);
-    g_free (base64);
     g_string_free (css, TRUE);
 }
 
+static void
+base64_space_pad (gchar* base64,
+                  guint  len)
+{
+    /* Replace '=' padding at the end with encoded spaces
+       so WebKit will accept concatenations to this string */
+    if (len > 2 && base64[len - 2] == '=')
+    {
+        base64[len - 3] += 2;
+        base64[len - 2] = 'A';
+    }
+    if (len > 1 && base64[len - 1] == '=')
+        base64[len - 1] = 'g';
+}
+
 /**
  * midori_web_settings_add_style:
  * @rule_id: a static string identifier
@@ -1871,15 +1917,24 @@ midori_web_settings_add_style (MidoriWebSettings* settings,
                                const gchar*       rule_id,
                                const gchar*       style)
 {
+    gchar* base64;
+    guint len;
+
     g_return_if_fail (MIDORI_IS_WEB_SETTINGS (settings));
     g_return_if_fail (rule_id != NULL);
     g_return_if_fail (style != NULL);
 
+    len = strlen (style);
+    base64 = g_base64_encode ((const guchar*)style, len);
+    len = ((len + 2) / 3) * 4;
+    base64_space_pad (base64, len);
+
     if (settings->user_stylesheets == NULL)
         settings->user_stylesheets = g_hash_table_new_full (g_str_hash, NULL,
-        NULL, g_free);
-    g_hash_table_insert (settings->user_stylesheets, (gchar*)rule_id, g_strdup (style));
-    midori_web_settings_process_stylesheets (settings);
+                                                            NULL, g_free);
+
+    g_hash_table_insert (settings->user_stylesheets, (gchar*)rule_id, base64);
+    midori_web_settings_process_stylesheets (settings, len);
 }
 
 /**
@@ -1894,13 +1949,18 @@ void
 midori_web_settings_remove_style (MidoriWebSettings* settings,
                                   const gchar*       rule_id)
 {
+    gchar* str;
+
     g_return_if_fail (MIDORI_IS_WEB_SETTINGS (settings));
     g_return_if_fail (rule_id != NULL);
 
     if (settings->user_stylesheets != NULL)
     {
-        g_hash_table_remove (settings->user_stylesheets, rule_id);
-        midori_web_settings_process_stylesheets (settings);
+        if ((str = g_hash_table_lookup (settings->user_stylesheets, rule_id)))
+        {
+            guint len = strlen (str);
+            g_hash_table_remove (settings->user_stylesheets, rule_id);
+            midori_web_settings_process_stylesheets (settings, -len);
+        }
     }
 }
-