From: Benjamin Otte Date: Thu, 7 Sep 2023 14:02:09 +0000 (+0200) Subject: rendernode: Fix Cairo rendering of repeating gradients X-Git-Tag: archive/raspbian/4.12.4+ds-3+rpi1^2~21^2~2^2~28 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=552a7dc3080acdf1ad3b6eed96f2af984bd9715f;p=gtk4.git rendernode: Fix Cairo rendering of repeating gradients Cairo and the GL renderer have a different idea of how to handle transitioning of colors outside the defined range. Consider these stops: black 50%, white 50% What color is at 0%? Cairo would transition between the last and first stop, ie it'd do a white-to-black transition and end up at rgb(0.5,0.5,0.5) at 0%. GL would behave as it would for non-repeating gradients and use black for the range [0%..50%] and white for [50%..100%]. The web would rescale the range so the first stop would be at 0% and the last stop would be at 100%, so this gradient would be illegal. Considering that it's possible for code to transition between the different behaviors by adding explicit stops at 0%/100%, I could choose any method. So I chose the simplest one, which is what the GL renderer does and which treats repeating and non-repeating gradients the same. Tests attached. --- diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 2758dff2a6..08bdc58e47 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -245,6 +245,13 @@ gsk_linear_gradient_node_draw (GskRenderNode *node, if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE) cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + if (self->stops[0].offset > 0.0) + cairo_pattern_add_color_stop_rgba (pattern, + 0.0, + self->stops[0].color.red, + self->stops[0].color.green, + self->stops[0].color.blue, + self->stops[0].color.alpha); for (i = 0; i < self->n_stops; i++) { cairo_pattern_add_color_stop_rgba (pattern, @@ -254,6 +261,13 @@ gsk_linear_gradient_node_draw (GskRenderNode *node, self->stops[i].color.blue, self->stops[i].color.alpha); } + if (self->stops[self->n_stops-1].offset < 1.0) + cairo_pattern_add_color_stop_rgba (pattern, + 1.0, + self->stops[self->n_stops-1].color.red, + self->stops[self->n_stops-1].color.green, + self->stops[self->n_stops-1].color.blue, + self->stops[self->n_stops-1].color.alpha); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); @@ -559,13 +573,29 @@ gsk_radial_gradient_node_draw (GskRenderNode *node, else cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); + if (self->stops[0].offset > 0.0) + cairo_pattern_add_color_stop_rgba (pattern, + 0.0, + self->stops[0].color.red, + self->stops[0].color.green, + self->stops[0].color.blue, + self->stops[0].color.alpha); for (i = 0; i < self->n_stops; i++) + { + cairo_pattern_add_color_stop_rgba (pattern, + self->stops[i].offset, + self->stops[i].color.red, + self->stops[i].color.green, + self->stops[i].color.blue, + self->stops[i].color.alpha); + } + if (self->stops[self->n_stops-1].offset < 1.0) cairo_pattern_add_color_stop_rgba (pattern, - self->stops[i].offset, - self->stops[i].color.red, - self->stops[i].color.green, - self->stops[i].color.blue, - self->stops[i].color.alpha); + 1.0, + self->stops[self->n_stops-1].color.red, + self->stops[self->n_stops-1].color.green, + self->stops[self->n_stops-1].color.blue, + self->stops[self->n_stops-1].color.alpha); gsk_cairo_rectangle (cr, &node->bounds); cairo_translate (cr, self->center.x, self->center.y); diff --git a/testsuite/gsk/compare/repeating-linear-gradient-edge-colors.node b/testsuite/gsk/compare/repeating-linear-gradient-edge-colors.node new file mode 100644 index 0000000000..06ffe1bcef --- /dev/null +++ b/testsuite/gsk/compare/repeating-linear-gradient-edge-colors.node @@ -0,0 +1,6 @@ +repeating-linear-gradient { + bounds: 0 0 50 50; + start: 0 0; + end: 0 50; + stops: 0.5 rgb(255,0,0), 0.5 rgb(0,255,0); +} diff --git a/testsuite/gsk/compare/repeating-linear-gradient-edge-colors.png b/testsuite/gsk/compare/repeating-linear-gradient-edge-colors.png new file mode 100644 index 0000000000..2ac3fd1e44 Binary files /dev/null and b/testsuite/gsk/compare/repeating-linear-gradient-edge-colors.png differ diff --git a/testsuite/gsk/compare/repeating-radial-gradient-edge-colors.node b/testsuite/gsk/compare/repeating-radial-gradient-edge-colors.node new file mode 100644 index 0000000000..10db7dc2ad --- /dev/null +++ b/testsuite/gsk/compare/repeating-radial-gradient-edge-colors.node @@ -0,0 +1,10 @@ +clip { + clip: -25 -25 50 50; + child: repeating-radial-gradient { + bounds: -100 -100 200 200; + center: 0 0; + hradius: 100; + vradius: 100; + stops: 0.5 rgb(255,0,0), 0.5 rgb(0,255,0); + } +} diff --git a/testsuite/gsk/compare/repeating-radial-gradient-edge-colors.png b/testsuite/gsk/compare/repeating-radial-gradient-edge-colors.png new file mode 100644 index 0000000000..9a5764a9b2 Binary files /dev/null and b/testsuite/gsk/compare/repeating-radial-gradient-edge-colors.png differ diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index e48e9a3a45..c0facb5a12 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -78,6 +78,8 @@ compare_render_tests = [ 'outset_shadow_rounded_top', 'outset_shadow_simple', 'repeat', + 'repeating-linear-gradient-edge-colors', + 'repeating-radial-gradient-edge-colors', 'repeat-no-repeat', 'repeat-empty-child-bounds', 'repeat-negative-coords',