[gnome-documents] documents: improve thumbnail frame rendering



commit 5eb3240f63ad009820e1a11ded23623228f884d5
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Fri Nov 18 15:13:04 2011 -0500

    documents: improve thumbnail frame rendering
    
    Use GTK+CSS tricks to render the thumbnail frame; this gives us a lot
    more flexibility and uses less code.

 data/thumbnail-frame.png |  Bin 482 -> 832 bytes
 src/documents.js         |   19 ++---
 src/lib/gd-utils.c       |  190 ++++++++++++++++++----------------------------
 src/lib/gd-utils.h       |   10 +--
 src/utils.js             |   22 ++++++
 5 files changed, 106 insertions(+), 135 deletions(-)
---
diff --git a/data/thumbnail-frame.png b/data/thumbnail-frame.png
index 674b648..ba5d721 100644
Binary files a/data/thumbnail-frame.png and b/data/thumbnail-frame.png differ
diff --git a/src/documents.js b/src/documents.js
index 8356f37..add3ccc 100644
--- a/src/documents.js
+++ b/src/documents.js
@@ -41,8 +41,6 @@ const Searchbar = imports.searchbar;
 const TrackerUtils = imports.trackerUtils;
 const Utils = imports.utils;
 
-const _THUMBNAIL_FRAME = 3;
-
 function SingleItemJob(doc) {
     this._init(doc);
 }
@@ -563,13 +561,14 @@ DocCommon.prototype = {
             }
         }
 
-        if (this.thumbnailed)
+        if (this.thumbnailed) {
+            let [ slice, border ] = Utils.getThumbnailFrameBorder();
             this.pixbuf = Gd.embed_image_in_frame(pixbuf,
-                Global.documentManager.getPixbufFrame(),
-                _THUMBNAIL_FRAME, _THUMBNAIL_FRAME,
-                _THUMBNAIL_FRAME, _THUMBNAIL_FRAME);
-        else
+                Path.ICONS_DIR + 'thumbnail-frame.png',
+                slice, border);
+        } else {
             this.pixbuf = pixbuf;
+        }
 
         this.emit('info-updated');
     },
@@ -825,8 +824,6 @@ DocumentManager.prototype = {
 
         Global.changeMonitor.connect('changes-pending',
                                      Lang.bind(this, this._onChangesPending));
-
-        this._pixbufFrame = GdkPixbuf.Pixbuf.new_from_file(Path.ICONS_DIR + 'thumbnail-frame.png');
     },
 
     _onChangesPending: function(monitor, changes) {
@@ -872,10 +869,6 @@ DocumentManager.prototype = {
                 (identifier.indexOf('https://docs.google.com') != -1));
     },
 
-    getPixbufFrame: function() {
-        return this._pixbufFrame;
-    },
-
     createDocumentFromCursor: function(cursor) {
         let identifier = cursor.get_string(Query.QueryColumns.IDENTIFIER)[0];
         let doc;
diff --git a/src/lib/gd-utils.c b/src/lib/gd-utils.c
index ecc5bac..a5804fd 100644
--- a/src/lib/gd-utils.c
+++ b/src/lib/gd-utils.c
@@ -304,131 +304,89 @@ gd_gtk_icon_view_set_activate_on_single_click (GtkIconView *icon_view,
   }
 }
 
-/* utility to stretch a frame to the desired size */
-
-static void
-draw_frame_row (GdkPixbuf *frame_image, int target_width, int source_width, int source_v_position, int dest_v_position, GdkPixbuf *result_pixbuf, int left_offset, int height)
-{
-	int remaining_width, h_offset, slab_width;
-	
-	remaining_width = target_width;
-	h_offset = 0;
-	while (remaining_width > 0) {	
-		slab_width = remaining_width > source_width ? source_width : remaining_width;
-		gdk_pixbuf_copy_area (frame_image, left_offset, source_v_position, slab_width, height, result_pixbuf, left_offset + h_offset, dest_v_position);
-		remaining_width -= slab_width;
-		h_offset += slab_width; 
-	}
-}
-
-/* utility to draw the middle section of the frame in a loop */
-static void
-draw_frame_column (GdkPixbuf *frame_image, int target_height, int source_height, int source_h_position, int dest_h_position, GdkPixbuf *result_pixbuf, int top_offset, int width)
-{
-	int remaining_height, v_offset, slab_height;
-	
-	remaining_height = target_height;
-	v_offset = 0;
-	while (remaining_height > 0) {	
-		slab_height = remaining_height > source_height ? source_height : remaining_height;
-		gdk_pixbuf_copy_area (frame_image, source_h_position, top_offset, width, slab_height, result_pixbuf, dest_h_position, top_offset + v_offset);
-		remaining_height -= slab_height;
-		v_offset += slab_height; 
-	}
-}
-
-static GdkPixbuf *
-gd_stretch_frame_image (GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset,
-			 int dest_width, int dest_height, gboolean fill_flag)
-{
-	GdkPixbuf *result_pixbuf;
-	guchar *pixels_ptr;
-	int frame_width, frame_height;
-	int y, row_stride;
-	int target_width, target_frame_width;
-	int target_height, target_frame_height;
-	
-	frame_width  = gdk_pixbuf_get_width  (frame_image);
-	frame_height = gdk_pixbuf_get_height (frame_image );
-	
-	if (fill_flag) {
-		result_pixbuf = gdk_pixbuf_scale_simple (frame_image, dest_width, dest_height, GDK_INTERP_NEAREST);
-	} else {
-		result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height);
-	}
-	row_stride = gdk_pixbuf_get_rowstride (result_pixbuf);
-	pixels_ptr = gdk_pixbuf_get_pixels (result_pixbuf);
-	
-	/* clear the new pixbuf */
-	if (!fill_flag) {
-		for (y = 0; y < dest_height; y++) {
-			memset (pixels_ptr, 255, row_stride);
-			pixels_ptr += row_stride; 
-		}
-	}
-	
-	target_width  = dest_width - left_offset - right_offset;
-	target_frame_width = frame_width - left_offset - right_offset;
-	
-	target_height  = dest_height - top_offset - bottom_offset;
-	target_frame_height = frame_height - top_offset - bottom_offset;
-	
-	/* draw the left top corner  and top row */
-	gdk_pixbuf_copy_area (frame_image, 0, 0, left_offset, top_offset, result_pixbuf, 0,  0);
-	draw_frame_row (frame_image, target_width, target_frame_width, 0, 0, result_pixbuf, left_offset, top_offset);
-	
-	/* draw the right top corner and left column */
-	gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, 0, right_offset, top_offset, result_pixbuf, dest_width - right_offset,  0);
-	draw_frame_column (frame_image, target_height, target_frame_height, 0, 0, result_pixbuf, top_offset, left_offset);
-
-	/* draw the bottom right corner and bottom row */
-	gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, frame_height - bottom_offset, right_offset, bottom_offset, result_pixbuf, dest_width - right_offset,  dest_height - bottom_offset);
-	draw_frame_row (frame_image, target_width, target_frame_width, frame_height - bottom_offset, dest_height - bottom_offset, result_pixbuf, left_offset, bottom_offset);
-		
-	/* draw the bottom left corner and the right column */
-	gdk_pixbuf_copy_area (frame_image, 0, frame_height - bottom_offset, left_offset, bottom_offset, result_pixbuf, 0,  dest_height - bottom_offset);
-	draw_frame_column (frame_image, target_height, target_frame_height, frame_width - right_offset, dest_width - right_offset, result_pixbuf, top_offset, right_offset);
-	
-	return result_pixbuf;
-}
-
 /**
  * gd_embed_image_in_frame: 
  * @source_image:
- * @frame_image:
- * @left_offset:
- * @top_offset:
- * @right_offset:
- * @bottom_offset:
+ * @frame_image_path:
+ * @slice_width:
+ * @border_width:
  *
  * Returns: (transfer full):
  */
-/* draw an arbitrary frame around an image, with the result passed back in a newly allocated pixbuf */
 GdkPixbuf *
 gd_embed_image_in_frame (GdkPixbuf *source_image,
-                         GdkPixbuf *frame_image,
-                         int left_offset, 
-                         int top_offset, 
-                         int right_offset, 
-                         int bottom_offset)
+                         const gchar *frame_image_path,
+                         GtkBorder *slice_width,
+                         GtkBorder *border_width)
 {
-	GdkPixbuf *result_pixbuf;
-	int source_width, source_height;
-	int dest_width, dest_height;
-	
-	source_width  = gdk_pixbuf_get_width  (source_image);
-	source_height = gdk_pixbuf_get_height (source_image);
-
-	dest_width  = source_width  + left_offset + right_offset;
-	dest_height = source_height + top_offset  + bottom_offset;
-	
-	result_pixbuf = gd_stretch_frame_image (frame_image, left_offset, top_offset, right_offset, bottom_offset, 
-                                                dest_width, dest_height, FALSE);
-		
-	/* Finally, copy the source image into the framed area */
-	gdk_pixbuf_copy_area (source_image, 0, 0, source_width, source_height, result_pixbuf, left_offset,  top_offset);
-
-	return result_pixbuf;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  int source_width, source_height;
+  int dest_width, dest_height;
+  gchar *css_str;
+  GtkCssProvider *provider;
+  GtkStyleContext *context;
+  GError *error = NULL;
+  GdkPixbuf *retval;
+  GtkWidgetPath *path;
+ 
+  source_width = gdk_pixbuf_get_width (source_image);
+  source_height = gdk_pixbuf_get_height (source_image);
+
+  dest_width = source_width +  border_width->left + border_width->right;
+  dest_height = source_height + border_width->top + border_width->bottom;
+
+  css_str = g_strdup_printf (".embedded-image { border-image: url(\"%s\") %d %d %d %d / %d %d %d %d }",
+                             frame_image_path, 
+                             slice_width->top, slice_width->right, slice_width->bottom, slice_width->left,
+                             border_width->top, border_width->right, border_width->bottom, border_width->left);
+  provider = gtk_css_provider_new ();
+  gtk_css_provider_load_from_data (provider, css_str, -1, &error);
+
+  if (error != NULL) 
+    {
+      g_warning ("Unable to create the thumbnail frame image: %s", error->message);
+      g_error_free (error);
+      g_free (css_str);
+
+      return g_object_ref (source_image);
+    }
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, dest_width, dest_height);
+  cr = cairo_create (surface);
+
+  context = gtk_style_context_new ();
+  path = gtk_widget_path_new ();
+  gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);
+
+  gtk_style_context_set_path (context, path);
+  gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), 600);
+
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, "embedded-image");
+
+  gtk_render_frame (context, cr,
+                    0, 0,
+                    dest_width, dest_height);
+
+  gtk_style_context_restore (context);
+
+  gtk_render_icon (context, cr,
+                   source_image,
+                   border_width->left, border_width->top);
+
+  retval = gdk_pixbuf_get_from_surface (surface,
+                                        0, 0, dest_width, dest_height);
+
+  cairo_surface_destroy (surface);
+  cairo_destroy (cr);
+
+  gtk_widget_path_unref (path);
+  g_object_unref (provider);
+  g_object_unref (context);
+  g_free (css_str);
+
+  return retval;
 }
 
 static char *
diff --git a/src/lib/gd-utils.h b/src/lib/gd-utils.h
index 8fea96f..c0d5757 100644
--- a/src/lib/gd-utils.h
+++ b/src/lib/gd-utils.h
@@ -58,12 +58,10 @@ void gd_gtk_tree_view_set_activate_on_single_click (GtkTreeView *tree_view,
 void gd_gtk_icon_view_set_activate_on_single_click (GtkIconView *icon_view,
                                                     gboolean should_activate);
 
-GdkPixbuf * gd_embed_image_in_frame (GdkPixbuf *source_image,
-                                     GdkPixbuf *frame_image,
-                                     int left_offset,
-                                     int top_offset,
-                                     int right_offset,
-                                     int bottom_offset);
+GdkPixbuf *gd_embed_image_in_frame (GdkPixbuf *source_image,
+                                    const gchar *frame_image_path,
+                                    GtkBorder *slice_width,
+                                    GtkBorder *border_width);
 
 char *gd_filename_strip_extension (const char * filename_with_extension);
 
diff --git a/src/utils.js b/src/utils.js
index 3fda1a3..12ffe83 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -40,6 +40,28 @@ function getIconSize() {
     return Global.settings.get_boolean('list-view') ? _LIST_VIEW_SIZE : _ICON_VIEW_SIZE;
 }
 
+function getThumbnailFrameBorder() {
+    let slice = new Gtk.Border();
+    let border = null;
+
+    slice.top = 3;
+    slice.right = 3;
+    slice.bottom = 6;
+    slice.left = 4;
+
+    if (Global.settings.get_boolean('list-view')) {
+        border = new Gtk.Border();
+        border.top = 1;
+        border.right = 1;
+        border.bottom = 3;
+        border.left = 2;
+    } else {
+        border = slice.copy();
+    }
+
+    return [ slice, border ];
+}
+
 function iconFromRdfType(type) {
     let iconName;
 



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