From d3545a3b535afac2b5a0a99836b9bed2bef97d59 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 22 Feb 2023 01:29:46 +0100 Subject: [PATCH] st: Drop usage of gdk_cairo_set_source_pixbuf() Avoid using it by... guess it... yes! Copying the function into an utility. This helper function to convert between pixel formats is quite self-contained and unrelated to the rest of GTK, so may be copied in place. Part-of: --- src/st/st-image-content.c | 2 + src/st/st-texture-cache.c | 117 +++++++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/st/st-image-content.c b/src/st/st-image-content.c index 92f1c1415..01a39f4f2 100644 --- a/src/st/st-image-content.c +++ b/src/st/st-image-content.c @@ -21,6 +21,8 @@ #include "st-image-content.h" #include "st-private.h" +#include + struct _StImageContent { /*< private >*/ diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c index acf01325e..bbe31bda7 100644 --- a/src/st/st-texture-cache.c +++ b/src/st/st-texture-cache.c @@ -541,6 +541,121 @@ pixbuf_to_st_content_image (GdkPixbuf *pixbuf, return image; } +static void +util_cairo_surface_paint_pixbuf (cairo_surface_t *surface, + const GdkPixbuf *pixbuf) +{ + int width, height; + guchar *gdk_pixels, *cairo_pixels; + int gdk_rowstride, cairo_stride; + int n_channels; + int j; + + if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) + return; + + /* This function can't just copy any pixbuf to any surface, be + * sure to read the invariants here before calling it */ + g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE); + g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_RGB24 || + cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32); + g_assert (cairo_image_surface_get_width (surface) == gdk_pixbuf_get_width (pixbuf)); + g_assert (cairo_image_surface_get_height (surface) == gdk_pixbuf_get_height (pixbuf)); + + cairo_surface_flush (surface); + + 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); + cairo_stride = cairo_image_surface_get_stride (surface); + cairo_pixels = cairo_image_surface_get_data (surface); + + for (j = height; j; j--) + { + guchar *p = gdk_pixels; + guchar *q = cairo_pixels; + + if (n_channels == 3) + { + guchar *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; + } + } + else + { + guchar *end = p + 4 * width; + guint t1,t2,t3; + +#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END + + while (p < end) + { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + MULT(q[0], p[2], p[3], t1); + MULT(q[1], p[1], p[3], t2); + MULT(q[2], p[0], p[3], t3); + q[3] = p[3]; +#else + q[0] = p[3]; + MULT(q[1], p[0], p[3], t1); + MULT(q[2], p[1], p[3], t2); + MULT(q[3], p[2], p[3], t3); +#endif + + p += 4; + q += 4; + } + +#undef MULT + } + + gdk_pixels += gdk_rowstride; + cairo_pixels += cairo_stride; + } + + cairo_surface_mark_dirty (surface); +} + +static void +util_cairo_set_source_pixbuf (cairo_t *cr, + const GdkPixbuf *pixbuf, + gdouble pixbuf_x, + gdouble pixbuf_y) +{ + cairo_format_t format; + cairo_surface_t *surface; + + if (gdk_pixbuf_get_n_channels (pixbuf) == 3) + format = CAIRO_FORMAT_RGB24; + else + format = CAIRO_FORMAT_ARGB32; + + surface = cairo_surface_create_similar_image (cairo_get_target (cr), + format, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + + util_cairo_surface_paint_pixbuf (surface, pixbuf); + + cairo_set_source_surface (cr, surface, pixbuf_x, pixbuf_y); + cairo_surface_destroy (surface); +} + static cairo_surface_t * pixbuf_to_cairo_surface (GdkPixbuf *pixbuf) { @@ -552,7 +667,7 @@ pixbuf_to_cairo_surface (GdkPixbuf *pixbuf) dummy_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); cr = cairo_create (dummy_surface); - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + util_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); pattern = cairo_get_source (cr); cairo_pattern_get_surface (pattern, &surface); cairo_surface_reference (surface);