diff --git a/midori/main.c b/midori/main.c index 8b722977..e51838b1 100644 --- a/midori/main.c +++ b/midori/main.c @@ -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 (""); diff --git a/midori/midori-websettings.c b/midori/midori-websettings.c index b6794a55..285652d8 100644 --- a/midori/midori-websettings.c +++ b/midori/midori-websettings.c @@ -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); + + 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_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); - + 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); + } } } -