From: Søren Sandmann Pedersen Date: Fri, 14 Oct 2011 13:02:14 +0000 (-0400) Subject: Use sentinels instead of special casing first and last stops X-Git-Tag: pixman-0.23.8~2^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2d0da8ab8d8fef60ed1bbb9d6b75f66577c3f85d;p=platform%2Fupstream%2Fpixman.git Use sentinels instead of special casing first and last stops When storing the gradient stops internally, allocate two more stops, one before the beginning of the stop list and one after the end. Initialize those stops based on the repeat property of the gradient. This allows gradient_walker_reset() to be simplified because it can now simply pick the two closest stops to the position without special casing the first and last stops. --- diff --git a/pixman/pixman-gradient-walker.c b/pixman/pixman-gradient-walker.c index 53d0b30..3848247 100644 --- a/pixman/pixman-gradient-walker.c +++ b/pixman/pixman-gradient-walker.c @@ -56,8 +56,6 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, int n, count = walker->num_stops; pixman_gradient_stop_t *stops = walker->stops; - static const pixman_color_t transparent_black = { 0, 0, 0, 0 }; - switch (walker->repeat) { case PIXMAN_REPEAT_NORMAL: @@ -68,27 +66,12 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, break; } - if (n == 0) - { - left_x = stops[count - 1].x - 0x10000; - left_c = &stops[count - 1].color; - } - else - { - left_x = stops[n - 1].x; - left_c = &stops[n - 1].color; - } + left_x = stops[n - 1].x; + left_c = &stops[n - 1].color; + + right_x = stops[n].x; + right_c = &stops[n].color; - if (n == count) - { - right_x = stops[0].x + 0x10000; - right_c = &stops[0].color; - } - else - { - right_x = stops[n].x; - right_c = &stops[n].color; - } left_x += (pos - x); right_x += (pos - x); break; @@ -100,27 +83,11 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, break; } - if (n == 0) - { - left_x = INT32_MIN; - left_c = &stops[0].color; - } - else - { - left_x = stops[n - 1].x; - left_c = &stops[n - 1].color; - } + left_x = stops[n - 1].x; + left_c = &stops[n - 1].color; - if (n == count) - { - right_x = INT32_MAX; - right_c = &stops[n - 1].color; - } - else - { - right_x = stops[n].x; - right_c = &stops[n].color; - } + right_x = stops[n].x; + right_c = &stops[n].color; break; case PIXMAN_REPEAT_REFLECT: @@ -134,27 +101,11 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, break; } - if (n == 0) - { - left_x = -stops[0].x; - left_c = &stops[0].color; - } - else - { - left_x = stops[n - 1].x; - left_c = &stops[n - 1].color; - } + left_x = stops[n - 1].x; + left_c = &stops[n - 1].color; - if (n == count) - { - right_x = 0x20000 - stops[n - 1].x; - right_c = &stops[n - 1].color; - } - else - { - right_x = stops[n].x; - right_c = &stops[n].color; - } + right_x = stops[n].x; + right_c = &stops[n].color; if ((int32_t)pos & 0x10000) { @@ -182,25 +133,11 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, break; } - if (n == 0) - { - left_x = INT32_MIN; - right_x = stops[0].x; - left_c = right_c = (pixman_color_t*) &transparent_black; - } - else if (n == count) - { - left_x = stops[n - 1].x; - right_x = INT32_MAX; - left_c = right_c = (pixman_color_t*) &transparent_black; - } - else - { - left_x = stops[n - 1].x; - right_x = stops[n].x; - left_c = &stops[n - 1].color; - right_c = &stops[n].color; - } + left_x = stops[n - 1].x; + left_c = &stops[n - 1].color; + + right_x = stops[n].x; + right_c = &stops[n].color; } walker->left_x = left_x; diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c index afe587f..09d7cbc 100644 --- a/pixman/pixman-image.c +++ b/pixman/pixman-image.c @@ -31,6 +31,50 @@ #include "pixman-private.h" +static const pixman_color_t transparent_black = { 0, 0, 0, 0 }; + +static void +gradient_property_changed (pixman_image_t *image) +{ + gradient_t *gradient = &image->gradient; + int n = gradient->n_stops; + pixman_gradient_stop_t *stops = gradient->stops; + pixman_gradient_stop_t *begin = &(gradient->stops[-1]); + pixman_gradient_stop_t *end = &(gradient->stops[n]); + + switch (gradient->common.repeat) + { + default: + case PIXMAN_REPEAT_NONE: + begin->x = INT32_MIN; + begin->color = transparent_black; + end->x = INT32_MAX; + end->color = transparent_black; + break; + + case PIXMAN_REPEAT_NORMAL: + begin->x = stops[n - 1].x - pixman_fixed_1; + begin->color = stops[n - 1].color; + end->x = stops[0].x + pixman_fixed_1; + end->color = stops[0].color; + break; + + case PIXMAN_REPEAT_REFLECT: + begin->x = - stops[0].x; + begin->color = stops[0].color; + end->x = pixman_int_to_fixed (2) - stops[n - 1].x; + end->color = stops[n - 1].color; + break; + + case PIXMAN_REPEAT_PAD: + begin->x = INT32_MIN; + begin->color = stops[0].color; + end->x = INT32_MAX; + end->color = stops[n - 1].color; + break; + } +} + pixman_bool_t _pixman_init_gradient (gradient_t * gradient, const pixman_gradient_stop_t *stops, @@ -38,14 +82,27 @@ _pixman_init_gradient (gradient_t * gradient, { return_val_if_fail (n_stops > 0, FALSE); - gradient->stops = pixman_malloc_ab (n_stops, sizeof (pixman_gradient_stop_t)); + /* We allocate two extra stops, one before the beginning of the stop list, + * and one after the end. These stops are initialized to whatever color + * would be used for positions outside the range of the stop list. + * + * This saves a bit of computation in the gradient walker. + * + * The pointer we store in the gradient_t struct still points to the + * first user-supplied struct, so when freeing, we will have to + * subtract one. + */ + gradient->stops = + pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t)); if (!gradient->stops) return FALSE; + gradient->stops += 1; memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t)); - gradient->n_stops = n_stops; + gradient->common.property_changed = gradient_property_changed; + return TRUE; } @@ -102,7 +159,17 @@ _pixman_image_fini (pixman_image_t *image) image->type == CONICAL) { if (image->gradient.stops) - free (image->gradient.stops); + { + /* See _pixman_init_gradient() for an explanation of the - 1 */ + free (image->gradient.stops - 1); + } + + /* This will trigger if someone adds a property_changed + * method to the linear/radial/conical gradient overwriting + * the general one. + */ + assert ( + image->common.property_changed == gradient_property_changed); } if (image->type == BITS && image->bits.free_me)