pixman: Branch 'master' - 3 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Feb 11 12:36:34 UTC 2019


 RELEASING                        |    4 
 configure.ac                     |    4 
 meson.build                      |    2 
 pixman/pixman-bits-image.c       |  414 ++++++++++++++++++++++++++++-----------
 pixman/pixman-conical-gradient.c |   36 ++-
 pixman/pixman-gradient-walker.c  |  114 ++++++++--
 pixman/pixman-inlines.h          |   25 ++
 pixman/pixman-linear-gradient.c  |   47 ++--
 pixman/pixman-private.h          |   35 +++
 pixman/pixman-radial-gradient.c  |  112 ++++++----
 10 files changed, 567 insertions(+), 226 deletions(-)

New commits:
commit 5d2cf8fc2149b9b632aafcde59734a7ea74f2b92
Author: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Date:   Mon Feb 11 13:25:14 2019 +0100

    Bump version to 0.38.0
    
    And update RELEASING for the new meson build system.
    
    Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>

diff --git a/RELEASING b/RELEASING
index 657857d..e104bda 100644
--- a/RELEASING
+++ b/RELEASING
@@ -10,8 +10,8 @@ Here are the steps to follow to create a new pixman release:
 
 	git log master...origin		(no output; note: *3* dots)
 
-2) Increment pixman_(major|minor|micro) in configure.ac according to
-   the directions in that file.
+2) Increment pixman_(major|minor|micro) in configure.ac and meson.build
+   according to the directions in those files.
 
 3) Make sure that new version works, including
 
diff --git a/configure.ac b/configure.ac
index 6f6bd7e..6efc6c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,8 +53,8 @@ AC_PREREQ([2.57])
 #
 
 m4_define([pixman_major], 0)
-m4_define([pixman_minor], 37)
-m4_define([pixman_micro], 1)
+m4_define([pixman_minor], 38)
+m4_define([pixman_micro], 0)
 
 m4_define([pixman_version],[pixman_major.pixman_minor.pixman_micro])
 
diff --git a/meson.build b/meson.build
index aaecc7b..fe77893 100644
--- a/meson.build
+++ b/meson.build
@@ -21,7 +21,7 @@
 project(
   'pixman',
   ['c'],
-  version : '0.37.1',
+  version : '0.38.0',
   license : 'MIT',
   meson_version : '>= 0.47.2',
   default_options : ['buildtype=debugoptimized'],
commit 6240ad15c67ff33f4a05831711cae23be7d51733
Author: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Date:   Thu Dec 6 15:42:26 2018 +0100

    pixman: Use maximum precision for pixman-bits-image, v2.
    
    pixman-bits-image's wide helpers first obtains the 8-bits image,
    then converts it to float. This destroys all the precision that
    the wide path was offering.
    
    Fix this by making get_pixel() take a pointer instead of returning
    a value. Floating point will fill in a argb_t, while the 8-bits path
    will fill a 32-bits ARGB value. This also requires writing a floating
    point bilinear interpolator. With this change pixman can use the full
    floating point precision internally in all paths.
    
    Changes since v1:
    - Make accum and reduce an argument to convolution functions,
      to remove duplication.
    
    Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
    Acked-by: Basile Clement <basile-pixman at clement.pm>

diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 9fb91ff..564789e 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -36,43 +36,45 @@
 #include "pixman-combine32.h"
 #include "pixman-inlines.h"
 
-static uint32_t *
-_pixman_image_get_scanline_generic_float (pixman_iter_t * iter,
-					  const uint32_t *mask)
-{
-    pixman_iter_get_scanline_t fetch_32 = iter->data;
-    uint32_t *buffer = iter->buffer;
-
-    fetch_32 (iter, NULL);
+/* Fetch functions */
 
-    pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
+static force_inline void
+fetch_pixel_no_alpha_32 (bits_image_t *image,
+			 int x, int y, pixman_bool_t check_bounds,
+			 void *out)
+{
+    uint32_t *ret = out;
 
-    return iter->buffer;
+    if (check_bounds &&
+	(x < 0 || x >= image->width || y < 0 || y >= image->height))
+	*ret = 0;
+    else
+	*ret = image->fetch_pixel_32 (image, x, y);
 }
 
-/* Fetch functions */
-
-static force_inline uint32_t
-fetch_pixel_no_alpha (bits_image_t *image,
-		      int x, int y, pixman_bool_t check_bounds)
+static force_inline void
+fetch_pixel_no_alpha_float (bits_image_t *image,
+			    int x, int y, pixman_bool_t check_bounds,
+			    void *out)
 {
+    argb_t *ret = out;
+
     if (check_bounds &&
 	(x < 0 || x >= image->width || y < 0 || y >= image->height))
-    {
-	return 0;
-    }
-
-    return image->fetch_pixel_32 (image, x, y);
+	ret->a = ret->r = ret->g = ret->b = 0.f;
+    else
+	*ret = image->fetch_pixel_float (image, x, y);
 }
 
-typedef uint32_t (* get_pixel_t) (bits_image_t *image,
-				  int x, int y, pixman_bool_t check_bounds);
+typedef void (* get_pixel_t) (bits_image_t *image,
+			      int x, int y, pixman_bool_t check_bounds, void *out);
 
-static force_inline uint32_t
+static force_inline void
 bits_image_fetch_pixel_nearest (bits_image_t   *image,
 				pixman_fixed_t  x,
 				pixman_fixed_t  y,
-				get_pixel_t	get_pixel)
+				get_pixel_t	get_pixel,
+				void	       *out)
 {
     int x0 = pixman_fixed_to_int (x - pixman_fixed_e);
     int y0 = pixman_fixed_to_int (y - pixman_fixed_e);
@@ -82,19 +84,20 @@ bits_image_fetch_pixel_nearest (bits_image_t   *image,
 	repeat (image->common.repeat, &x0, image->width);
 	repeat (image->common.repeat, &y0, image->height);
 
-	return get_pixel (image, x0, y0, FALSE);
+	get_pixel (image, x0, y0, FALSE, out);
     }
     else
     {
-	return get_pixel (image, x0, y0, TRUE);
+	get_pixel (image, x0, y0, TRUE, out);
     }
 }
 
-static force_inline uint32_t
-bits_image_fetch_pixel_bilinear (bits_image_t   *image,
-				 pixman_fixed_t  x,
-				 pixman_fixed_t  y,
-				 get_pixel_t	 get_pixel)
+static force_inline void
+bits_image_fetch_pixel_bilinear_32 (bits_image_t   *image,
+				    pixman_fixed_t  x,
+				    pixman_fixed_t  y,
+				    get_pixel_t	    get_pixel,
+				    void	   *out)
 {
     pixman_repeat_t repeat_mode = image->common.repeat;
     int width = image->width;
@@ -102,6 +105,7 @@ bits_image_fetch_pixel_bilinear (bits_image_t   *image,
     int x1, y1, x2, y2;
     uint32_t tl, tr, bl, br;
     int32_t distx, disty;
+    uint32_t *ret = out;
 
     x1 = x - pixman_fixed_1 / 2;
     y1 = y - pixman_fixed_1 / 2;
@@ -121,27 +125,140 @@ bits_image_fetch_pixel_bilinear (bits_image_t   *image,
 	repeat (repeat_mode, &x2, width);
 	repeat (repeat_mode, &y2, height);
 
-	tl = get_pixel (image, x1, y1, FALSE);
-	bl = get_pixel (image, x1, y2, FALSE);
-	tr = get_pixel (image, x2, y1, FALSE);
-	br = get_pixel (image, x2, y2, FALSE);
+	get_pixel (image, x1, y1, FALSE, &tl);
+	get_pixel (image, x2, y1, FALSE, &tr);
+	get_pixel (image, x1, y2, FALSE, &bl);
+	get_pixel (image, x2, y2, FALSE, &br);
     }
     else
     {
-	tl = get_pixel (image, x1, y1, TRUE);
-	tr = get_pixel (image, x2, y1, TRUE);
-	bl = get_pixel (image, x1, y2, TRUE);
-	br = get_pixel (image, x2, y2, TRUE);
+	get_pixel (image, x1, y1, TRUE, &tl);
+	get_pixel (image, x2, y1, TRUE, &tr);
+	get_pixel (image, x1, y2, TRUE, &bl);
+	get_pixel (image, x2, y2, TRUE, &br);
     }
 
-    return bilinear_interpolation (tl, tr, bl, br, distx, disty);
+    *ret = bilinear_interpolation (tl, tr, bl, br, distx, disty);
 }
 
-static force_inline uint32_t
+static force_inline void
+bits_image_fetch_pixel_bilinear_float (bits_image_t   *image,
+				       pixman_fixed_t  x,
+				       pixman_fixed_t  y,
+				       get_pixel_t     get_pixel,
+				       void	      *out)
+{
+    pixman_repeat_t repeat_mode = image->common.repeat;
+    int width = image->width;
+    int height = image->height;
+    int x1, y1, x2, y2;
+    argb_t tl, tr, bl, br;
+    float distx, disty;
+    argb_t *ret = out;
+
+    x1 = x - pixman_fixed_1 / 2;
+    y1 = y - pixman_fixed_1 / 2;
+
+    distx = ((float)pixman_fixed_fraction(x1)) / 65536.f;
+    disty = ((float)pixman_fixed_fraction(y1)) / 65536.f;
+
+    x1 = pixman_fixed_to_int (x1);
+    y1 = pixman_fixed_to_int (y1);
+    x2 = x1 + 1;
+    y2 = y1 + 1;
+
+    if (repeat_mode != PIXMAN_REPEAT_NONE)
+    {
+	repeat (repeat_mode, &x1, width);
+	repeat (repeat_mode, &y1, height);
+	repeat (repeat_mode, &x2, width);
+	repeat (repeat_mode, &y2, height);
+
+	get_pixel (image, x1, y1, FALSE, &tl);
+	get_pixel (image, x2, y1, FALSE, &tr);
+	get_pixel (image, x1, y2, FALSE, &bl);
+	get_pixel (image, x2, y2, FALSE, &br);
+    }
+    else
+    {
+	get_pixel (image, x1, y1, TRUE, &tl);
+	get_pixel (image, x2, y1, TRUE, &tr);
+	get_pixel (image, x1, y2, TRUE, &bl);
+	get_pixel (image, x2, y2, TRUE, &br);
+    }
+
+    *ret = bilinear_interpolation_float (tl, tr, bl, br, distx, disty);
+}
+
+static force_inline void accum_32(int *satot, int *srtot,
+				  int *sgtot, int *sbtot,
+				  const void *p, pixman_fixed_t f)
+{
+    uint32_t pixel = *(uint32_t *)p;
+
+    *srtot += (int)RED_8 (pixel) * f;
+    *sgtot += (int)GREEN_8 (pixel) * f;
+    *sbtot += (int)BLUE_8 (pixel) * f;
+    *satot += (int)ALPHA_8 (pixel) * f;
+}
+
+static force_inline void reduce_32(int satot, int srtot,
+				   int sgtot, int sbtot, void *p)
+{
+    uint32_t *ret = p;
+
+    satot = (satot + 0x8000) >> 16;
+    srtot = (srtot + 0x8000) >> 16;
+    sgtot = (sgtot + 0x8000) >> 16;
+    sbtot = (sbtot + 0x8000) >> 16;
+
+    satot = CLIP (satot, 0, 0xff);
+    srtot = CLIP (srtot, 0, 0xff);
+    sgtot = CLIP (sgtot, 0, 0xff);
+    sbtot = CLIP (sbtot, 0, 0xff);
+
+    *ret = ((satot << 24) | (srtot << 16) | (sgtot <<  8) | (sbtot));
+}
+
+static force_inline void accum_float(int *satot, int *srtot,
+				     int *sgtot, int *sbtot,
+				     const void *p, pixman_fixed_t f)
+{
+    const argb_t *pixel = p;
+
+    *satot += pixel->a * f;
+    *srtot += pixel->r * f;
+    *sgtot += pixel->g * f;
+    *sbtot += pixel->b * f;
+}
+
+static force_inline void reduce_float(int satot, int srtot,
+				      int sgtot, int sbtot,
+				      void *p)
+{
+    argb_t *ret = p;
+
+    ret->a = CLIP (satot / 65536.f, 0.f, 1.f);
+    ret->r = CLIP (srtot / 65536.f, 0.f, 1.f);
+    ret->g = CLIP (sgtot / 65536.f, 0.f, 1.f);
+    ret->b = CLIP (sbtot / 65536.f, 0.f, 1.f);
+}
+
+typedef void (* accumulate_pixel_t) (int *satot, int *srtot,
+				     int *sgtot, int *sbtot,
+				     const void *pixel, pixman_fixed_t f);
+
+typedef void (* reduce_pixel_t) (int satot, int srtot,
+				 int sgtot, int sbtot, void *out);
+
+static force_inline void
 bits_image_fetch_pixel_convolution (bits_image_t   *image,
 				    pixman_fixed_t  x,
 				    pixman_fixed_t  y,
-				    get_pixel_t     get_pixel)
+				    get_pixel_t     get_pixel,
+				    void	      *out,
+				    accumulate_pixel_t accum,
+				    reduce_pixel_t reduce)
 {
     pixman_fixed_t *params = image->common.filter_params;
     int x_off = (params[0] - pixman_fixed_1) >> 1;
@@ -174,48 +291,39 @@ bits_image_fetch_pixel_convolution (bits_image_t   *image,
 
 	    if (f)
 	    {
-		uint32_t pixel;
+		/* Must be big enough to hold a argb_t */
+		argb_t pixel;
 
 		if (repeat_mode != PIXMAN_REPEAT_NONE)
 		{
 		    repeat (repeat_mode, &rx, width);
 		    repeat (repeat_mode, &ry, height);
 
-		    pixel = get_pixel (image, rx, ry, FALSE);
+		    get_pixel (image, rx, ry, FALSE, &pixel);
 		}
 		else
 		{
-		    pixel = get_pixel (image, rx, ry, TRUE);
+		    get_pixel (image, rx, ry, TRUE, &pixel);
 		}
 
-		srtot += (int)RED_8 (pixel) * f;
-		sgtot += (int)GREEN_8 (pixel) * f;
-		sbtot += (int)BLUE_8 (pixel) * f;
-		satot += (int)ALPHA_8 (pixel) * f;
+		accum (&satot, &srtot, &sgtot, &sbtot, &pixel, f);
 	    }
 
 	    params++;
 	}
     }
 
-    satot = (satot + 0x8000) >> 16;
-    srtot = (srtot + 0x8000) >> 16;
-    sgtot = (sgtot + 0x8000) >> 16;
-    sbtot = (sbtot + 0x8000) >> 16;
-
-    satot = CLIP (satot, 0, 0xff);
-    srtot = CLIP (srtot, 0, 0xff);
-    sgtot = CLIP (sgtot, 0, 0xff);
-    sbtot = CLIP (sbtot, 0, 0xff);
-
-    return ((satot << 24) | (srtot << 16) | (sgtot <<  8) | (sbtot));
+    reduce (satot, srtot, sgtot, sbtot, out);
 }
 
-static uint32_t
-bits_image_fetch_pixel_separable_convolution (bits_image_t *image,
-                                              pixman_fixed_t x,
-                                              pixman_fixed_t y,
-                                              get_pixel_t    get_pixel)
+static void
+bits_image_fetch_pixel_separable_convolution (bits_image_t  *image,
+					      pixman_fixed_t x,
+					      pixman_fixed_t y,
+					      get_pixel_t    get_pixel,
+					      void	    *out,
+					      accumulate_pixel_t accum,
+					      reduce_pixel_t     reduce)
 {
     pixman_fixed_t *params = image->common.filter_params;
     pixman_repeat_t repeat_mode = image->common.repeat;
@@ -270,82 +378,91 @@ bits_image_fetch_pixel_separable_convolution (bits_image_t *image,
 
                 if (fx)
                 {
+                    /* Must be big enough to hold a argb_t */
+                    argb_t pixel;
                     pixman_fixed_t f;
-                    uint32_t pixel;
 
                     if (repeat_mode != PIXMAN_REPEAT_NONE)
                     {
                         repeat (repeat_mode, &rx, width);
                         repeat (repeat_mode, &ry, height);
 
-                        pixel = get_pixel (image, rx, ry, FALSE);
+                        get_pixel (image, rx, ry, FALSE, &pixel);
                     }
                     else
                     {
-                        pixel = get_pixel (image, rx, ry, TRUE);
+                        get_pixel (image, rx, ry, TRUE, &pixel);
 		    }
 
                     f = (fy * fx + 0x8000) >> 16;
 
-                    srtot += (int)RED_8 (pixel) * f;
-                    sgtot += (int)GREEN_8 (pixel) * f;
-                    sbtot += (int)BLUE_8 (pixel) * f;
-                    satot += (int)ALPHA_8 (pixel) * f;
+		    accum(&satot, &srtot, &sgtot, &sbtot, &pixel, f);
                 }
             }
 	}
     }
 
-    satot = (satot + 0x8000) >> 16;
-    srtot = (srtot + 0x8000) >> 16;
-    sgtot = (sgtot + 0x8000) >> 16;
-    sbtot = (sbtot + 0x8000) >> 16;
 
-    satot = CLIP (satot, 0, 0xff);
-    srtot = CLIP (srtot, 0, 0xff);
-    sgtot = CLIP (sgtot, 0, 0xff);
-    sbtot = CLIP (sbtot, 0, 0xff);
-
-    return ((satot << 24) | (srtot << 16) | (sgtot <<  8) | (sbtot));
+    reduce(satot, srtot, sgtot, sbtot, out);
 }
 
-static force_inline uint32_t
-bits_image_fetch_pixel_filtered (bits_image_t *image,
+static force_inline void
+bits_image_fetch_pixel_filtered (bits_image_t  *image,
+				 pixman_bool_t  wide,
 				 pixman_fixed_t x,
 				 pixman_fixed_t y,
-				 get_pixel_t    get_pixel)
+				 get_pixel_t    get_pixel,
+				 void          *out)
 {
     switch (image->common.filter)
     {
     case PIXMAN_FILTER_NEAREST:
     case PIXMAN_FILTER_FAST:
-	return bits_image_fetch_pixel_nearest (image, x, y, get_pixel);
+	bits_image_fetch_pixel_nearest (image, x, y, get_pixel, out);
 	break;
 
     case PIXMAN_FILTER_BILINEAR:
     case PIXMAN_FILTER_GOOD:
     case PIXMAN_FILTER_BEST:
-	return bits_image_fetch_pixel_bilinear (image, x, y, get_pixel);
+	if (wide)
+	    bits_image_fetch_pixel_bilinear_float (image, x, y, get_pixel, out);
+	else
+	    bits_image_fetch_pixel_bilinear_32 (image, x, y, get_pixel, out);
 	break;
 
     case PIXMAN_FILTER_CONVOLUTION:
-	return bits_image_fetch_pixel_convolution (image, x, y, get_pixel);
+	if (wide)
+	    bits_image_fetch_pixel_convolution (image, x, y,
+						get_pixel, out,
+						accum_float,
+						reduce_float);
+	else
+	    bits_image_fetch_pixel_convolution (image, x, y,
+						get_pixel, out,
+						accum_32, reduce_32);
 	break;
 
     case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
-        return bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel);
+	if (wide)
+	    bits_image_fetch_pixel_separable_convolution (image, x, y,
+							  get_pixel, out,
+							  accum_float,
+							  reduce_float);
+	else
+	    bits_image_fetch_pixel_separable_convolution (image, x, y,
+							  get_pixel, out,
+							  accum_32, reduce_32);
         break;
 
     default:
         break;
     }
-
-    return 0;
 }
 
 static uint32_t *
-bits_image_fetch_affine_no_alpha (pixman_iter_t *  iter,
-				  const uint32_t * mask)
+__bits_image_fetch_affine_no_alpha (pixman_iter_t *  iter,
+				    pixman_bool_t    wide,
+				    const uint32_t * mask)
 {
     pixman_image_t *image  = iter->image;
     int             offset = iter->x;
@@ -357,6 +474,8 @@ bits_image_fetch_affine_no_alpha (pixman_iter_t *  iter,
     pixman_fixed_t ux, uy;
     pixman_vector_t v;
     int i;
+    get_pixel_t get_pixel =
+	wide ? fetch_pixel_no_alpha_float : fetch_pixel_no_alpha_32;
 
     /* reference point is the center of the pixel */
     v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
@@ -384,27 +503,45 @@ bits_image_fetch_affine_no_alpha (pixman_iter_t *  iter,
     {
 	if (!mask || mask[i])
 	{
-	    buffer[i] = bits_image_fetch_pixel_filtered (
-		&image->bits, x, y, fetch_pixel_no_alpha);
+	    bits_image_fetch_pixel_filtered (
+		&image->bits, wide, x, y, get_pixel, buffer);
 	}
 
 	x += ux;
 	y += uy;
+	buffer += wide ? 4 : 1;
     }
 
-    return buffer;
+    return iter->buffer;
+}
+
+static uint32_t *
+bits_image_fetch_affine_no_alpha_32 (pixman_iter_t  *iter,
+				     const uint32_t *mask)
+{
+    return __bits_image_fetch_affine_no_alpha(iter, FALSE, mask);
+}
+
+static uint32_t *
+bits_image_fetch_affine_no_alpha_float (pixman_iter_t  *iter,
+					const uint32_t *mask)
+{
+    return __bits_image_fetch_affine_no_alpha(iter, TRUE, mask);
 }
 
 /* General fetcher */
-static force_inline uint32_t
-fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds)
+static force_inline void
+fetch_pixel_general_32 (bits_image_t *image,
+			int x, int y, pixman_bool_t check_bounds,
+			void *out)
 {
-    uint32_t pixel;
+    uint32_t pixel, *ret = out;
 
     if (check_bounds &&
 	(x < 0 || x >= image->width || y < 0 || y >= image->height))
     {
-	return 0;
+	*ret = 0;
+	return;
     }
 
     pixel = image->fetch_pixel_32 (image, x, y);
@@ -433,18 +570,59 @@ fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_boun
 	pixel |= (pixel_a << 24);
     }
 
-    return pixel;
+    *ret = pixel;
+}
+
+static force_inline void
+fetch_pixel_general_float (bits_image_t *image,
+			int x, int y, pixman_bool_t check_bounds,
+			void *out)
+{
+    argb_t *ret = out;
+
+    if (check_bounds &&
+	(x < 0 || x >= image->width || y < 0 || y >= image->height))
+    {
+	ret->a = ret->r = ret->g = ret->b = 0;
+	return;
+    }
+
+    *ret = image->fetch_pixel_float (image, x, y);
+
+    if (image->common.alpha_map)
+    {
+	x -= image->common.alpha_origin_x;
+	y -= image->common.alpha_origin_y;
+
+	if (x < 0 || x >= image->common.alpha_map->width ||
+	    y < 0 || y >= image->common.alpha_map->height)
+	{
+	    ret->a = 0.f;
+	}
+	else
+	{
+	    argb_t alpha;
+
+	    alpha = image->common.alpha_map->fetch_pixel_float (
+		    image->common.alpha_map, x, y);
+
+	    ret->a = alpha.a;
+	}
+    }
 }
 
 static uint32_t *
-bits_image_fetch_general (pixman_iter_t  *iter,
-			  const uint32_t *mask)
+__bits_image_fetch_general (pixman_iter_t  *iter,
+			    pixman_bool_t wide,
+			    const uint32_t *mask)
 {
     pixman_image_t *image  = iter->image;
     int             offset = iter->x;
     int             line   = iter->y++;
     int             width  = iter->width;
     uint32_t *      buffer = iter->buffer;
+    get_pixel_t     get_pixel =
+	wide ? fetch_pixel_general_float : fetch_pixel_general_32;
 
     pixman_fixed_t x, y, w;
     pixman_fixed_t ux, uy, uw;
@@ -493,16 +671,31 @@ bits_image_fetch_general (pixman_iter_t  *iter,
 		y0 = 0;
 	    }
 
-	    buffer[i] = bits_image_fetch_pixel_filtered (
-		&image->bits, x0, y0, fetch_pixel_general);
+	    bits_image_fetch_pixel_filtered (
+		&image->bits, wide, x0, y0, get_pixel, buffer);
 	}
 
 	x += ux;
 	y += uy;
 	w += uw;
+	buffer += wide ? 4 : 1;
     }
 
-    return buffer;
+    return iter->buffer;
+}
+
+static uint32_t *
+bits_image_fetch_general_32 (pixman_iter_t  *iter,
+			     const uint32_t *mask)
+{
+    return __bits_image_fetch_general(iter, FALSE, mask);
+}
+
+static uint32_t *
+bits_image_fetch_general_float (pixman_iter_t  *iter,
+				const uint32_t *mask)
+{
+    return __bits_image_fetch_general(iter, TRUE, mask);
 }
 
 static void
@@ -703,15 +896,15 @@ static const fetcher_info_t fetcher_info[] =
     /* Affine, no alpha */
     { PIXMAN_any,
       (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM),
-      bits_image_fetch_affine_no_alpha,
-      _pixman_image_get_scanline_generic_float
+      bits_image_fetch_affine_no_alpha_32,
+      bits_image_fetch_affine_no_alpha_float,
     },
 
     /* General */
     { PIXMAN_any,
       0,
-      bits_image_fetch_general,
-      _pixman_image_get_scanline_generic_float
+      bits_image_fetch_general_32,
+      bits_image_fetch_general_float,
     },
 
     { PIXMAN_null },
@@ -741,7 +934,6 @@ _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
 	    }
 	    else
 	    {
-		iter->data = info->get_scanline_32;
 		iter->get_scanline = info->get_scanline_float;
 	    }
 	    return;
diff --git a/pixman/pixman-inlines.h b/pixman/pixman-inlines.h
index 1c8441d..332e208 100644
--- a/pixman/pixman-inlines.h
+++ b/pixman/pixman-inlines.h
@@ -222,6 +222,31 @@ bilinear_interpolation (uint32_t tl, uint32_t tr,
 #endif
 #endif // BILINEAR_INTERPOLATION_BITS <= 4
 
+static force_inline argb_t
+bilinear_interpolation_float (argb_t tl, argb_t tr,
+			      argb_t bl, argb_t br,
+			      float distx, float disty)
+{
+    float distxy, distxiy, distixy, distixiy;
+    argb_t r;
+
+    distxy = distx * disty;
+    distxiy = distx - (1.f - distxy);
+    distixy = (1.f - distx) * disty;
+    distixiy = (1.f - distx) * (1.f - disty);
+
+    r.a = tl.a * distixiy + tr.a * distxiy +
+          bl.a * distixy  + br.a * distxy;
+    r.r = tl.r * distixiy + tr.r * distxiy +
+          bl.r * distixy  + br.r * distxy;
+    r.g = tl.g * distixiy + tr.g * distxiy +
+          bl.g * distixy  + br.g * distxy;
+    r.b = tl.b * distixiy + tr.b * distxiy +
+          bl.b * distixy  + br.b * distxy;
+
+    return r;
+}
+
 /*
  * For each scanline fetched from source image with PAD repeat:
  * - calculate how many pixels need to be padded on the left side
commit a32fc4faf9defc6c18cf1cca7075ef3866fd5de6
Author: Basile Clement <basile-pixman at clement.pm>
Date:   Mon Dec 3 15:55:28 2018 +0100

    Implement floating point gradient computation, v2.
    
    This patch modifies the gradient walker to be able to generate floating
    point values directly in addition to a8r8g8b8 32 bit values.  This is
    then used by the various gradient implementations to render in floating
    point when asked to do so, instead of rendering to a8r8g8b8 and then
    expanding to floating point as they were doing previously.
    
    Changes since v1 (mlankhorst):
    - Implement pixman_gradient_walker_pixel_32 without calling
      pixman_gradient_walker_pixel_float, to prevent performance degradation.
      Suggested by Adam Jackson.
    - Fix whitespace errors.
    - Remove unnecessary function prototypes in pixman-private.h
    
    Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
    [mlankhorst: Add comment about pixman_contract_from_float,
                 based on Basille's suggestion]
    Acked-by: Basile Clement <basile-pixman at clement.pm>

diff --git a/pixman/pixman-conical-gradient.c b/pixman/pixman-conical-gradient.c
index 8bb46ae..a39e20c 100644
--- a/pixman/pixman-conical-gradient.c
+++ b/pixman/pixman-conical-gradient.c
@@ -51,7 +51,10 @@ coordinates_to_parameter (double x, double y, double angle)
 }
 
 static uint32_t *
-conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
+conical_get_scanline (pixman_iter_t                 *iter,
+		      const uint32_t                *mask,
+		      int                            Bpp,
+		      pixman_gradient_walker_write_t write_pixel)
 {
     pixman_image_t *image = iter->image;
     int x = iter->x;
@@ -61,7 +64,7 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 
     gradient_t *gradient = (gradient_t *)image;
     conical_gradient_t *conical = (conical_gradient_t *)image;
-    uint32_t       *end = buffer + width;
+    uint32_t       *end = buffer + width * (Bpp / 4);
     pixman_gradient_walker_t walker;
     pixman_bool_t affine = TRUE;
     double cx = 1.;
@@ -109,11 +112,12 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 	    {
 		double t = coordinates_to_parameter (rx, ry, conical->angle);
 
-		*buffer = _pixman_gradient_walker_pixel (
-		    &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
+		write_pixel (&walker,
+			     (pixman_fixed_48_16_t)pixman_double_to_fixed (t),
+			     buffer);
 	    }
 
-	    ++buffer;
+	    buffer += (Bpp / 4);
 
 	    rx += cx;
 	    ry += cy;
@@ -144,11 +148,12 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 
 		t = coordinates_to_parameter (x, y, conical->angle);
 
-		*buffer = _pixman_gradient_walker_pixel (
-		    &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
+		write_pixel (&walker,
+			     (pixman_fixed_48_16_t)pixman_double_to_fixed (t),
+			     buffer);
 	    }
 
-	    ++buffer;
+	    buffer += (Bpp / 4);
 
 	    rx += cx;
 	    ry += cy;
@@ -161,14 +166,17 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 }
 
 static uint32_t *
-conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 {
-    uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
-
-    pixman_expand_to_float (
-	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
+    return conical_get_scanline (iter, mask, 4,
+				 _pixman_gradient_walker_write_narrow);
+}
 
-    return buffer;
+static uint32_t *
+conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+{
+    return conical_get_scanline (iter, NULL, 16,
+				 _pixman_gradient_walker_write_wide);
 }
 
 void
diff --git a/pixman/pixman-gradient-walker.c b/pixman/pixman-gradient-walker.c
index 822f8e6..af4df58 100644
--- a/pixman/pixman-gradient-walker.c
+++ b/pixman/pixman-gradient-walker.c
@@ -122,10 +122,9 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
 	    left_c = right_c;
     }
 
-    /* The alpha channel is scaled to be in the [0, 255] interval,
-     * and the red/green/blue channels are scaled to be in [0, 1].
+    /* The alpha/red/green/blue channels are scaled to be in [0, 1].
      * This ensures that after premultiplication all channels will
-     * be in the [0, 255] interval.
+     * be in the [0, 1] interval.
      */
     la = (left_c->alpha * (1.0f/257.0f));
     lr = (left_c->red * (1.0f/257.0f));
@@ -143,7 +142,7 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
     if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
     {
 	walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
-	walker->a_b = (la + ra) / 2.0f;
+	walker->a_b = (la + ra) / 510.0f;
 	walker->r_b = (lr + rr) / 510.0f;
 	walker->g_b = (lg + rg) / 510.0f;
 	walker->b_b = (lb + rb) / 510.0f;
@@ -152,12 +151,12 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
     {
 	float w_rec = 1.0f / (rx - lx);
 
-	walker->a_b = (la * rx - ra * lx) * w_rec;
+	walker->a_b = (la * rx - ra * lx) * w_rec * (1.0f/255.0f);
 	walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
 	walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
 	walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
 
-	walker->a_s = (ra - la) * w_rec;
+	walker->a_s = (ra - la) * w_rec * (1.0f/255.0f);
 	walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
 	walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
 	walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
@@ -169,34 +168,97 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
     walker->need_reset = FALSE;
 }
 
-uint32_t
-_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
-                               pixman_fixed_48_16_t      x)
+static argb_t
+pixman_gradient_walker_pixel_float (pixman_gradient_walker_t *walker,
+				    pixman_fixed_48_16_t      x)
 {
-    float a, r, g, b;
-    uint8_t a8, r8, g8, b8;
-    uint32_t v;
+    argb_t f;
     float y;
 
     if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
-        gradient_walker_reset (walker, x);
+	gradient_walker_reset (walker, x);
 
     y = x * (1.0f / 65536.0f);
 
-    a = walker->a_s * y + walker->a_b;
-    r = a * (walker->r_s * y + walker->r_b);
-    g = a * (walker->g_s * y + walker->g_b);
-    b = a * (walker->b_s * y + walker->b_b);
+    f.a = walker->a_s * y + walker->a_b;
+    f.r = f.a * (walker->r_s * y + walker->r_b);
+    f.g = f.a * (walker->g_s * y + walker->g_b);
+    f.b = f.a * (walker->b_s * y + walker->b_b);
 
-    a8 = a + 0.5f;
-    r8 = r + 0.5f;
-    g8 = g + 0.5f;
-    b8 = b + 0.5f;
+    return f;
+}
+
+static uint32_t
+pixman_gradient_walker_pixel_32 (pixman_gradient_walker_t *walker,
+				 pixman_fixed_48_16_t      x)
+{
+    argb_t f;
+    float y;
+
+    if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
+	gradient_walker_reset (walker, x);
+
+    y = x * (1.0f / 65536.0f);
+
+    /* Instead of [0...1] for ARGB, we want [0...255],
+     * multiply alpha with 255 and the color channels
+     * also get multiplied by the alpha multiplier.
+     *
+     * We don't use pixman_contract_from_float because it causes a 2x
+     * slowdown to do so, and the values are already normalized,
+     * so we don't have to worry about values < 0.f or > 1.f
+     */
+    f.a = 255.f * (walker->a_s * y + walker->a_b);
+    f.r = f.a * (walker->r_s * y + walker->r_b);
+    f.g = f.a * (walker->g_s * y + walker->g_b);
+    f.b = f.a * (walker->b_s * y + walker->b_b);
 
-    v = ((a8 << 24) & 0xff000000) |
-        ((r8 << 16) & 0x00ff0000) |
-        ((g8 <<  8) & 0x0000ff00) |
-        ((b8 >>  0) & 0x000000ff);
+    return (((uint8_t)(f.a + .5f) << 24) & 0xff000000) |
+           (((uint8_t)(f.r + .5f) << 16) & 0x00ff0000) |
+           (((uint8_t)(f.g + .5f) <<  8) & 0x0000ff00) |
+           (((uint8_t)(f.b + .5f) >>  0) & 0x000000ff);
+}
+
+void
+_pixman_gradient_walker_write_narrow (pixman_gradient_walker_t *walker,
+				      pixman_fixed_48_16_t      x,
+				      uint32_t                 *buffer)
+{
+    *buffer = pixman_gradient_walker_pixel_32 (walker, x);
+}
+
+void
+_pixman_gradient_walker_write_wide (pixman_gradient_walker_t *walker,
+				    pixman_fixed_48_16_t      x,
+				    uint32_t                 *buffer)
+{
+    *(argb_t *)buffer = pixman_gradient_walker_pixel_float (walker, x);
+}
+
+void
+_pixman_gradient_walker_fill_narrow (pixman_gradient_walker_t *walker,
+				     pixman_fixed_48_16_t      x,
+				     uint32_t                 *buffer,
+				     uint32_t                 *end)
+{
+    register uint32_t color;
+
+    color = pixman_gradient_walker_pixel_32 (walker, x);
+    while (buffer < end)
+	*buffer++ = color;
+}
+
+void
+_pixman_gradient_walker_fill_wide (pixman_gradient_walker_t *walker,
+				   pixman_fixed_48_16_t      x,
+				   uint32_t                 *buffer,
+				   uint32_t                 *end)
+{
+    register argb_t color;
+    argb_t *buffer_wide = (argb_t *)buffer;
+    argb_t *end_wide    = (argb_t *)end;
 
-    return v;
+    color = pixman_gradient_walker_pixel_float (walker, x);
+    while (buffer_wide < end_wide)
+	*buffer_wide++ = color;
 }
diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c
index 40c8c9f..3f52850 100644
--- a/pixman/pixman-linear-gradient.c
+++ b/pixman/pixman-linear-gradient.c
@@ -89,8 +89,11 @@ linear_gradient_is_horizontal (pixman_image_t *image,
 }
 
 static uint32_t *
-linear_get_scanline_narrow (pixman_iter_t  *iter,
-			    const uint32_t *mask)
+linear_get_scanline (pixman_iter_t                 *iter,
+		     const uint32_t                *mask,
+		     int                            Bpp,
+		     pixman_gradient_walker_write_t write_pixel,
+		     pixman_gradient_walker_fill_t  fill_pixel)
 {
     pixman_image_t *image  = iter->image;
     int             x      = iter->x;
@@ -103,7 +106,7 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
     pixman_fixed_48_16_t dx, dy;
     gradient_t *gradient = (gradient_t *)image;
     linear_gradient_t *linear = (linear_gradient_t *)image;
-    uint32_t *end = buffer + width;
+    uint32_t *end = buffer + width * (Bpp / 4);
     pixman_gradient_walker_t walker;
 
     _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
@@ -137,7 +140,7 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
     if (l == 0 || unit.vector[2] == 0)
     {
 	/* affine transformation only */
-        pixman_fixed_32_32_t t, next_inc;
+	pixman_fixed_32_32_t t, next_inc;
 	double inc;
 
 	if (l == 0 || v.vector[2] == 0)
@@ -152,7 +155,7 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
 	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
 		(l * (double) v.vector[2]);
 	    v2 = v.vector[2] * (1. / pixman_fixed_1);
-	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
+	    t = ((dx * v.vector[0] + dy * v.vector[1]) -
 		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
 	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
 	}
@@ -160,11 +163,7 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
 
 	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
 	{
-	    register uint32_t color;
-
-	    color = _pixman_gradient_walker_pixel (&walker, t);
-	    while (buffer < end)
-		*buffer++ = color;
+	    fill_pixel (&walker, t, buffer, end);
 	}
 	else
 	{
@@ -175,12 +174,11 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
 	    {
 		if (!mask || *mask++)
 		{
-		    *buffer = _pixman_gradient_walker_pixel (&walker,
-							     t + next_inc);
+		    write_pixel (&walker, t + next_inc, buffer);
 		}
 		i++;
 		next_inc = inc * i;
-		buffer++;
+		buffer += (Bpp / 4);
 	    }
 	}
     }
@@ -202,14 +200,14 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
 		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
 			(l * (double) v.vector[2]);
 		    v2 = v.vector[2] * (1. / pixman_fixed_1);
-		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
+		    t = ((dx * v.vector[0] + dy * v.vector[1]) -
 			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
 		}
 
-		*buffer = _pixman_gradient_walker_pixel (&walker, t);
+		write_pixel (&walker, t, buffer);
 	    }
 
-	    ++buffer;
+	    buffer += (Bpp / 4);
 
 	    v.vector[0] += unit.vector[0];
 	    v.vector[1] += unit.vector[1];
@@ -223,14 +221,21 @@ linear_get_scanline_narrow (pixman_iter_t  *iter,
 }
 
 static uint32_t *
-linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+linear_get_scanline_narrow (pixman_iter_t  *iter,
+			    const uint32_t *mask)
 {
-    uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
+    return linear_get_scanline (iter, mask, 4,
+				_pixman_gradient_walker_write_narrow,
+				_pixman_gradient_walker_fill_narrow);
+}
 
-    pixman_expand_to_float (
-	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
 
-    return buffer;
+static uint32_t *
+linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+{
+    return linear_get_scanline (iter, NULL, 16,
+				_pixman_gradient_walker_write_wide,
+				_pixman_gradient_walker_fill_wide);
 }
 
 void
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 73a5414..1bd9695 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -363,9 +363,38 @@ void
 _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker,
                                pixman_fixed_48_16_t      pos);
 
-uint32_t
-_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
-                               pixman_fixed_48_16_t      x);
+typedef void (*pixman_gradient_walker_write_t) (
+    pixman_gradient_walker_t *walker,
+    pixman_fixed_48_16_t      x,
+    uint32_t                 *buffer);
+
+void
+_pixman_gradient_walker_write_narrow(pixman_gradient_walker_t *walker,
+				     pixman_fixed_48_16_t      x,
+				     uint32_t                 *buffer);
+
+void
+_pixman_gradient_walker_write_wide(pixman_gradient_walker_t *walker,
+				   pixman_fixed_48_16_t      x,
+				   uint32_t                 *buffer);
+
+typedef void (*pixman_gradient_walker_fill_t) (
+    pixman_gradient_walker_t *walker,
+    pixman_fixed_48_16_t      x,
+    uint32_t                 *buffer,
+    uint32_t                 *end);
+
+void
+_pixman_gradient_walker_fill_narrow(pixman_gradient_walker_t *walker,
+				    pixman_fixed_48_16_t      x,
+				    uint32_t                 *buffer,
+				    uint32_t                 *end);
+
+void
+_pixman_gradient_walker_fill_wide(pixman_gradient_walker_t *walker,
+				  pixman_fixed_48_16_t      x,
+				  uint32_t                 *buffer,
+				  uint32_t                 *end);
 
 /*
  * Edges
diff --git a/pixman/pixman-radial-gradient.c b/pixman/pixman-radial-gradient.c
index 6a21796..0367d78 100644
--- a/pixman/pixman-radial-gradient.c
+++ b/pixman/pixman-radial-gradient.c
@@ -66,15 +66,18 @@ fdot (double x1,
     return x1 * x2 + y1 * y2 + z1 * z2;
 }
 
-static uint32_t
-radial_compute_color (double                    a,
-		      double                    b,
-		      double                    c,
-		      double                    inva,
-		      double                    dr,
-		      double                    mindr,
-		      pixman_gradient_walker_t *walker,
-		      pixman_repeat_t           repeat)
+static void
+radial_write_color (double                         a,
+		    double                         b,
+		    double                         c,
+		    double                         inva,
+		    double                         dr,
+		    double                         mindr,
+		    pixman_gradient_walker_t      *walker,
+		    pixman_repeat_t                repeat,
+		    int                            Bpp,
+		    pixman_gradient_walker_write_t write_pixel,
+		    uint32_t                      *buffer)
 {
     /*
      * In this function error propagation can lead to bad results:
@@ -99,21 +102,25 @@ radial_compute_color (double                    a,
 	double t;
 
 	if (b == 0)
-	    return 0;
+	{
+	    memset (buffer, 0, Bpp);
+	    return;
+	}
 
 	t = pixman_fixed_1 / 2 * c / b;
 	if (repeat == PIXMAN_REPEAT_NONE)
 	{
 	    if (0 <= t && t <= pixman_fixed_1)
-		return _pixman_gradient_walker_pixel (walker, t);
+		return write_pixel (walker, t, buffer);
 	}
 	else
 	{
 	    if (t * dr >= mindr)
-		return _pixman_gradient_walker_pixel (walker, t);
+		return write_pixel (walker, t, buffer);
 	}
 
-	return 0;
+	memset (buffer, 0, Bpp);
+	return;
     }
 
     discr = fdot (b, a, 0, b, -c, 0);
@@ -139,24 +146,28 @@ radial_compute_color (double                    a,
 	if (repeat == PIXMAN_REPEAT_NONE)
 	{
 	    if (0 <= t0 && t0 <= pixman_fixed_1)
-		return _pixman_gradient_walker_pixel (walker, t0);
+		return write_pixel (walker, t0, buffer);
 	    else if (0 <= t1 && t1 <= pixman_fixed_1)
-		return _pixman_gradient_walker_pixel (walker, t1);
+		return write_pixel (walker, t1, buffer);
 	}
 	else
 	{
 	    if (t0 * dr >= mindr)
-		return _pixman_gradient_walker_pixel (walker, t0);
+		return write_pixel (walker, t0, buffer);
 	    else if (t1 * dr >= mindr)
-		return _pixman_gradient_walker_pixel (walker, t1);
+		return write_pixel (walker, t1, buffer);
 	}
     }
 
-    return 0;
+    memset (buffer, 0, Bpp);
+    return;
 }
 
 static uint32_t *
-radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
+radial_get_scanline (pixman_iter_t                 *iter,
+		     const uint32_t                *mask,
+		     int                            Bpp,
+		     pixman_gradient_walker_write_t write_pixel)
 {
     /*
      * Implementation of radial gradients following the PDF specification.
@@ -247,7 +258,7 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 
     gradient_t *gradient = (gradient_t *)image;
     radial_gradient_t *radial = (radial_gradient_t *)image;
-    uint32_t *end = buffer + width;
+    uint32_t *end = buffer + width * (Bpp / 4);
     pixman_gradient_walker_t walker;
     pixman_vector_t v, unit;
 
@@ -330,18 +341,21 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 	{
 	    if (!mask || *mask++)
 	    {
-		*buffer = radial_compute_color (radial->a, b, c,
-						radial->inva,
-						radial->delta.radius,
-						radial->mindr,
-						&walker,
-						image->common.repeat);
+		radial_write_color (radial->a, b, c,
+				    radial->inva,
+				    radial->delta.radius,
+				    radial->mindr,
+				    &walker,
+				    image->common.repeat,
+				    Bpp,
+				    write_pixel,
+				    buffer);
 	    }
 
 	    b += db;
 	    c += dc;
 	    dc += ddc;
-	    ++buffer;
+	    buffer += (Bpp / 4);
 	}
     }
     else
@@ -375,20 +389,23 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 			      pdx, pdy, radial->c1.radius);
 		    /*  / pixman_fixed_1 / pixman_fixed_1 */
 
-		    *buffer = radial_compute_color (radial->a, b, c,
-						    radial->inva,
-						    radial->delta.radius,
-						    radial->mindr,
-						    &walker,
-						    image->common.repeat);
+		    radial_write_color (radial->a, b, c,
+					radial->inva,
+					radial->delta.radius,
+					radial->mindr,
+					&walker,
+					image->common.repeat,
+					Bpp,
+					write_pixel,
+					buffer);
 		}
 		else
 		{
-		    *buffer = 0;
+		    memset (buffer, 0, Bpp);
 		}
 	    }
 
-	    ++buffer;
+	    buffer += (Bpp / 4);
 
 	    v.vector[0] += unit.vector[0];
 	    v.vector[1] += unit.vector[1];
@@ -401,14 +418,17 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 }
 
 static uint32_t *
-radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 {
-    uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
-
-    pixman_expand_to_float (
-	(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
+    return radial_get_scanline (iter, mask, 4,
+				_pixman_gradient_walker_write_narrow);
+}
 
-    return buffer;
+static uint32_t *
+radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+{
+    return radial_get_scanline (iter, NULL, 16,
+				_pixman_gradient_walker_write_wide);
 }
 
 void
@@ -422,11 +442,11 @@ _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
 
 PIXMAN_EXPORT pixman_image_t *
 pixman_image_create_radial_gradient (const pixman_point_fixed_t *  inner,
-                                     const pixman_point_fixed_t *  outer,
-                                     pixman_fixed_t                inner_radius,
-                                     pixman_fixed_t                outer_radius,
-                                     const pixman_gradient_stop_t *stops,
-                                     int                           n_stops)
+				     const pixman_point_fixed_t *  outer,
+				     pixman_fixed_t                inner_radius,
+				     pixman_fixed_t                outer_radius,
+				     const pixman_gradient_stop_t *stops,
+				     int                           n_stops)
 {
     pixman_image_t *image;
     radial_gradient_t *radial;


More information about the xorg-commit mailing list