From: Benjamin Otte Date: Mon, 3 Jul 2023 18:45:53 +0000 (+0200) Subject: gsk: Fix luminance in Cairo and GL renderer X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~77^2~1 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=c6eb7fd4837c34ab83de7c79c141404862b80810;p=gtk4.git gsk: Fix luminance in Cairo and GL renderer In particular, fix the combination of luminance and alpha. We want to do mask = luminance * alpha and for inverted mask = (1.0 - luminance) * alpha so add a test that makes sure we do that and then fix the code and existing tests to conform to it. --- diff --git a/gsk/gl/resources/mask.glsl b/gsk/gl/resources/mask.glsl index 602c83dd64..0c2814be9f 100644 --- a/gsk/gl/resources/mask.glsl +++ b/gsk/gl/resources/mask.glsl @@ -13,6 +13,12 @@ void main() { uniform int u_mode; uniform sampler2D u_mask; +float +luminance (vec3 color) +{ + return dot (vec3 (0.2126, 0.7152, 0.0722), color); +} + void main() { vec4 source = GskTexture(u_source, vUv); vec4 mask = GskTexture(u_mask, vUv); @@ -23,9 +29,9 @@ void main() { else if (u_mode == 1) mask_value = 1.0 - mask.a; else if (u_mode == 2) - mask_value = (0.2126 * mask.r + 0.7152 * mask.g + 0.0722 * mask.b) * mask.a; + mask_value = luminance (mask.rgb); else if (u_mode == 3) - mask_value = 1.0 - (0.2126 * mask.r + 0.7152 * mask.g + 0.0722 * mask.b) * mask.a; + mask_value = mask.a - luminance (mask.rgb); else mask_value = 0.0; diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index e3ca2b8b73..54234992f9 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -3702,8 +3702,7 @@ gsk_color_matrix_node_finalize (GskRenderNode *node) static void apply_color_matrix_to_pattern (cairo_pattern_t *pattern, const graphene_matrix_t *color_matrix, - const graphene_vec4_t *color_offset, - gboolean multiply_alpha) + const graphene_vec4_t *color_offset) { cairo_surface_t *surface, *image_surface; guchar *data; @@ -3741,13 +3740,6 @@ apply_color_matrix_to_pattern (cairo_pattern_t *pattern, graphene_matrix_transform_vec4 (color_matrix, &pixel, &pixel); } - if (multiply_alpha) - graphene_vec4_init (&pixel, - graphene_vec4_get_x (&pixel), - graphene_vec4_get_y (&pixel), - graphene_vec4_get_z (&pixel), - alpha * graphene_vec4_get_w (&pixel)); - graphene_vec4_add (&pixel, color_offset, &pixel); alpha = graphene_vec4_get_w (&pixel); @@ -3793,7 +3785,7 @@ gsk_color_matrix_node_draw (GskRenderNode *node, pattern = cairo_pop_group (cr); - apply_color_matrix_to_pattern (pattern, &self->color_matrix, &self->color_offset, FALSE); + apply_color_matrix_to_pattern (pattern, &self->color_matrix, &self->color_offset); cairo_set_source (cr, pattern); cairo_paint (cr); @@ -5654,6 +5646,50 @@ gsk_mask_node_finalize (GskRenderNode *node) parent_class->finalize (node); } +static void +apply_luminance_to_pattern (cairo_pattern_t *pattern, + gboolean invert_luminance) +{ + cairo_surface_t *surface, *image_surface; + guchar *data; + gsize x, y, width, height, stride; + int red, green, blue, alpha, luminance; + guint32* pixel_data; + + 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); + + for (y = 0; y < height; y++) + { + pixel_data = (guint32 *) data; + for (x = 0; x < width; x++) + { + alpha = (pixel_data[x] >> 24) & 0xFF; + red = (pixel_data[x] >> 16) & 0xFF; + green = (pixel_data[x] >> 8) & 0xFF; + blue = (pixel_data[x] >> 0) & 0xFF; + + luminance = 2126 * red + 7152 * green + 722 * blue; + if (invert_luminance) + luminance = 10000 * alpha - luminance; + luminance = (luminance + 5000) / 10000; + + pixel_data[x] = luminance * 0x1010101; + } + data += stride; + } + + cairo_surface_mark_dirty (image_surface); + cairo_surface_unmap_image (surface, image_surface); + /* https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/487 */ + cairo_surface_mark_dirty (surface); +} + static void gsk_mask_node_draw (GskRenderNode *node, cairo_t *cr) @@ -5676,28 +5712,18 @@ gsk_mask_node_draw (GskRenderNode *node, case GSK_MASK_MODE_ALPHA: break; case GSK_MASK_MODE_INVERTED_ALPHA: - graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, -1 }); - graphene_vec4_init (&color_offset, 0, 0, 0, 1); - apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, FALSE); + graphene_matrix_init_from_float (&color_matrix, (float[]){ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + -1, -1, -1, -1 }); + graphene_vec4_init (&color_offset, 1, 1, 1, 1); + apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset); break; case GSK_MASK_MODE_LUMINANCE: - graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, 0.2126, - 0, 1, 0, 0.7152, - 0, 0, 1, 0.0722, - 0, 0, 0, 0 }); - graphene_vec4_init (&color_offset, 0, 0, 0, 0); - apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, TRUE); + apply_luminance_to_pattern (mask_pattern, FALSE); break; case GSK_MASK_MODE_INVERTED_LUMINANCE: - graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, -0.2126, - 0, 1, 0, -0.7152, - 0, 0, 1, -0.0722, - 0, 0, 0, 0 }); - graphene_vec4_init (&color_offset, 0, 0, 0, 1); - apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, TRUE); + apply_luminance_to_pattern (mask_pattern, TRUE); break; default: g_assert_not_reached (); diff --git a/testsuite/gsk/compare/mask-modes-with-alpha.node b/testsuite/gsk/compare/mask-modes-with-alpha.node new file mode 100644 index 0000000000..b40fd82bab --- /dev/null +++ b/testsuite/gsk/compare/mask-modes-with-alpha.node @@ -0,0 +1,43 @@ +mask { + source: color { + bounds: 0 0 50 50; + color: rgb(255,0,0); + } + mask: color { + bounds: 0 0 50 50; + color: rgba(204,204,204,0.666667); + } +} +mask { + mode: luminance; + source: color { + bounds: 50 0 50 50; + color: rgb(255,0,0); + } + mask: color { + bounds: 50 0 50 50; + color: rgba(204,204,204,0.666667); + } +} +mask { + mode: inverted-alpha; + source: color { + bounds: 0 50 50 50; + color: rgb(255,0,0); + } + mask: color { + bounds: 0 50 50 50; + color: rgba(204,204,204,0.666667); + } +} +mask { + mode: inverted-luminance; + source: color { + bounds: 50 50 50 50; + color: rgb(255,0,0); + } + mask: color { + bounds: 50 50 50 50; + color: rgba(204,204,204,0.666667); + } +} diff --git a/testsuite/gsk/compare/mask-modes-with-alpha.png b/testsuite/gsk/compare/mask-modes-with-alpha.png new file mode 100644 index 0000000000..b376da993c Binary files /dev/null and b/testsuite/gsk/compare/mask-modes-with-alpha.png differ diff --git a/testsuite/gsk/compare/mask-modes.png b/testsuite/gsk/compare/mask-modes.png index 148fbf887b..ee2f59e1b0 100644 Binary files a/testsuite/gsk/compare/mask-modes.png and b/testsuite/gsk/compare/mask-modes.png differ diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index 1a57cfa3ad..9317e3a3e1 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -66,6 +66,7 @@ compare_render_tests = [ 'issue-3615', 'mask', 'mask-modes', + 'mask-modes-with-alpha', 'nested-rounded-clips', 'opacity_clip', 'opacity-overdraw',