summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Canciani <ranma42@gmail.com>2011-12-24 23:02:33 +0100
committerAndrea Canciani <ranma42@gmail.com>2011-12-24 23:03:13 +0100
commit071ca020e234374194235c426e6559edc86f246c (patch)
tree8f4fa02c89a364ec51a95b249aac046a0240bb8a
parentf70764d96a2063a933fb436abd43575de3e95c68 (diff)
wip
-rw-r--r--pixman/pixman-gradient-walker.c74
-rw-r--r--pixman/pixman-image.c126
-rw-r--r--pixman/pixman-private.h3
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