[gnome-desktop] thumbnail: Always use external gdk-pixbuf thumbnailer



commit b69fde6f4a709f8c4fa3087941cee5b4c4169a8d
Author: Bastien Nocera <hadess hadess net>
Date:   Sun Jun 26 12:18:28 2016 +0200

    thumbnail: Always use external gdk-pixbuf thumbnailer
    
    Instead of special-casing gdk-pixbuf-supported image formats, use an
    external thumbnailer. This will give us the ability to:
    - cancel running thumbnail operations
    - avoid memory leaks, buffer overflows, double-frees, etc. in the
      image loaders having an impact on the application
    - limit resource usage when thumbnailing
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768064

 configure.ac                               |    2 +-
 libgnome-desktop/gnome-desktop-thumbnail.c |  351 +---------------------------
 2 files changed, 4 insertions(+), 349 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 2f3382d..a4df4d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -103,7 +103,7 @@ GLIB_TESTS
 dnl If you add a version number here, you *must* add an AC_SUBST line for
 dnl it too, or it will never make it into the spec file!
 
-GDK_PIXBUF_REQUIRED=2.33.0
+GDK_PIXBUF_REQUIRED=2.36.1
 GTK_REQUIRED=3.3.6
 GLIB_REQUIRED=2.44.0
 XRANDR_REQUIRED=1.3
diff --git a/libgnome-desktop/gnome-desktop-thumbnail.c b/libgnome-desktop/gnome-desktop-thumbnail.c
index 3946309..0605a76 100644
--- a/libgnome-desktop/gnome-desktop-thumbnail.c
+++ b/libgnome-desktop/gnome-desktop-thumbnail.c
@@ -180,16 +180,6 @@ G_DEFINE_TYPE (GnomeDesktopThumbnailFactory,
 #define GNOME_DESKTOP_THUMBNAIL_FACTORY_GET_PRIVATE(object) \
   (G_TYPE_INSTANCE_GET_PRIVATE ((object), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, 
GnomeDesktopThumbnailFactoryPrivate))
 
-typedef struct {
-    gint width;
-    gint height;
-    gint input_width;
-    gint input_height;
-    gboolean preserve_aspect_ratio;
-} SizePrepareContext;
-
-#define LOAD_BUFFER_SIZE 4096
-
 #define THUMBNAILER_ENTRY_GROUP "Thumbnailer Entry"
 #define THUMBNAILER_EXTENSION   ".thumbnailer"
 
@@ -358,229 +348,6 @@ get_thumbnailers_dirs (void)
   return g_once (&once_init, init_thumbnailers_dirs, NULL);
 }
 
-static void
-size_prepared_cb (GdkPixbufLoader *loader, 
-                 int              width,
-                 int              height,
-                 gpointer         data)
-{
-  SizePrepareContext *info = data;
-  
-  g_return_if_fail (width > 0 && height > 0);
-  
-  info->input_width = width;
-  info->input_height = height;
-  
-  if (width < info->width && height < info->height) return;
-  
-  if (info->preserve_aspect_ratio && 
-      (info->width > 0 || info->height > 0)) {
-    if (info->width < 0)
-      {
-       width = width * (double)info->height/(double)height;
-       height = info->height;
-      }
-    else if (info->height < 0)
-      {
-       height = height * (double)info->width/(double)width;
-       width = info->width;
-      }
-    else if ((double)height * (double)info->width >
-            (double)width * (double)info->height) {
-      width = 0.5 + (double)width * (double)info->height / (double)height;
-      height = info->height;
-    } else {
-      height = 0.5 + (double)height * (double)info->width / (double)width;
-      width = info->width;
-    }
-  } else {
-    if (info->width > 0)
-      width = info->width;
-    if (info->height > 0)
-      height = info->height;
-  }
-  
-  gdk_pixbuf_loader_set_size (loader, width, height);
-}
-
-static GdkPixbufLoader *
-create_loader (GFile        *file,
-               const guchar *data,
-               gsize         size)
-{
-  GdkPixbufLoader *loader;
-  GError *error = NULL;
-  char *mime_type;
-  char *filename;
-
-  loader = NULL;
-
-  /* need to specify the type here because the gdk_pixbuf_loader_write
-     doesn't have access to the filename in order to correct detect
-     the image type. */
-  filename = g_file_get_basename (file);
-  mime_type = g_content_type_guess (filename, data, size, NULL);
-  g_free (filename);
-
-  if (mime_type != NULL) {
-    loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error);
-  }
-
-  if (loader == NULL) {
-    g_debug ("Unable to create loader for mime type %s: %s", mime_type, error->message);
-    g_clear_error (&error);
-    loader = gdk_pixbuf_loader_new ();
-  }
-  g_free (mime_type);
-
-  return loader;
-}
-
-static GdkPixbuf *
-_gdk_pixbuf_new_from_uri_at_scale (const char *uri,
-                                  gint        width,
-                                  gint        height,
-                                  gboolean    preserve_aspect_ratio)
-{
-    gboolean result;
-    guchar buffer[LOAD_BUFFER_SIZE];
-    gssize bytes_read;
-    GdkPixbufLoader *loader = NULL;
-    GdkPixbuf *pixbuf; 
-    GdkPixbufAnimation *animation;
-    GdkPixbufAnimationIter *iter;
-    gboolean has_frame;
-    SizePrepareContext info;
-    GFile *file;
-    GFileInfo *file_info;
-    GInputStream *input_stream;
-    GError *error = NULL;
-
-    g_return_val_if_fail (uri != NULL, NULL);
-
-    input_stream = NULL;
-
-    file = g_file_new_for_uri (uri);
-
-    /* First see if we can get an input stream via preview::icon  */
-    file_info = g_file_query_info (file,
-                                   G_FILE_ATTRIBUTE_PREVIEW_ICON,
-                                   G_FILE_QUERY_INFO_NONE,
-                                   NULL,  /* GCancellable */
-                                   NULL); /* return location for GError */
-    if (file_info != NULL) {
-        GObject *object;
-
-        object = g_file_info_get_attribute_object (file_info,
-                                                   G_FILE_ATTRIBUTE_PREVIEW_ICON);
-        if (object != NULL && G_IS_LOADABLE_ICON (object)) {
-            input_stream = g_loadable_icon_load (G_LOADABLE_ICON (object),
-                                                 0,     /* size */
-                                                 NULL,  /* return location for type */
-                                                 NULL,  /* GCancellable */
-                                                 NULL); /* return location for GError */
-        }
-        g_object_unref (file_info);
-    }
-
-    if (input_stream == NULL) {
-           input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
-           if (input_stream == NULL) {
-                   g_warning ("Unable to create an input stream for %s: %s", uri, error->message);
-                   g_clear_error (&error);
-                   g_object_unref (file);
-                   return NULL;
-           }
-    }
-
-    has_frame = FALSE;
-
-    result = FALSE;
-    while (!has_frame) {
-
-       bytes_read = g_input_stream_read (input_stream,
-                                         buffer,
-                                         sizeof (buffer),
-                                         NULL,
-                                         &error);
-        if (bytes_read == -1) {
-            g_warning ("Error reading from %s: %s", uri, error->message);
-            g_clear_error (&error);
-            break;
-        }
-       result = TRUE;
-       if (bytes_read == 0) {
-           break;
-       }
-
-        if (loader == NULL) {
-            loader = create_loader (file, buffer, bytes_read);
-            if (1 <= width || 1 <= height) {
-              info.width = width;
-              info.height = height;
-              info.input_width = info.input_height = 0;
-              info.preserve_aspect_ratio = preserve_aspect_ratio;
-              g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
-            }
-            g_assert (loader != NULL);
-        }
-
-       if (!gdk_pixbuf_loader_write (loader,
-                                     (unsigned char *)buffer,
-                                     bytes_read,
-                                     &error)) {
-            g_warning ("Error creating thumbnail for %s: %s", uri, error->message);
-            g_clear_error (&error);
-           result = FALSE;
-           break;
-       }
-
-       animation = gdk_pixbuf_loader_get_animation (loader);
-       if (animation) {
-               iter = gdk_pixbuf_animation_get_iter (animation, NULL);
-               if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
-                       has_frame = TRUE;
-               }
-               g_object_unref (iter);
-       }
-    }
-
-    if (loader == NULL) {
-        /* This can happen if the above loop was exited due to the
-         * g_input_stream_read() call failing. */
-        result = FALSE;
-    } else if (gdk_pixbuf_loader_close (loader, &error) == FALSE &&
-               !g_error_matches (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION)) {
-        g_warning ("Error creating thumbnail for %s: %s", uri, error->message);
-        result = FALSE;
-    }
-    g_clear_error (&error);
-
-    if (!result) {
-        g_clear_object (&loader);
-       g_input_stream_close (input_stream, NULL, NULL);
-       g_object_unref (input_stream);
-       g_object_unref (file);
-       return NULL;
-    }
-
-    g_input_stream_close (input_stream, NULL, NULL);
-    g_object_unref (input_stream);
-    g_object_unref (file);
-
-    pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-    if (pixbuf != NULL) {
-       g_object_ref (G_OBJECT (pixbuf));
-       g_object_set_data (G_OBJECT (pixbuf), "gnome-original-width",
-                          GINT_TO_POINTER (info.input_width));
-       g_object_set_data (G_OBJECT (pixbuf), "gnome-original-height",
-                          GINT_TO_POINTER (info.input_height));
-    }
-    g_object_unref (G_OBJECT (loader));
-
-    return pixbuf;
-}
-
 /* These should be called with the lock held */
 static void
 gnome_desktop_thumbnail_factory_register_mime_types (GnomeDesktopThumbnailFactory *factory,
@@ -638,7 +405,6 @@ remove_thumbnailer_from_mime_type_map (gchar       *key,
   return (strcmp (value->path, path) == 0);
 }
 
-
 static void
 update_or_create_thumbnailer (GnomeDesktopThumbnailFactory *factory,
                               const gchar                  *path)
@@ -1161,54 +927,6 @@ gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnai
   return TRUE;
 }
 
-static gboolean
-mimetype_supported_by_gdk_pixbuf (const char *mime_type)
-{
-        guint i;
-        static gsize formats_hash = 0;
-        gchar *key;
-        gboolean result;
-
-       if (g_once_init_enter (&formats_hash)) {
-                GSList *formats, *list;
-               GHashTable *hash;
-
-                hash = g_hash_table_new_full (g_str_hash,
-                                             (GEqualFunc) g_content_type_equals,
-                                             g_free, NULL);
-
-                formats = gdk_pixbuf_get_formats ();
-                list = formats;
-
-                while (list) {
-                        GdkPixbufFormat *format = list->data;
-                        gchar **mime_types;
-
-                        mime_types = gdk_pixbuf_format_get_mime_types (format);
-
-                        for (i = 0; mime_types[i] != NULL; i++)
-                                g_hash_table_insert (hash,
-                                                     (gpointer) g_content_type_from_mime_type 
(mime_types[i]),
-                                                     GUINT_TO_POINTER (1));    
-
-                        g_strfreev (mime_types);
-                        list = list->next;
-                }
-                g_slist_free (formats);
-
-               g_once_init_leave (&formats_hash, (gsize) hash);
-        }
-
-        key = g_content_type_from_mime_type (mime_type);
-        if (g_hash_table_lookup ((void*)formats_hash, key))
-                result = TRUE;
-        else
-                result = FALSE;
-        g_free (key);
-
-        return result;
-}
-
 /**
  * gnome_desktop_thumbnail_factory_can_thumbnail:
  * @factory: a #GnomeDesktopThumbnailFactory
@@ -1252,7 +970,7 @@ gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *fac
     }
   g_mutex_unlock (&factory->priv->lock);
 
-  if (have_script || mimetype_supported_by_gdk_pixbuf (mime_type))
+  if (have_script)
     {
       return !gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (factory,
                                                                           uri,
@@ -1351,13 +1069,9 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
                                                    const char            *uri,
                                                    const char            *mime_type)
 {
-  GdkPixbuf *pixbuf, *scaled, *tmp_pixbuf;
+  GdkPixbuf *pixbuf;
   char *script, *expanded_script;
-  int width, height, size;
-  int original_width = 0;
-  int original_height = 0;
-  char dimension[12];
-  double scale;
+  int size;
   int exit_status;
   char *tmpname;
 
@@ -1411,65 +1125,6 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
       g_free (script);
     }
 
-  /* Fall back to gdk-pixbuf */
-  if (pixbuf == NULL)
-    {
-      pixbuf = _gdk_pixbuf_new_from_uri_at_scale (uri, size, size, TRUE);
-
-      if (pixbuf != NULL)
-        {
-          original_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
-                                                               "gnome-original-width"));
-          original_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
-                                                                "gnome-original-height"));
-        }
-    }
-      
-  if (pixbuf == NULL)
-    return NULL;
-
-  /* The pixbuf loader may attach an "orientation" option to the pixbuf,
-     if the tiff or exif jpeg file had an orientation tag. Rotate/flip
-     the pixbuf as specified by this tag, if present. */
-  tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
-  g_object_unref (pixbuf);
-  pixbuf = tmp_pixbuf;
-
-  width = gdk_pixbuf_get_width (pixbuf);
-  height = gdk_pixbuf_get_height (pixbuf);
-  
-  if (width > size || height > size)
-    {
-      const gchar *orig_width, *orig_height;
-      scale = (double)size / MAX (width, height);
-
-      scaled = gnome_desktop_thumbnail_scale_down_pixbuf (pixbuf,
-                                                 floor (width * scale + 0.5),
-                                                 floor (height * scale + 0.5));
-
-      orig_width = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
-      orig_height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
-
-      if (orig_width != NULL) {
-             gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Width", orig_width);
-      }
-      if (orig_height != NULL) {
-             gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Height", orig_height);
-      }
-      
-      g_object_unref (pixbuf);
-      pixbuf = scaled;
-    }
-  
-  if (original_width > 0) {
-         g_snprintf (dimension, sizeof (dimension), "%i", original_width);
-         gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Width", dimension);
-  }
-  if (original_height > 0) {
-         g_snprintf (dimension, sizeof (dimension), "%i", original_height);
-         gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Height", dimension);
-  }
-
   return pixbuf;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]