[Xfce4-commits] <thunar:master> Store cairo surfaces on pixbufs.

Nick Schermer noreply at xfce.org
Sun Nov 11 18:54:01 CET 2012


Updating branch refs/heads/master
         to 9b02a15007ac21a45e5784cde4741602bacb6cff (commit)
       from a72c39d14052e1aea96e749c4e373967d96585d7 (commit)

commit 9b02a15007ac21a45e5784cde4741602bacb6cff
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Nov 11 18:14:35 2012 +0100

    Store cairo surfaces on pixbufs.
    
    Because we store pixbufs in the icon factory
    and re-use them, its efficient to store the
    generated cairo surfaces on the pixmaps and
    re-use those as well.
    
    For this the gdk_cairo_set_source_pixbuf has
    been included in thunar to build the surface,
    we then peek it if already generated for a
    pixmap.

 thunar/thunar-gdk-extensions.c          |  148 +++++++++++++++++++++++++++++++
 thunar/thunar-gdk-extensions.h          |   10 ++-
 thunar/thunar-icon-renderer.c           |    5 +-
 thunar/thunar-shortcuts-icon-renderer.c |    3 +-
 4 files changed, 161 insertions(+), 5 deletions(-)

diff --git a/thunar/thunar-gdk-extensions.c b/thunar/thunar-gdk-extensions.c
index 8330303..8c1fb73 100644
--- a/thunar/thunar-gdk-extensions.c
+++ b/thunar/thunar-gdk-extensions.c
@@ -39,6 +39,113 @@
 
 
 
+static const cairo_user_data_key_t cairo_key;
+
+
+
+static cairo_surface_t *
+thunar_gdk_cairo_create_surface (const GdkPixbuf *pixbuf)
+{
+  gint             width;
+  gint             height;
+  guchar          *gdk_pixels;
+  gint             gdk_rowstride;
+  gint             n_channels;
+  gint             cairo_stride;
+  guchar          *cairo_pixels;
+  cairo_format_t   format;
+  cairo_surface_t *surface;
+  gint             j;
+  guchar          *p, *q;
+  guchar          *end;
+
+  _thunar_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+  /* get pixbuf information */
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
+  gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+  if (n_channels == 3)
+    format = CAIRO_FORMAT_RGB24;
+  else
+    format = CAIRO_FORMAT_ARGB32;
+
+  /* prepare pixel data and surface */
+  cairo_stride = cairo_format_stride_for_width (format, width);
+  cairo_pixels = g_malloc (height * cairo_stride);
+  surface = cairo_image_surface_create_for_data (cairo_pixels, format,
+                                                 width, height, cairo_stride);
+  cairo_surface_set_user_data (surface, &cairo_key, cairo_pixels, g_free);
+
+  /* convert format */
+  if (G_UNLIKELY (n_channels == 3))
+    {
+      for (j = height; j; j--)
+        {
+          p = gdk_pixels;
+          q = cairo_pixels;
+          end = p + 3 * width;
+
+          while (p < end)
+            {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+              q[0] = p[2];
+              q[1] = p[1];
+              q[2] = p[0];
+#else
+              q[1] = p[0];
+              q[2] = p[1];
+              q[3] = p[2];
+#endif
+              p += 3;
+              q += 4;
+            }
+
+          gdk_pixels += gdk_rowstride;
+          cairo_pixels += cairo_stride;
+        }
+    }
+  else
+    {
+#define MULT(d,c,a) G_STMT_START { guint t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
+      for (j = height; j; j--)
+        {
+          p = gdk_pixels;
+          q = cairo_pixels;
+          end = p + 4 * width;
+
+          while (p < end)
+            {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+              MULT(q[0], p[2], p[3]);
+              MULT(q[1], p[1], p[3]);
+              MULT(q[2], p[0], p[3]);
+              q[3] = p[3];
+#else
+              q[0] = p[3];
+              MULT(q[1], p[0], p[3]);
+              MULT(q[2], p[1], p[3]);
+              MULT(q[3], p[2], p[3]);
+#endif
+
+              p += 4;
+              q += 4;
+            }
+
+          gdk_pixels += gdk_rowstride;
+          cairo_pixels += cairo_stride;
+        }
+#undef MULT
+    }
+
+  return surface;
+}
+
+
+
 /**
  * thunar_gdk_screen_open:
  * @display_name : a fully qualified display name.
@@ -128,3 +235,44 @@ thunar_gdk_screen_open (const gchar *display_name,
 
   return screen;
 }
+
+
+
+/**
+ * thunar_gdk_cairo_set_source_pixbuf:
+ * cr       : a Cairo context
+ * pixbuf   : a GdkPixbuf
+ * pixbuf_x : X coordinate of location to place upper left corner of pixbuf
+ * pixbuf_y : Y coordinate of location to place upper left corner of pixbuf
+ *
+ * Works like gdk_cairo_set_source_pixbuf but we try to cache the surface
+ * on the pixbuf, which is efficient within Thunar because we also share
+ * the pixbufs using the icon cache.
+ **/
+void
+thunar_gdk_cairo_set_source_pixbuf (cairo_t   *cr,
+                                    GdkPixbuf *pixbuf,
+                                    gdouble    pixbuf_x,
+                                    gdouble    pixbuf_y)
+{
+  cairo_surface_t *surface;
+  static GQuark    surface_quark = 0;
+
+  if (G_UNLIKELY (surface_quark == 0))
+    surface_quark = g_quark_from_static_string ("thunar-gdk-surface");
+
+  /* peek if there is already a surface */
+  surface = g_object_get_qdata (G_OBJECT (pixbuf), surface_quark);
+  if (surface == NULL)
+    {
+      /* create a new surface */
+      surface = thunar_gdk_cairo_create_surface (pixbuf);
+
+      /* store the pixbuf on the pixbuf */
+      g_object_set_qdata_full (G_OBJECT (pixbuf), surface_quark,
+                               surface, (GDestroyNotify) cairo_surface_destroy);
+    }
+
+  /* apply */
+  cairo_set_source_surface (cr, surface, pixbuf_x, pixbuf_y);
+}
diff --git a/thunar/thunar-gdk-extensions.h b/thunar/thunar-gdk-extensions.h
index be516bb..60b8876 100644
--- a/thunar/thunar-gdk-extensions.h
+++ b/thunar/thunar-gdk-extensions.h
@@ -21,11 +21,17 @@
 #define __THUNAR_GDK_EXTENSIONS_H__
 
 #include <gdk/gdk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 G_BEGIN_DECLS;
 
-GdkScreen *thunar_gdk_screen_open       (const gchar *display_name,
-                                         GError     **error);
+GdkScreen *thunar_gdk_screen_open             (const gchar *display_name,
+                                               GError     **error);
+
+void       thunar_gdk_cairo_set_source_pixbuf (cairo_t     *cr,
+                                               GdkPixbuf   *pixbuf,
+                                               gdouble      pixbuf_x,
+                                               gdouble      pixbuf_y);
 
 G_END_DECLS;
 
diff --git a/thunar/thunar-icon-renderer.c b/thunar/thunar-icon-renderer.c
index 8103a47..f76fdfb 100644
--- a/thunar/thunar-icon-renderer.c
+++ b/thunar/thunar-icon-renderer.c
@@ -23,6 +23,7 @@
 
 #include <thunar/thunar-clipboard-manager.h>
 #include <thunar/thunar-gobject-extensions.h>
+#include <thunar/thunar-gdk-extensions.h>
 #include <thunar/thunar-icon-factory.h>
 #include <thunar/thunar-icon-renderer.h>
 #include <thunar/thunar-private.h>
@@ -444,7 +445,7 @@ thunar_icon_renderer_render (GtkCellRenderer     *renderer,
         }
 
       /* render the invalid parts of the icon */
-      gdk_cairo_set_source_pixbuf (cr, icon, icon_area.x, icon_area.y);
+      thunar_gdk_cairo_set_source_pixbuf (cr, icon, icon_area.x, icon_area.y);
       gdk_cairo_rectangle (cr, &draw_area);
       cairo_paint_with_alpha (cr, alpha);
     }
@@ -529,7 +530,7 @@ thunar_icon_renderer_render (GtkCellRenderer     *renderer,
               if (gdk_rectangle_intersect (expose_area, &emblem_area, &draw_area))
                 {
                   /* render the invalid parts of the icon */
-                  gdk_cairo_set_source_pixbuf (cr, emblem, emblem_area.x, emblem_area.y);
+                  thunar_gdk_cairo_set_source_pixbuf (cr, emblem, emblem_area.x, emblem_area.y);
                   gdk_cairo_rectangle (cr, &draw_area);
                   cairo_paint (cr);
                 }
diff --git a/thunar/thunar-shortcuts-icon-renderer.c b/thunar/thunar-shortcuts-icon-renderer.c
index 9b2f16d..5f122e6 100644
--- a/thunar/thunar-shortcuts-icon-renderer.c
+++ b/thunar/thunar-shortcuts-icon-renderer.c
@@ -26,6 +26,7 @@
 
 #include <thunar/thunar-gio-extensions.h>
 #include <thunar/thunar-gobject-extensions.h>
+#include <thunar/thunar-gdk-extensions.h>
 #include <thunar/thunar-icon-factory.h>
 #include <thunar/thunar-shortcuts-icon-renderer.h>
 #include <thunar/thunar-device.h>
@@ -282,7 +283,7 @@ thunar_shortcuts_icon_renderer_render (GtkCellRenderer     *renderer,
             {
               /* render the invalid parts of the icon */
               cr = gdk_cairo_create (window);
-              gdk_cairo_set_source_pixbuf (cr, icon, icon_area.x, icon_area.y);
+              thunar_gdk_cairo_set_source_pixbuf (cr, icon, icon_area.x, icon_area.y);
               gdk_cairo_rectangle (cr, &draw_area);
               cairo_paint_with_alpha (cr, alpha);
               cairo_destroy (cr);


More information about the Xfce4-commits mailing list