Updating branch refs/heads/master to 9b02a15007ac21a45e5784cde4741602bacb6cff (commit) from a72c39d14052e1aea96e749c4e373967d96585d7 (commit)
commit 9b02a15007ac21a45e5784cde4741602bacb6cff Author: Nick Schermer <n...@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); _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org https://mail.xfce.org/mailman/listinfo/xfce4-commits