gl: fix gradient color generation where two stops have same offset
"Henry (Yu) Song - SISA" <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <3955FA337689574EB32F94B12A7E6E9E16364AD5@sisaex01sj> |
Hi, Chris Based on your comments, I am re-working the patch. The first patch is about fixing gradient color generation when multiple stops have a same offset but different color. This patch brings test case linear-gradient-large closer to reference image Thanks Henry From 29f4412c0a2454c36828b4dce826d9f29e6b0739 Mon Sep 17 00:00:00 2001 From: Henry Song <[email protected]> Date: Wed, 25 Jul 2012 15:34:52 -0700 Subject: [PATCH] gl: fix gradient color generation for GL in cases where there are stops that have same offset but different color. bring test case: linear-gradient-large closer to reference image --- src/cairo-gl-gradient.c | 51 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c index ffb5468..a66f26d 100644 --- a/src/cairo-gl-gradient.c +++ b/src/cairo-gl-gradient.c @@ -44,6 +44,7 @@ #include "cairo-gl-gradient-private.h" #include "cairo-gl-private.h" +#define OFFSET_TOLERANCE 0.00001 static int _cairo_gl_gradient_sample_width (unsigned int n_stops, @@ -57,9 +58,10 @@ _cairo_gl_gradient_sample_width (unsigned int n_stops, double dx = stops[n].offset - stops[n-1].offset; double delta, max; int ramp; - + + /* in case two stops offsets are same, and colors for different. */ if (dx == 0) - continue; + dx = 0.01; max = stops[n].color.red - stops[n-1].color.red; @@ -97,6 +99,8 @@ _cairo_gl_gradient_render (const cairo_gl_context_t *ctx, pixman_point_fixed_t p1, p2; unsigned int i; pixman_format_code_t gradient_pixman_format; + double *offset_stops; + double min_offset, max_offset; /* * Ensure that the order of the gradient's components in memory is BGRA. @@ -116,14 +120,55 @@ _cairo_gl_gradient_render (const cairo_gl_context_t *ctx, return _cairo_error (CAIRO_STATUS_NO_MEMORY); } + /* due to a "bug" in pixman, when there are two stops that have + * a same offset, pixman always uses the right side of the offset + * color. This causes problem in the following situation: + * + * two stops (0, 1, 1, 1, 1) and (0, 0, 0, 0, 1) - both offset at 0, + * pixman picks the back color, the correct color should be white. + * + * To fix this, we need to increment the second offset a little. + * however, if these two offset are at 1, then we should decrement + * the first offset. This implementation assumes the stops are in + * ascending order + */ + offset_stops = _cairo_malloc_ab (n_stops, sizeof (double)); + min_offset = stops[0].offset; + max_offset = stops[n_stops - 1].offset; + offset_stops[0] = stops[0].offset; + /* from left to right, increment offset if two stops have same offset */ + for (i = 1; i < n_stops; i++) { + if (offset_stops[i-1] == stops[i].offset) { + if (stops[i].offset == max_offset || + stops[i].offset >= max_offset - OFFSET_TOLERANCE) + offset_stops[i] = stops[i].offset; + else + offset_stops[i] = stops[i].offset + OFFSET_TOLERANCE; + } + else + offset_stops[i] = stops[i].offset; + } + /* from right to left */ + i = n_stops - 1; + while (i != 0) { + if (offset_stops[i-1] == offset_stops[i]) { + if (offset_stops[i] != min_offset && + offset_stops[i] >= min_offset + OFFSET_TOLERANCE) + offset_stops[i] -= OFFSET_TOLERANCE; + } + i--; + } + for (i = 0; i < n_stops; i++) { - pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset); + pixman_stops[i].x = _cairo_fixed_16_16_from_double (offset_stops[i]); pixman_stops[i].color.red = stops[i].color.red_short; pixman_stops[i].color.green = stops[i].color.green_short; pixman_stops[i].color.blue = stops[i].color.blue_short; pixman_stops[i].color.alpha = stops[i].color.alpha_short; } + free (offset_stops); + p1.x = _cairo_fixed_16_16_from_double (0.5); p1.y = 0; p2.x = _cairo_fixed_16_16_from_double (width - 0.5); -- 1.7.9.5 -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo