[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