mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-03 15:10:17 +01:00
pattern: Simplify degenerate linear pattern to solid colors
Degenerate linear patterns are considered clear if they have EXTEND_NONE, the average of the first and the last stop if they are EXTEND_PAD, the weighted average of the stops (based on the size of the interpolation range in which they are active, just like integrating over the whole interpolation range and taking the average) if they are EXTEND_REPEAT or EXTEND_REFLECT. Fixes degenerate-linear-gradient
This commit is contained in:
parent
d54a5a9fc9
commit
ae2b7b13cd
2 changed files with 117 additions and 2 deletions
|
|
@ -1816,6 +1816,116 @@ _gradient_is_clear (const cairo_gradient_pattern_t *gradient,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gradient_color_average (const cairo_gradient_pattern_t *gradient,
|
||||
cairo_color_t *color)
|
||||
{
|
||||
double delta0, delta1;
|
||||
double r, g, b, a;
|
||||
unsigned int i, start = 1, end;
|
||||
|
||||
assert (gradient->n_stops > 0);
|
||||
assert (gradient->base.extend != CAIRO_EXTEND_NONE);
|
||||
|
||||
if (gradient->n_stops == 1) {
|
||||
_cairo_color_init_rgba (color,
|
||||
gradient->stops[0].color.red,
|
||||
gradient->stops[0].color.green,
|
||||
gradient->stops[0].color.blue,
|
||||
gradient->stops[0].color.alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
end = gradient->n_stops - 1;
|
||||
|
||||
switch (gradient->base.extend) {
|
||||
case CAIRO_EXTEND_REPEAT:
|
||||
/*
|
||||
* Sa, Sb and Sy, Sz are the first two and last two stops respectively.
|
||||
* The weight of the first and last stop can be computed as the area of
|
||||
* the following triangles (taken with height 1, since the whole [0-1]
|
||||
* will have total weight 1 this way): b*h/2
|
||||
*
|
||||
* + +
|
||||
* / |\ / | \
|
||||
* / | \ / | \
|
||||
* / | \ / | \
|
||||
* ~~~~~+---+---+---+~~~~~~~+-------+---+---+~~~~~
|
||||
* -1+Sz 0 Sa Sb Sy Sz 1 1+Sa
|
||||
*
|
||||
* For the first stop: (Sb-(-1+Sz)/2 = (1+Sb-Sz)/2
|
||||
* For the last stop: ((1+Sa)-Sy)/2 = (1+Sa-Sy)/2
|
||||
* Halving the result is done after summing up all the areas.
|
||||
*/
|
||||
delta0 = 1.0 + gradient->stops[1].offset - gradient->stops[end].offset;
|
||||
delta1 = 1.0 + gradient->stops[0].offset - gradient->stops[end-1].offset;
|
||||
break;
|
||||
|
||||
case CAIRO_EXTEND_REFLECT:
|
||||
/*
|
||||
* Sa, Sb and Sy, Sz are the first two and last two stops respectively.
|
||||
* The weight of the first and last stop can be computed as the area of
|
||||
* the following trapezoids (taken with height 1, since the whole [0-1]
|
||||
* will have total weight 1 this way): (b+B)*h/2
|
||||
*
|
||||
* +-------+ +---+
|
||||
* | |\ / | |
|
||||
* | | \ / | |
|
||||
* | | \ / | |
|
||||
* +-------+---+~~~~~~~+-------+---+
|
||||
* 0 Sa Sb Sy Sz 1
|
||||
*
|
||||
* For the first stop: (Sa+Sb)/2
|
||||
* For the last stop: ((1-Sz) + (1-Sy))/2 = (2-Sy-Sz)/2
|
||||
* Halving the result is done after summing up all the areas.
|
||||
*/
|
||||
delta0 = gradient->stops[0].offset + gradient->stops[1].offset;
|
||||
delta1 = 2.0 - gradient->stops[end-1].offset - gradient->stops[end].offset;
|
||||
break;
|
||||
|
||||
case CAIRO_EXTEND_PAD:
|
||||
/* PAD is computed as the average of the first and last stop:
|
||||
* - take both of them with weight 1 (they will be halved
|
||||
* after the whole sum has been computed).
|
||||
* - avoid summing any of the inner stops.
|
||||
*/
|
||||
delta0 = delta1 = 1.0;
|
||||
start = end;
|
||||
break;
|
||||
|
||||
case CAIRO_EXTEND_NONE:
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
_cairo_color_init_rgba (color, 0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
r = delta0 * gradient->stops[0].color.red;
|
||||
g = delta0 * gradient->stops[0].color.green;
|
||||
b = delta0 * gradient->stops[0].color.blue;
|
||||
a = delta0 * gradient->stops[0].color.alpha;
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
/* Inner stops weight is the same as the area of the triangle they influence
|
||||
* (which goes from the stop before to the stop after), again with height 1
|
||||
* since the whole must sum up to 1: b*h/2
|
||||
* Halving is done after the whole sum has been computed.
|
||||
*/
|
||||
double delta = gradient->stops[i+1].offset - gradient->stops[i-1].offset;
|
||||
r += delta * gradient->stops[i].color.red;
|
||||
g += delta * gradient->stops[i].color.green;
|
||||
b += delta * gradient->stops[i].color.blue;
|
||||
a += delta * gradient->stops[i].color.alpha;
|
||||
}
|
||||
|
||||
r += delta1 * gradient->stops[end].color.red;
|
||||
g += delta1 * gradient->stops[end].color.green;
|
||||
b += delta1 * gradient->stops[end].color.blue;
|
||||
a += delta1 * gradient->stops[end].color.alpha;
|
||||
|
||||
_cairo_color_init_rgba (color, r * .5, g * .5, b * .5, a * .5);
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_gradient_pattern_is_solid
|
||||
*
|
||||
|
|
@ -1838,10 +1948,15 @@ _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
|
|||
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
|
||||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
|
||||
|
||||
/* TODO: radial, degenerate linear */
|
||||
/* TODO: radial */
|
||||
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
|
||||
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
|
||||
if (_linear_pattern_is_degenerate (linear)) {
|
||||
_gradient_color_average (gradient, color);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
|
||||
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
|
||||
double t[2];
|
||||
|
||||
/* We already know that the pattern is not clear, thus if some
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 322 B |
Loading…
Add table
Reference in a new issue