Fri, 11 Apr 2014 22:53:23 +0200
PurpleImage: better reference management
--- a/libpurple/image-store.c Fri Apr 11 22:20:09 2014 +0200 +++ b/libpurple/image-store.c Fri Apr 11 22:53:23 2014 +0200 @@ -23,6 +23,7 @@ #include "eventloop.h" #include "glibcompat.h" +#include "util.h" #define TEMP_IMAGE_TIMEOUT 5 @@ -157,6 +158,31 @@ return g_hash_table_lookup(id_to_image, GINT_TO_POINTER(id)); } +PurpleImage * +purple_image_store_get_from_uri(const gchar *uri) +{ + guint64 longid; + guint id; + gchar *endptr; + + if (!purple_str_has_prefix(uri, PURPLE_IMAGE_STORE_PROTOCOL)) + return NULL; + + uri += sizeof(PURPLE_IMAGE_STORE_PROTOCOL) - 1; + if (uri[0] == '-') + return NULL; + + longid = g_ascii_strtoull(uri, &endptr, 10); + if (endptr[0] != '\0') + return NULL; + + id = longid; + if (id != longid) + return NULL; + + return purple_image_store_get(id); +} + void _purple_image_store_init(void) {
--- a/libpurple/image-store.h Fri Apr 11 22:20:09 2014 +0200 +++ b/libpurple/image-store.h Fri Apr 11 22:53:23 2014 +0200 @@ -53,6 +53,9 @@ PurpleImage * purple_image_store_get(guint id); +PurpleImage * +purple_image_store_get_from_uri(const gchar *uri); + void _purple_image_store_init(void);
--- a/libpurple/image.c Fri Apr 11 22:20:09 2014 +0200 +++ b/libpurple/image.c Fri Apr 11 22:53:23 2014 +0200 @@ -163,6 +163,7 @@ g_return_val_if_fail(g_file_test(path, G_FILE_TEST_EXISTS), NULL); img = g_object_new(PURPLE_TYPE_IMAGE, NULL); + purple_image_set_friendly_filename(img, path); priv = PURPLE_IMAGE_GET_PRIVATE(img); priv->path = g_strdup(path);
--- a/pidgin/gtkwebview.c Fri Apr 11 22:20:09 2014 +0200 +++ b/pidgin/gtkwebview.c Fri Apr 11 22:53:23 2014 +0200 @@ -111,9 +111,6 @@ /* WebKit inspector */ WebKitWebView *inspector_view; GtkWindow *inspector_win; - - /* Resources cache */ - GHashTable *loaded_images; } PidginWebViewPriv; /****************************************************************************** @@ -125,6 +122,14 @@ static GRegex *smileys_re = NULL; static GRegex *empty_html_re = NULL; +/* Resources cache. + * + * It's global, because gtkwebkit calls "resource-load-finished" only once + * for each static resource. + */ +static GHashTable *globally_loaded_images = NULL; +guint globally_loaded_images_refcnt = 0; + /****************************************************************************** * Helpers @@ -208,10 +213,9 @@ webview_resource_loaded(WebKitWebView *web_view, WebKitWebFrame *web_frame, WebKitWebResource *web_resource, gpointer user_data) { - PidginWebViewPriv *priv = PIDGIN_WEBVIEW_GET_PRIVATE(web_view); const gchar *uri; GString *data; - PurpleImage *image; + PurpleImage *image = NULL; if (!purple_str_has_caseprefix( webkit_web_resource_get_mime_type(web_resource), "image/")) @@ -220,20 +224,23 @@ } uri = webkit_web_resource_get_uri(web_resource); - if (g_hash_table_lookup(priv->loaded_images, uri)) + if (g_hash_table_lookup(globally_loaded_images, uri)) return; data = webkit_web_resource_get_data(web_resource); if (data->len == 0) return; - /* TODO: we could avoid copying data, if uri is a - * PURPLE_IMAGE_STORE_PROTOCOL */ - image = purple_image_new_from_data( - g_memdup(data->str, data->len), data->len); - g_return_if_fail(image != NULL); + image = purple_image_store_get_from_uri(uri); + if (image) { + g_object_ref(image); + } else { + image = purple_image_new_from_data( + g_memdup(data->str, data->len), data->len); + g_return_if_fail(image != NULL); + } - g_hash_table_insert(priv->loaded_images, g_strdup(uri), image); + g_hash_table_insert(globally_loaded_images, g_strdup(uri), image); } static PurpleImage * @@ -243,7 +250,7 @@ g_return_val_if_fail(priv != NULL, NULL); - return g_hash_table_lookup(priv->loaded_images, uri); + return g_hash_table_lookup(globally_loaded_images, uri); } static void @@ -1117,7 +1124,11 @@ } g_queue_free(priv->load_queue); - g_hash_table_destroy(priv->loaded_images); + if (--globally_loaded_images_refcnt == 0) { + g_assert(globally_loaded_images != NULL); + g_hash_table_destroy(globally_loaded_images); + globally_loaded_images = NULL; + } G_OBJECT_CLASS(parent_class)->finalize(G_OBJECT(webview)); } @@ -1298,8 +1309,11 @@ g_signal_connect(G_OBJECT(inspector), "show-window", G_CALLBACK(webview_inspector_show), webview); - priv->loaded_images = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_object_unref); + if (globally_loaded_images_refcnt++ == 0) { + g_assert(globally_loaded_images == NULL); + globally_loaded_images = g_hash_table_new_full(g_str_hash, + g_str_equal, g_free, g_object_unref); + } } GType
--- a/pidgin/gtkwebviewtoolbar.c Fri Apr 11 22:20:09 2014 +0200 +++ b/pidgin/gtkwebviewtoolbar.c Fri Apr 11 22:53:23 2014 +0200 @@ -608,10 +608,7 @@ do_insert_image_cb(GtkWidget *widget, int response, PidginWebViewToolbar *toolbar) { PidginWebViewToolbarPriv *priv = PIDGIN_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar); - gchar *filename = NULL, *buf; - char *filedata; - size_t size; - GError *error = NULL; + gchar *filename = NULL; PurpleImage *img; if (response == GTK_RESPONSE_ACCEPT) @@ -623,20 +620,12 @@ if (filename == NULL) return; - if (!g_file_get_contents(filename, &filedata, &size, &error)) { - purple_notify_error(NULL, NULL, error->message, NULL, NULL); - - g_error_free(error); - g_free(filename); - - return; - } - - img = purple_image_new_from_data(filedata, size); - purple_image_set_friendly_filename(img, filename); + img = purple_image_new_from_file(filename, TRUE); if (!img) { - buf = g_strdup_printf(_("Failed to store image: %s\n"), filename); + gchar *buf = g_strdup_printf(_("Failed to store image: %s"), + filename); + purple_notify_error(NULL, NULL, buf, NULL, NULL); g_free(buf);