summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2011-10-14 09:02:14 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2011-10-15 10:50:20 -0400
commit2d0da8ab8d8fef60ed1bbb9d6b75f66577c3f85d (patch)
tree11a5ce95bd57ee8f7102d5c7c038745342d2ea85
parent84d6ca7c891601b019d4862a556ed98b7e6fe525 (diff)
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.
-rw-r--r--pixman/pixman-gradient-walker.c99
-rw-r--r--pixman/pixman-image.c73
2 files changed, 88 insertions, 84 deletions
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)