diff options
author | Andrea Canciani <ranma42@gmail.com> | 2011-12-24 23:02:33 +0100 |
---|---|---|
committer | Andrea Canciani <ranma42@gmail.com> | 2011-12-24 23:03:13 +0100 |
commit | 071ca020e234374194235c426e6559edc86f246c (patch) | |
tree | 8f4fa02c89a364ec51a95b249aac046a0240bb8a | |
parent | f70764d96a2063a933fb436abd43575de3e95c68 (diff) |
wip
-rw-r--r-- | pixman/pixman-gradient-walker.c | 74 | ||||
-rw-r--r-- | pixman/pixman-image.c | 126 | ||||
-rw-r--r-- | pixman/pixman-private.h | 3 |
3 files changed, 122 insertions, 81 deletions
diff --git a/pixman/pixman-gradient-walker.c b/pixman/pixman-gradient-walker.c index d0b55e7..6c7afce 100644 --- a/pixman/pixman-gradient-walker.c +++ b/pixman/pixman-gradient-walker.c @@ -28,14 +28,36 @@ #endif #include "pixman-private.h" +static int32_t +_pixman_gradient_repeat_to_mask (pixman_repeat_t repeat) +{ + switch (repeat) + { + case PIXMAN_REPEAT_NORMAL: + return 0xffff; + + case PIXMAN_REPEAT_REFLECT: + return 0x1ffff; + + case PIXMAN_REPEAT_NONE: + case PIXMAN_REPEAT_PAD: + return 0xffffffff; + } + + return 0; +} + void _pixman_gradient_walker_init (pixman_gradient_walker_t *walker, gradient_t * gradient, pixman_repeat_t repeat) { walker->num_stops = gradient->n_stops; - walker->stops = gradient->stops; - walker->repeat = repeat; + walker->stops = gradient->stops + 2; + walker->mask = _pixman_gradient_repeat_to_mask(repeat); + + if (PIXMAN_REPEAT_REFLECT) + walker->num_stops *= 2; /* The remaining part of the structure should be initalized by the * reset function. Set left < right to trigger a reset as soon as @@ -53,58 +75,22 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, int n, count = walker->num_stops; pixman_gradient_stop_t *stops = walker->stops; - if (walker->repeat == PIXMAN_REPEAT_NORMAL) - { - x = (int32_t)pos & 0xffff; - } - else if (walker->repeat == PIXMAN_REPEAT_REFLECT) - { - x = (int32_t)pos & 0xffff; - if ((int32_t)pos & 0x10000) - x = 0x10000 - x; - } - else - { - x = pos; - } - + x = (int32_t)pos & walker->mask; + for (n = 0; n < count; n++) { if (x < stops[n].x) break; } - + left_x = stops[n - 1].x; left_c = &stops[n - 1].color; - + right_x = stops[n].x; right_c = &stops[n].color; - if (walker->repeat == PIXMAN_REPEAT_NORMAL) - { - left_x += (pos - x); - right_x += (pos - x); - } - else if (walker->repeat == PIXMAN_REPEAT_REFLECT) - { - if ((int32_t)pos & 0x10000) - { - pixman_color_t *tmp_c; - int32_t tmp_x; - - tmp_x = 0x10000 - right_x; - right_x = 0x10000 - left_x; - left_x = tmp_x; - - tmp_c = right_c; - right_c = left_c; - left_c = tmp_c; - - x = 0x10000 - x; - } - left_x += (pos - x); - right_x += (pos - x); - } + left_x += (pos - x); + right_x += (pos - x); walker->left_x = left_x; walker->right_x = right_x; diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c index 913853c..9da934d 100644 --- a/pixman/pixman-image.c +++ b/pixman/pixman-image.c @@ -37,40 +37,97 @@ 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]); + int i, n = gradient->n_stops; + pixman_gradient_stop_t *stops = gradient->stops + 2; + pixman_gradient_stop_t *first = &stops[0]; + pixman_gradient_stop_t *last = &stops[n - 1]; 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; + /* Add a transparent black stop right before the first stop, + * at the same offset */ + first[-1].x = first->x; + first[-1].color = transparent_black; + + /* Add a transparent black stop right after the last stop, at + * the same offset */ + last[1].x = last->x; + last[1].color = transparent_black; + + /* Complete adding stops at infinity as per PAD */ + first--; + last++; + + /* fall-through */ + + case PIXMAN_REPEAT_PAD: + /* Add a stop with the same color as the first stop at -INF */ + first[-1].x = INT32_MIN; + first[-1].color = first->color; + + /* Add a stop with the same color as the last stop at +INF */ + last[1].x = INT32_MAX; + last[1].color = last->color; + + /* + * The valid stop range is now [first - 1, last + 1]. + * + * It is possible to use these stops to interpolate in the + * offset range [INT32_MIN to INT32_MAX). + */ + 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; + /* Add a stop with the same color as the last stop at its + * offset - 1 (the repeat period). */ + first[-1].x = last->x - pixman_fixed_1; + first[-1].color = last->color; + + /* Add a stop with the same color as the first stop at its + * offset + 1 (the repeat period). */ + last[1].x = first->x + pixman_fixed_1; + last[1].color = first->color; + + /* + * The valid stop range is now [first - 1, last + 1]. + * + * It is possible to use these stops to interpolate in the + * offset range [last->x - 1.0, first->x + 1). + * + * Assuming last->x <= 1.0 && first->x >= 0.0, this range is + * guaranteed to contain [0,1). + */ + 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; + /* Add a stop with the same color as the first stop at -offset + * (i.e. the first stop, reflected around 0). */ + first[-1].x = -first->x; + first[-1].color = first->color; + last += n; + + /* Reflect all the stops (including the newly added one) + * around 1. */ + for (i = -1; i < n; i++) + { + last[-i].x = pixman_int_to_fixed (2) - first[i].x; + last[-i].color = first[i].color; + } + + /* + * The valid stop range is now [first - 1, last + 1]. + * + * It is possible to use these stops to interpolate in the + * offset range [-first->x, 2 + first->x). + * + * Assuming first->x >= 0.0, this range is guaranteed to + * contain [0,2). + */ - case PIXMAN_REPEAT_PAD: - begin->x = INT32_MIN; - begin->color = stops[0].color; - end->x = INT32_MAX; - end->color = stops[n - 1].color; break; } } @@ -82,23 +139,20 @@ _pixman_init_gradient (gradient_t * gradient, { return_val_if_fail (n_stops > 0, FALSE); - /* 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. + /* + * REPEAT_NONE needs 4 extra stops. + * REPEAT_NORMAL needs 2 extra stops. + * REPEAT_REFLECT needs 2 times the original stops + 2. + * REPEAT_PAD needs 2 extra stops. + * We allocate 2*n_stops + 4 to keep things as simple as possible. */ - gradient->stops = - pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t)); + gradient->stops = pixman_malloc_ab (n_stops + 2, + 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)); + memcpy (gradient->stops + 2, stops, + n_stops * sizeof (pixman_gradient_stop_t)); gradient->n_stops = n_stops; gradient->common.property_changed = gradient_property_changed; @@ -158,7 +212,7 @@ _pixman_image_fini (pixman_image_t *image) if (image->gradient.stops) { /* See _pixman_init_gradient() for an explanation of the - 1 */ - free (image->gradient.stops - 1); + free (image->gradient.stops); } /* This will trigger if someone adds a property_changed diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index a41d46c..cf6767f 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -107,6 +107,7 @@ struct gradient image_common_t common; int n_stops; pixman_gradient_stop_t *stops; + pixman_gradient_stop_t *orig_stops; }; struct linear_gradient @@ -305,7 +306,7 @@ typedef struct pixman_gradient_stop_t *stops; int num_stops; - pixman_repeat_t repeat; + uint32_t mask; } pixman_gradient_walker_t; void |