Break out cairo color matrix recoloring to gdk_cairo_image_surface_recolor()

This is useful in some parts of the icon theme APIs.
This commit is contained in:
Alexander Larsson 2020-01-28 11:42:24 +01:00
parent dbe021239f
commit afa6cc2369
3 changed files with 68 additions and 50 deletions

View File

@ -456,3 +456,62 @@ gdk_cairo_region_from_clip (cairo_t *cr)
return region;
}
void
gdk_cairo_image_surface_recolor (cairo_surface_t *image_surface,
const graphene_matrix_t *color_matrix,
const graphene_vec4_t *color_offset)
{
graphene_vec4_t pixel;
guint32* pixel_data;
guchar *data;
gsize x, y, width, height, stride;
float alpha;
data = cairo_image_surface_get_data (image_surface);
width = cairo_image_surface_get_width (image_surface);
height = cairo_image_surface_get_height (image_surface);
stride = cairo_image_surface_get_stride (image_surface);
for (y = 0; y < height; y++)
{
pixel_data = (guint32 *) data;
for (x = 0; x < width; x++)
{
alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0;
if (alpha == 0)
{
graphene_vec4_init (&pixel, 0.0, 0.0, 0.0, 0.0);
}
else
{
graphene_vec4_init (&pixel,
((pixel_data[x] >> 16) & 0xFF) / (255.0 * alpha),
((pixel_data[x] >> 8) & 0xFF) / (255.0 * alpha),
( pixel_data[x] & 0xFF) / (255.0 * alpha),
alpha);
graphene_matrix_transform_vec4 (color_matrix, &pixel, &pixel);
}
graphene_vec4_add (&pixel, color_offset, &pixel);
alpha = graphene_vec4_get_w (&pixel);
if (alpha > 0.0)
{
alpha = MIN (alpha, 1.0);
pixel_data[x] = (((guint32) roundf (alpha * 255)) << 24) |
(((guint32) roundf (CLAMP (graphene_vec4_get_x (&pixel), 0, 1) * alpha * 255)) << 16) |
(((guint32) roundf (CLAMP (graphene_vec4_get_y (&pixel), 0, 1) * alpha * 255)) << 8) |
((guint32) roundf (CLAMP (graphene_vec4_get_z (&pixel), 0, 1) * alpha * 255));
}
else
{
pixel_data[x] = 0;
}
}
data += stride;
}
cairo_surface_mark_dirty (image_surface);
}

View File

@ -26,6 +26,7 @@
#include <gdk/gdkrgba.h>
#include <gdk/gdkpixbuf.h>
#include <pango/pangocairo.h>
#include <graphene.h>
G_BEGIN_DECLS
@ -72,6 +73,11 @@ void gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface,
int height,
GdkGLContext *context);
GDK_AVAILABLE_IN_ALL
void gdk_cairo_image_surface_recolor (cairo_surface_t *image_surface,
const graphene_matrix_t *color_matrix,
const graphene_vec4_t *color_offset);
G_END_DECLS
#endif /* __GDK_CAIRO_H__ */

View File

@ -2339,11 +2339,6 @@ gsk_color_matrix_node_draw (GskRenderNode *node,
GskColorMatrixNode *self = (GskColorMatrixNode *) node;
cairo_pattern_t *pattern;
cairo_surface_t *surface, *image_surface;
graphene_vec4_t pixel;
guint32* pixel_data;
guchar *data;
gsize x, y, width, height, stride;
float alpha;
cairo_save (cr);
@ -2360,52 +2355,10 @@ gsk_color_matrix_node_draw (GskRenderNode *node,
cairo_pattern_get_surface (pattern, &surface);
image_surface = cairo_surface_map_to_image (surface, NULL);
data = cairo_image_surface_get_data (image_surface);
width = cairo_image_surface_get_width (image_surface);
height = cairo_image_surface_get_height (image_surface);
stride = cairo_image_surface_get_stride (image_surface);
gdk_cairo_image_surface_recolor (image_surface,
&self->color_matrix,
&self->color_offset);
for (y = 0; y < height; y++)
{
pixel_data = (guint32 *) data;
for (x = 0; x < width; x++)
{
alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0;
if (alpha == 0)
{
graphene_vec4_init (&pixel, 0.0, 0.0, 0.0, 0.0);
}
else
{
graphene_vec4_init (&pixel,
((pixel_data[x] >> 16) & 0xFF) / (255.0 * alpha),
((pixel_data[x] >> 8) & 0xFF) / (255.0 * alpha),
( pixel_data[x] & 0xFF) / (255.0 * alpha),
alpha);
graphene_matrix_transform_vec4 (&self->color_matrix, &pixel, &pixel);
}
graphene_vec4_add (&pixel, &self->color_offset, &pixel);
alpha = graphene_vec4_get_w (&pixel);
if (alpha > 0.0)
{
alpha = MIN (alpha, 1.0);
pixel_data[x] = (((guint32) roundf (alpha * 255)) << 24) |
(((guint32) roundf (CLAMP (graphene_vec4_get_x (&pixel), 0, 1) * alpha * 255)) << 16) |
(((guint32) roundf (CLAMP (graphene_vec4_get_y (&pixel), 0, 1) * alpha * 255)) << 8) |
((guint32) roundf (CLAMP (graphene_vec4_get_z (&pixel), 0, 1) * alpha * 255));
}
else
{
pixel_data[x] = 0;
}
}
data += stride;
}
cairo_surface_mark_dirty (image_surface);
cairo_surface_unmap_image (surface, image_surface);
cairo_set_source (cr, pattern);