Don't put an off-by-one n_stops into cairo_shader_op_t. (_cairo_shader_op_find_color_stops): Put search for two color stops containing a given offset into its own function. Handle the case of before first and after last stop by returning the nearest stop twice. (_cairo_pattern_calc_color_at_pixel): Handle case of no color stops by returning a transparent pixel.

This commit is contained in:
Carl Worth 2005-02-25 12:52:47 +00:00
parent 8ad3ab22e4
commit 1a043bbf26
4 changed files with 131 additions and 64 deletions

View file

@ -1,3 +1,14 @@
2005-02-25 Carl Worth <cworth@cworth.org>
* src/cairo_pattern.c (_cairo_pattern_shader_init): Don't put an
off-by-one n_stops into cairo_shader_op_t.
(_cairo_shader_op_find_color_stops): Put search for two color
stops containing a given offset into its own function. Handle the
case of before first and after last stop by returning the nearest
stop twice.
(_cairo_pattern_calc_color_at_pixel): Handle case of no color
stops by returning a transparent pixel.
2005-02-24 Owen Taylor <otaylor@redhat.com>
* src/cairo_win32_surface.c: Remove a left-over debug printf.

View file

@ -428,9 +428,7 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern,
cairo_shader_op_t *op)
{
op->stops = pattern->stops;
op->n_stops = pattern->n_stops - 1;
op->min_offset = pattern->stops[0].offset;
op->max_offset = pattern->stops[op->n_stops].offset;
op->n_stops = pattern->n_stops;
op->extend = pattern->extend;
switch (pattern->filter) {
@ -449,12 +447,52 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern,
}
}
/* Find two color stops bounding the given offset. If the given offset
* is before the first or after the last stop offset, the nearest
* offset is returned twice.
*/
static void
_cairo_shader_op_find_color_stops (cairo_shader_op_t *op,
cairo_fixed_t offset,
cairo_color_stop_t *stops[2])
{
int i;
/* Before first stop. */
if (offset <= op->stops[0].offset) {
stops[0] = &op->stops[0];
stops[1] = &op->stops[0];
return;
}
/* Between two stops. */
for (i = 0; i < op->n_stops - 1; i++) {
if (offset <= op->stops[i + 1].offset) {
stops[0] = &op->stops[i];
stops[1] = &op->stops[i + 1];
return;
}
}
/* After last stop. */
stops[0] = &op->stops[op->n_stops - 1];
stops[1] = &op->stops[op->n_stops - 1];
}
void
_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
cairo_fixed_t factor,
int *pixel)
{
int i;
cairo_color_stop_t *stops[2];
/* A gradient with no color stops is just transparent. (It'd be
smart to catch this no-op much higher in the stack too.)
*/
if (op->n_stops == 0) {
*pixel = 0;
return;
}
switch (op->extend) {
case CAIRO_EXTEND_REPEAT:
@ -472,35 +510,26 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
break;
}
if (factor < op->min_offset)
factor = op->min_offset;
else if (factor > op->max_offset)
factor = op->max_offset;
for (i = 0; i < op->n_stops; i++) {
if (factor <= op->stops[i + 1].offset) {
_cairo_shader_op_find_color_stops (op, factor, stops);
/* take offset as new 0 of coordinate system */
factor -= stops[0]->offset;
/* take offset as new 0 of coordinate system */
factor -= op->stops[i].offset;
/* difference between two offsets == 0, abrubt change */
if (stops[1]->scale)
factor = ((cairo_fixed_48_16_t) factor << 16) /
stops[1]->scale;
op->shader_function (stops[0]->color_char,
stops[1]->color_char,
factor, pixel);
/* difference between two offsets == 0, abrubt change */
if (op->stops[i + 1].scale)
factor = ((cairo_fixed_48_16_t) factor << 16) /
op->stops[i + 1].scale;
op->shader_function (op->stops[i].color_char,
op->stops[i + 1].color_char,
factor, pixel);
/* multiply alpha */
if (((unsigned char) (*pixel >> 24)) != 0xff) {
*pixel = (*pixel & 0xff000000) |
(MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
(MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
(MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
}
break;
}
/* multiply alpha */
if (((unsigned char) (*pixel >> 24)) != 0xff) {
*pixel = (*pixel & 0xff000000) |
(MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
(MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
(MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
}
}

View file

@ -428,9 +428,7 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern,
cairo_shader_op_t *op)
{
op->stops = pattern->stops;
op->n_stops = pattern->n_stops - 1;
op->min_offset = pattern->stops[0].offset;
op->max_offset = pattern->stops[op->n_stops].offset;
op->n_stops = pattern->n_stops;
op->extend = pattern->extend;
switch (pattern->filter) {
@ -449,12 +447,52 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern,
}
}
/* Find two color stops bounding the given offset. If the given offset
* is before the first or after the last stop offset, the nearest
* offset is returned twice.
*/
static void
_cairo_shader_op_find_color_stops (cairo_shader_op_t *op,
cairo_fixed_t offset,
cairo_color_stop_t *stops[2])
{
int i;
/* Before first stop. */
if (offset <= op->stops[0].offset) {
stops[0] = &op->stops[0];
stops[1] = &op->stops[0];
return;
}
/* Between two stops. */
for (i = 0; i < op->n_stops - 1; i++) {
if (offset <= op->stops[i + 1].offset) {
stops[0] = &op->stops[i];
stops[1] = &op->stops[i + 1];
return;
}
}
/* After last stop. */
stops[0] = &op->stops[op->n_stops - 1];
stops[1] = &op->stops[op->n_stops - 1];
}
void
_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
cairo_fixed_t factor,
int *pixel)
{
int i;
cairo_color_stop_t *stops[2];
/* A gradient with no color stops is just transparent. (It'd be
smart to catch this no-op much higher in the stack too.)
*/
if (op->n_stops == 0) {
*pixel = 0;
return;
}
switch (op->extend) {
case CAIRO_EXTEND_REPEAT:
@ -472,35 +510,26 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
break;
}
if (factor < op->min_offset)
factor = op->min_offset;
else if (factor > op->max_offset)
factor = op->max_offset;
for (i = 0; i < op->n_stops; i++) {
if (factor <= op->stops[i + 1].offset) {
_cairo_shader_op_find_color_stops (op, factor, stops);
/* take offset as new 0 of coordinate system */
factor -= stops[0]->offset;
/* take offset as new 0 of coordinate system */
factor -= op->stops[i].offset;
/* difference between two offsets == 0, abrubt change */
if (stops[1]->scale)
factor = ((cairo_fixed_48_16_t) factor << 16) /
stops[1]->scale;
op->shader_function (stops[0]->color_char,
stops[1]->color_char,
factor, pixel);
/* difference between two offsets == 0, abrubt change */
if (op->stops[i + 1].scale)
factor = ((cairo_fixed_48_16_t) factor << 16) /
op->stops[i + 1].scale;
op->shader_function (op->stops[i].color_char,
op->stops[i + 1].color_char,
factor, pixel);
/* multiply alpha */
if (((unsigned char) (*pixel >> 24)) != 0xff) {
*pixel = (*pixel & 0xff000000) |
(MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
(MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
(MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
}
break;
}
/* multiply alpha */
if (((unsigned char) (*pixel >> 24)) != 0xff) {
*pixel = (*pixel & 0xff000000) |
(MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
(MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
(MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
}
}

View file

@ -743,8 +743,6 @@ typedef void (*cairo_shader_function_t) (unsigned char *color0,
typedef struct _cairo_shader_op {
cairo_color_stop_t *stops;
int n_stops;
cairo_fixed_t min_offset;
cairo_fixed_t max_offset;
cairo_extend_t extend;
cairo_shader_function_t shader_function;
} cairo_shader_op_t;