[Pixman] [PATCH 2/3] Use sentinels instead of special casing first and last stops

Søren Sandmann sandmann at cs.au.dk
Sat Oct 15 07:57:11 PDT 2011


From: Søren Sandmann Pedersen <ssp at redhat.com>

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.
---
 pixman/pixman-gradient-walker.c |   99 +++++++--------------------------------
 pixman/pixman-image.c           |   73 +++++++++++++++++++++++++++-
 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)
-- 
1.6.0.6



More information about the Pixman mailing list