gfx/cairo/pixman-16-bit-pipeline.patch

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/cairo/pixman-16-bit-pipeline.patch	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1242 @@
     1.4 +diff --git a/gfx/cairo/libpixman/src/pixman-access.c b/gfx/cairo/libpixman/src/pixman-access.c
     1.5 +--- a/gfx/cairo/libpixman/src/pixman-access.c
     1.6 ++++ b/gfx/cairo/libpixman/src/pixman-access.c
     1.7 +@@ -933,16 +933,54 @@ store_scanline_x2b10g10r10 (bits_image_t
     1.8 +     {
     1.9 + 	WRITE (image, pixel++,
    1.10 + 	       ((values[i] >> 38) & 0x3ff) |
    1.11 + 	       ((values[i] >> 12) & 0xffc00) |
    1.12 + 	       ((values[i] << 14) & 0x3ff00000));
    1.13 +     }
    1.14 + }
    1.15 + 
    1.16 ++static void
    1.17 ++store_scanline_16 (bits_image_t *  image,
    1.18 ++		   int             x,
    1.19 ++		   int             y,
    1.20 ++		   int             width,
    1.21 ++		   const uint32_t *v)
    1.22 ++{
    1.23 ++    uint16_t *bits = (uint16_t*)(image->bits + image->rowstride * y);
    1.24 ++    uint16_t *values = (uint16_t *)v;
    1.25 ++    uint16_t *pixel = bits + x;
    1.26 ++    int i;
    1.27 ++
    1.28 ++    for (i = 0; i < width; ++i)
    1.29 ++    {
    1.30 ++	WRITE (image, pixel++, values[i]);
    1.31 ++    }
    1.32 ++}
    1.33 ++
    1.34 ++static void
    1.35 ++fetch_scanline_16 (pixman_image_t *image,
    1.36 ++                            int             x,
    1.37 ++                            int             y,
    1.38 ++                            int             width,
    1.39 ++                            uint32_t *      b,
    1.40 ++                            const uint32_t *mask)
    1.41 ++{
    1.42 ++    const uint16_t *bits = (uint16_t*)(image->bits.bits + y * image->bits.rowstride);
    1.43 ++    const uint16_t *pixel = bits + x;
    1.44 ++    int i;
    1.45 ++    uint16_t *buffer = (uint16_t *)b;
    1.46 ++
    1.47 ++    for (i = 0; i < width; ++i)
    1.48 ++    {
    1.49 ++	*buffer++ = READ (image, pixel++);
    1.50 ++    }
    1.51 ++}
    1.52 ++
    1.53 ++
    1.54 + /*
    1.55 +  * Contracts a 64bpp image to 32bpp and then stores it using a regular 32-bit
    1.56 +  * store proc. Despite the type, this function expects a uint64_t buffer.
    1.57 +  */
    1.58 + static void
    1.59 + store_scanline_generic_64 (bits_image_t *  image,
    1.60 +                            int             x,
    1.61 +                            int             y,
    1.62 +@@ -1044,32 +1082,47 @@ fetch_pixel_generic_lossy_32 (bits_image
    1.63 +     pixman_contract (&result, &pixel64, 1);
    1.64 + 
    1.65 +     return result;
    1.66 + }
    1.67 + 
    1.68 + typedef struct
    1.69 + {
    1.70 +     pixman_format_code_t	format;
    1.71 ++    fetch_scanline_t		fetch_scanline_16;
    1.72 +     fetch_scanline_t		fetch_scanline_32;
    1.73 +     fetch_scanline_t		fetch_scanline_64;
    1.74 +     fetch_pixel_32_t		fetch_pixel_32;
    1.75 +     fetch_pixel_64_t		fetch_pixel_64;
    1.76 ++    store_scanline_t		store_scanline_16;
    1.77 +     store_scanline_t		store_scanline_32;
    1.78 +     store_scanline_t		store_scanline_64;
    1.79 + } format_info_t;
    1.80 + 
    1.81 + #define FORMAT_INFO(format) 						\
    1.82 +     {									\
    1.83 + 	PIXMAN_ ## format,						\
    1.84 ++	    NULL,							\
    1.85 + 	    fetch_scanline_ ## format,					\
    1.86 + 	    fetch_scanline_generic_64,					\
    1.87 + 	    fetch_pixel_ ## format, fetch_pixel_generic_64,		\
    1.88 ++	    NULL,							\
    1.89 + 	    store_scanline_ ## format, store_scanline_generic_64	\
    1.90 +     }
    1.91 ++#define FORMAT_INFO16(format) 						\
    1.92 ++    {									\
    1.93 ++	PIXMAN_ ## format,						\
    1.94 ++	    fetch_scanline_16,						\
    1.95 ++	    fetch_scanline_ ## format,					\
    1.96 ++	    fetch_scanline_generic_64,					\
    1.97 ++	    fetch_pixel_ ## format, fetch_pixel_generic_64,		\
    1.98 ++	    store_scanline_16,						\
    1.99 ++	    store_scanline_ ## format, store_scanline_generic_64	\
   1.100 ++    }
   1.101 ++
   1.102 + 
   1.103 + static const format_info_t accessors[] =
   1.104 + {
   1.105 + /* 32 bpp formats */
   1.106 +     FORMAT_INFO (a8r8g8b8),
   1.107 +     FORMAT_INFO (x8r8g8b8),
   1.108 +     FORMAT_INFO (a8b8g8r8),
   1.109 +     FORMAT_INFO (x8b8g8r8),
   1.110 +@@ -1079,18 +1132,18 @@ static const format_info_t accessors[] =
   1.111 +     FORMAT_INFO (r8g8b8x8),
   1.112 +     FORMAT_INFO (x14r6g6b6),
   1.113 + 
   1.114 + /* 24bpp formats */
   1.115 +     FORMAT_INFO (r8g8b8),
   1.116 +     FORMAT_INFO (b8g8r8),
   1.117 +     
   1.118 + /* 16bpp formats */
   1.119 +-    FORMAT_INFO (r5g6b5),
   1.120 +-    FORMAT_INFO (b5g6r5),
   1.121 ++    FORMAT_INFO16 (r5g6b5),
   1.122 ++    FORMAT_INFO16 (b5g6r5),
   1.123 +     
   1.124 +     FORMAT_INFO (a1r5g5b5),
   1.125 +     FORMAT_INFO (x1r5g5b5),
   1.126 +     FORMAT_INFO (a1b5g5r5),
   1.127 +     FORMAT_INFO (x1b5g5r5),
   1.128 +     FORMAT_INFO (a4r4g4b4),
   1.129 +     FORMAT_INFO (x4r4g4b4),
   1.130 +     FORMAT_INFO (a4b4g4r4),
   1.131 +@@ -1132,62 +1185,64 @@ static const format_info_t accessors[] =
   1.132 +     
   1.133 + /* 1bpp formats */
   1.134 +     FORMAT_INFO (a1),
   1.135 +     FORMAT_INFO (g1),
   1.136 +     
   1.137 + /* Wide formats */
   1.138 +     
   1.139 +     { PIXMAN_a2r10g10b10,
   1.140 +-      NULL, fetch_scanline_a2r10g10b10,
   1.141 ++      NULL, NULL, fetch_scanline_a2r10g10b10,
   1.142 +       fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10,
   1.143 +       NULL, store_scanline_a2r10g10b10 },
   1.144 +     
   1.145 +     { PIXMAN_x2r10g10b10,
   1.146 +-      NULL, fetch_scanline_x2r10g10b10,
   1.147 ++      NULL, NULL, fetch_scanline_x2r10g10b10,
   1.148 +       fetch_pixel_generic_lossy_32, fetch_pixel_x2r10g10b10,
   1.149 +       NULL, store_scanline_x2r10g10b10 },
   1.150 +     
   1.151 +     { PIXMAN_a2b10g10r10,
   1.152 +-      NULL, fetch_scanline_a2b10g10r10,
   1.153 ++      NULL, NULL, fetch_scanline_a2b10g10r10,
   1.154 +       fetch_pixel_generic_lossy_32, fetch_pixel_a2b10g10r10,
   1.155 +       NULL, store_scanline_a2b10g10r10 },
   1.156 +     
   1.157 +     { PIXMAN_x2b10g10r10,
   1.158 +-      NULL, fetch_scanline_x2b10g10r10,
   1.159 ++      NULL, NULL, fetch_scanline_x2b10g10r10,
   1.160 +       fetch_pixel_generic_lossy_32, fetch_pixel_x2b10g10r10,
   1.161 +       NULL, store_scanline_x2b10g10r10 },
   1.162 +     
   1.163 + /* YUV formats */
   1.164 +     { PIXMAN_yuy2,
   1.165 +-      fetch_scanline_yuy2, fetch_scanline_generic_64,
   1.166 ++      NULL, fetch_scanline_yuy2, fetch_scanline_generic_64,
   1.167 +       fetch_pixel_yuy2, fetch_pixel_generic_64,
   1.168 +       NULL, NULL },
   1.169 +     
   1.170 +     { PIXMAN_yv12,
   1.171 +-      fetch_scanline_yv12, fetch_scanline_generic_64,
   1.172 ++      NULL, fetch_scanline_yv12, fetch_scanline_generic_64,
   1.173 +       fetch_pixel_yv12, fetch_pixel_generic_64,
   1.174 +       NULL, NULL },
   1.175 +     
   1.176 +     { PIXMAN_null },
   1.177 + };
   1.178 + 
   1.179 + static void
   1.180 + setup_accessors (bits_image_t *image)
   1.181 + {
   1.182 +     const format_info_t *info = accessors;
   1.183 +     
   1.184 +     while (info->format != PIXMAN_null)
   1.185 +     {
   1.186 + 	if (info->format == image->format)
   1.187 + 	{
   1.188 ++	    image->fetch_scanline_16 = info->fetch_scanline_16;
   1.189 + 	    image->fetch_scanline_32 = info->fetch_scanline_32;
   1.190 + 	    image->fetch_scanline_64 = info->fetch_scanline_64;
   1.191 + 	    image->fetch_pixel_32 = info->fetch_pixel_32;
   1.192 + 	    image->fetch_pixel_64 = info->fetch_pixel_64;
   1.193 ++	    image->store_scanline_16 = info->store_scanline_16;
   1.194 + 	    image->store_scanline_32 = info->store_scanline_32;
   1.195 + 	    image->store_scanline_64 = info->store_scanline_64;
   1.196 + 	    
   1.197 + 	    return;
   1.198 + 	}
   1.199 + 	
   1.200 + 	info++;
   1.201 +     }
   1.202 +diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c
   1.203 +--- a/gfx/cairo/libpixman/src/pixman-bits-image.c
   1.204 ++++ b/gfx/cairo/libpixman/src/pixman-bits-image.c
   1.205 +@@ -1247,16 +1247,31 @@ src_get_scanline_wide (pixman_iter_t *it
   1.206 + 
   1.207 + void
   1.208 + _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
   1.209 + {
   1.210 +     if (iter->flags & ITER_NARROW)
   1.211 + 	iter->get_scanline = src_get_scanline_narrow;
   1.212 +     else
   1.213 + 	iter->get_scanline = src_get_scanline_wide;
   1.214 ++
   1.215 ++}
   1.216 ++
   1.217 ++static uint32_t *
   1.218 ++dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
   1.219 ++{
   1.220 ++    pixman_image_t *image  = iter->image;
   1.221 ++    int             x      = iter->x;
   1.222 ++    int             y      = iter->y;
   1.223 ++    int             width  = iter->width;
   1.224 ++    uint32_t *	    buffer = iter->buffer;
   1.225 ++
   1.226 ++    image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask);
   1.227 ++
   1.228 ++    return iter->buffer;
   1.229 + }
   1.230 + 
   1.231 + static uint32_t *
   1.232 + dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
   1.233 + {
   1.234 +     pixman_image_t *image  = iter->image;
   1.235 +     int             x      = iter->x;
   1.236 +     int             y      = iter->y;
   1.237 +@@ -1327,16 +1342,30 @@ dest_get_scanline_wide (pixman_iter_t *i
   1.238 + 	    free (alpha);
   1.239 + 	}
   1.240 +     }
   1.241 + 
   1.242 +     return iter->buffer;
   1.243 + }
   1.244 + 
   1.245 + static void
   1.246 ++dest_write_back_16 (pixman_iter_t *iter)
   1.247 ++{
   1.248 ++    bits_image_t *  image  = &iter->image->bits;
   1.249 ++    int             x      = iter->x;
   1.250 ++    int             y      = iter->y;
   1.251 ++    int             width  = iter->width;
   1.252 ++    const uint32_t *buffer = iter->buffer;
   1.253 ++
   1.254 ++    image->store_scanline_16 (image, x, y, width, buffer);
   1.255 ++
   1.256 ++    iter->y++;
   1.257 ++}
   1.258 ++
   1.259 ++static void
   1.260 + dest_write_back_narrow (pixman_iter_t *iter)
   1.261 + {
   1.262 +     bits_image_t *  image  = &iter->image->bits;
   1.263 +     int             x      = iter->x;
   1.264 +     int             y      = iter->y;
   1.265 +     int             width  = iter->width;
   1.266 +     const uint32_t *buffer = iter->buffer;
   1.267 + 
   1.268 +@@ -1375,28 +1404,41 @@ dest_write_back_wide (pixman_iter_t *ite
   1.269 +     }
   1.270 + 
   1.271 +     iter->y++;
   1.272 + }
   1.273 + 
   1.274 + void
   1.275 + _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter)
   1.276 + {
   1.277 +-    if (iter->flags & ITER_NARROW)
   1.278 ++    if (iter->flags & ITER_16)
   1.279 ++    {
   1.280 ++        if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
   1.281 ++	    (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
   1.282 ++	{
   1.283 ++            iter->get_scanline = _pixman_iter_get_scanline_noop;
   1.284 ++        }
   1.285 ++        else
   1.286 ++        {
   1.287 ++	    iter->get_scanline = dest_get_scanline_16;
   1.288 ++        }
   1.289 ++	iter->write_back = dest_write_back_16;
   1.290 ++    }
   1.291 ++    else if (iter->flags & ITER_NARROW)
   1.292 +     {
   1.293 + 	if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
   1.294 + 	    (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
   1.295 + 	{
   1.296 + 	    iter->get_scanline = _pixman_iter_get_scanline_noop;
   1.297 + 	}
   1.298 + 	else
   1.299 + 	{
   1.300 + 	    iter->get_scanline = dest_get_scanline_narrow;
   1.301 + 	}
   1.302 +-	
   1.303 ++
   1.304 + 	iter->write_back = dest_write_back_narrow;
   1.305 +     }
   1.306 +     else
   1.307 +     {
   1.308 + 	iter->get_scanline = dest_get_scanline_wide;
   1.309 + 	iter->write_back = dest_write_back_wide;
   1.310 +     }
   1.311 + }
   1.312 +diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c
   1.313 +new file mode 100644
   1.314 +--- /dev/null
   1.315 ++++ b/gfx/cairo/libpixman/src/pixman-combine16.c
   1.316 +@@ -0,0 +1,124 @@
   1.317 ++#ifdef HAVE_CONFIG_H
   1.318 ++#include <config.h>
   1.319 ++#endif
   1.320 ++
   1.321 ++#include <math.h>
   1.322 ++#include <string.h>
   1.323 ++
   1.324 ++#include "pixman-private.h"
   1.325 ++
   1.326 ++#include "pixman-combine32.h"
   1.327 ++
   1.328 ++static force_inline uint32_t
   1.329 ++combine_mask (const uint32_t src, const uint32_t mask)
   1.330 ++{
   1.331 ++    uint32_t s, m;
   1.332 ++
   1.333 ++    m = mask >> A_SHIFT;
   1.334 ++
   1.335 ++    if (!m)
   1.336 ++	return 0;
   1.337 ++    s = src;
   1.338 ++
   1.339 ++    UN8x4_MUL_UN8 (s, m);
   1.340 ++
   1.341 ++    return s;
   1.342 ++}
   1.343 ++
   1.344 ++static inline uint32_t convert_0565_to_8888(uint16_t color)
   1.345 ++{
   1.346 ++    return CONVERT_0565_TO_8888(color);
   1.347 ++}
   1.348 ++
   1.349 ++static inline uint16_t convert_8888_to_0565(uint32_t color)
   1.350 ++{
   1.351 ++    return CONVERT_8888_TO_0565(color);
   1.352 ++}
   1.353 ++
   1.354 ++static void
   1.355 ++combine_src_u (pixman_implementation_t *imp,
   1.356 ++               pixman_op_t              op,
   1.357 ++               uint32_t *               dest,
   1.358 ++               const uint32_t *         src,
   1.359 ++               const uint32_t *         mask,
   1.360 ++               int                      width)
   1.361 ++{
   1.362 ++    int i;
   1.363 ++
   1.364 ++    if (!mask)
   1.365 ++	memcpy (dest, src, width * sizeof (uint16_t));
   1.366 ++    else
   1.367 ++    {
   1.368 ++	uint16_t *d = (uint16_t*)dest;
   1.369 ++	uint16_t *src16 = (uint16_t*)src;
   1.370 ++	for (i = 0; i < width; ++i)
   1.371 ++	{
   1.372 ++	    if ((*mask & 0xff000000) == 0xff000000) {
   1.373 ++		// it's likely worth special casing
   1.374 ++		// fully opaque because it avoids
   1.375 ++		// the cost of conversion as well the multiplication
   1.376 ++		*(d + i) = *src16;
   1.377 ++	    } else {
   1.378 ++		// the mask is still 32bits
   1.379 ++		uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask);
   1.380 ++		*(d + i) = convert_8888_to_0565(s);
   1.381 ++	    }
   1.382 ++	    mask++;
   1.383 ++	    src16++;
   1.384 ++	}
   1.385 ++    }
   1.386 ++
   1.387 ++}
   1.388 ++
   1.389 ++static void
   1.390 ++combine_over_u (pixman_implementation_t *imp,
   1.391 ++               pixman_op_t              op,
   1.392 ++               uint32_t *                dest,
   1.393 ++               const uint32_t *          src,
   1.394 ++               const uint32_t *          mask,
   1.395 ++               int                      width)
   1.396 ++{
   1.397 ++    int i;
   1.398 ++
   1.399 ++    if (!mask)
   1.400 ++	memcpy (dest, src, width * sizeof (uint16_t));
   1.401 ++    else
   1.402 ++    {
   1.403 ++	uint16_t *d = (uint16_t*)dest;
   1.404 ++	uint16_t *src16 = (uint16_t*)src;
   1.405 ++	for (i = 0; i < width; ++i)
   1.406 ++	{
   1.407 ++	    if ((*mask & 0xff000000) == 0xff000000) {
   1.408 ++		// it's likely worth special casing
   1.409 ++		// fully opaque because it avoids
   1.410 ++		// the cost of conversion as well the multiplication
   1.411 ++		*(d + i) = *src16;
   1.412 ++	    } else if ((*mask & 0xff000000) == 0x00000000) {
   1.413 ++		// keep the dest the same
   1.414 ++	    } else {
   1.415 ++		// the mask is still 32bits
   1.416 ++		uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask);
   1.417 ++		uint32_t ia = ALPHA_8 (~s);
   1.418 ++		uint32_t d32 = convert_0565_to_8888(*(d + i));
   1.419 ++		UN8x4_MUL_UN8_ADD_UN8x4 (d32, ia, s);
   1.420 ++		*(d + i) = convert_8888_to_0565(d32);
   1.421 ++	    }
   1.422 ++	    mask++;
   1.423 ++	    src16++;
   1.424 ++	}
   1.425 ++    }
   1.426 ++
   1.427 ++}
   1.428 ++
   1.429 ++
   1.430 ++void
   1.431 ++_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp)
   1.432 ++{
   1.433 ++    int i;
   1.434 ++    for (i = 0; i < PIXMAN_N_OPERATORS; i++) {
   1.435 ++	imp->combine_16[i] = NULL;
   1.436 ++    }
   1.437 ++    imp->combine_16[PIXMAN_OP_SRC] = combine_src_u;
   1.438 ++    imp->combine_16[PIXMAN_OP_OVER] = combine_over_u;
   1.439 ++}
   1.440 ++
   1.441 +diff --git a/gfx/cairo/libpixman/src/pixman-general.c b/gfx/cairo/libpixman/src/pixman-general.c
   1.442 +--- a/gfx/cairo/libpixman/src/pixman-general.c
   1.443 ++++ b/gfx/cairo/libpixman/src/pixman-general.c
   1.444 +@@ -106,46 +106,61 @@ general_composite_rect  (pixman_implemen
   1.445 +     PIXMAN_COMPOSITE_ARGS (info);
   1.446 +     uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8];
   1.447 +     uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer;
   1.448 +     uint8_t *src_buffer, *mask_buffer, *dest_buffer;
   1.449 +     pixman_iter_t src_iter, mask_iter, dest_iter;
   1.450 +     pixman_combine_32_func_t compose;
   1.451 +     pixman_bool_t component_alpha;
   1.452 +     iter_flags_t narrow, src_flags;
   1.453 ++    iter_flags_t rgb16;
   1.454 +     int Bpp;
   1.455 +     int i;
   1.456 + 
   1.457 +     if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT)		    &&
   1.458 + 	(!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) &&
   1.459 + 	(dest_image->common.flags & FAST_PATH_NARROW_FORMAT))
   1.460 +     {
   1.461 + 	narrow = ITER_NARROW;
   1.462 + 	Bpp = 4;
   1.463 +     }
   1.464 +     else
   1.465 +     {
   1.466 + 	narrow = 0;
   1.467 + 	Bpp = 8;
   1.468 +     }
   1.469 + 
   1.470 ++    // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps
   1.471 ++    // by having it deal more specifically with different intermediate formats
   1.472 ++    if (
   1.473 ++	(dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) &&
   1.474 ++	( op == PIXMAN_OP_SRC ||
   1.475 ++         (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE))
   1.476 ++	)
   1.477 ++	) {
   1.478 ++	rgb16 = ITER_16;
   1.479 ++    } else {
   1.480 ++	rgb16 = 0;
   1.481 ++    }
   1.482 ++
   1.483 ++
   1.484 +     if (width * Bpp > SCANLINE_BUFFER_LENGTH)
   1.485 +     {
   1.486 + 	scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
   1.487 + 
   1.488 + 	if (!scanline_buffer)
   1.489 + 	    return;
   1.490 +     }
   1.491 + 
   1.492 +     src_buffer = scanline_buffer;
   1.493 +     mask_buffer = src_buffer + width * Bpp;
   1.494 +     dest_buffer = mask_buffer + width * Bpp;
   1.495 + 
   1.496 +     /* src iter */
   1.497 +-    src_flags = narrow | op_flags[op].src;
   1.498 ++    src_flags = narrow | op_flags[op].src | rgb16;
   1.499 + 
   1.500 +     _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image,
   1.501 + 					  src_x, src_y, width, height,
   1.502 + 					  src_buffer, src_flags);
   1.503 + 
   1.504 +     /* mask iter */
   1.505 +     if ((src_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
   1.506 + 	(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
   1.507 +@@ -164,20 +179,20 @@ general_composite_rect  (pixman_implemen
   1.508 + 
   1.509 +     _pixman_implementation_src_iter_init (
   1.510 + 	imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height,
   1.511 + 	mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB));
   1.512 + 
   1.513 +     /* dest iter */
   1.514 +     _pixman_implementation_dest_iter_init (
   1.515 + 	imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height,
   1.516 +-	dest_buffer, narrow | op_flags[op].dst);
   1.517 ++	dest_buffer, narrow | op_flags[op].dst | rgb16);
   1.518 + 
   1.519 +     compose = _pixman_implementation_lookup_combiner (
   1.520 +-	imp->toplevel, op, component_alpha, narrow);
   1.521 ++	imp->toplevel, op, component_alpha, narrow, !!rgb16);
   1.522 + 
   1.523 +     if (!compose)
   1.524 + 	return;
   1.525 + 
   1.526 +     for (i = 0; i < height; ++i)
   1.527 +     {
   1.528 + 	uint32_t *s, *m, *d;
   1.529 + 
   1.530 +@@ -234,16 +249,17 @@ general_fill (pixman_implementation_t *i
   1.531 +     return FALSE;
   1.532 + }
   1.533 + 
   1.534 + pixman_implementation_t *
   1.535 + _pixman_implementation_create_general (void)
   1.536 + {
   1.537 +     pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
   1.538 + 
   1.539 ++    _pixman_setup_combiner_functions_16 (imp);
   1.540 +     _pixman_setup_combiner_functions_32 (imp);
   1.541 +     _pixman_setup_combiner_functions_64 (imp);
   1.542 + 
   1.543 +     imp->blt = general_blt;
   1.544 +     imp->fill = general_fill;
   1.545 +     imp->src_iter_init = general_src_iter_init;
   1.546 +     imp->dest_iter_init = general_dest_iter_init;
   1.547 + 
   1.548 +diff --git a/gfx/cairo/libpixman/src/pixman-image.c b/gfx/cairo/libpixman/src/pixman-image.c
   1.549 +--- a/gfx/cairo/libpixman/src/pixman-image.c
   1.550 ++++ b/gfx/cairo/libpixman/src/pixman-image.c
   1.551 +@@ -451,16 +451,20 @@ compute_image_info (pixman_image_t *imag
   1.552 + 		flags |= FAST_PATH_IS_OPAQUE;
   1.553 + 	}
   1.554 + 
   1.555 + 	if (image->bits.read_func || image->bits.write_func)
   1.556 + 	    flags &= ~FAST_PATH_NO_ACCESSORS;
   1.557 + 
   1.558 + 	if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
   1.559 + 	    flags &= ~FAST_PATH_NARROW_FORMAT;
   1.560 ++
   1.561 ++	if (image->bits.format == PIXMAN_r5g6b5)
   1.562 ++	    flags |= FAST_PATH_16_FORMAT;
   1.563 ++
   1.564 + 	break;
   1.565 + 
   1.566 +     case RADIAL:
   1.567 + 	code = PIXMAN_unknown;
   1.568 + 
   1.569 + 	/*
   1.570 + 	 * As explained in pixman-radial-gradient.c, every point of
   1.571 + 	 * the plane has a valid associated radius (and thus will be
   1.572 +diff --git a/gfx/cairo/libpixman/src/pixman-implementation.c b/gfx/cairo/libpixman/src/pixman-implementation.c
   1.573 +--- a/gfx/cairo/libpixman/src/pixman-implementation.c
   1.574 ++++ b/gfx/cairo/libpixman/src/pixman-implementation.c
   1.575 +@@ -101,45 +101,51 @@ pixman_implementation_t *
   1.576 +     imp->fill = delegate_fill;
   1.577 +     imp->src_iter_init = delegate_src_iter_init;
   1.578 +     imp->dest_iter_init = delegate_dest_iter_init;
   1.579 + 
   1.580 +     imp->fast_paths = fast_paths;
   1.581 + 
   1.582 +     for (i = 0; i < PIXMAN_N_OPERATORS; ++i)
   1.583 +     {
   1.584 ++	imp->combine_16[i] = NULL;
   1.585 + 	imp->combine_32[i] = NULL;
   1.586 + 	imp->combine_64[i] = NULL;
   1.587 + 	imp->combine_32_ca[i] = NULL;
   1.588 + 	imp->combine_64_ca[i] = NULL;
   1.589 +     }
   1.590 + 
   1.591 +     return imp;
   1.592 + }
   1.593 + 
   1.594 + pixman_combine_32_func_t
   1.595 + _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
   1.596 + 					pixman_op_t		 op,
   1.597 + 					pixman_bool_t		 component_alpha,
   1.598 +-					pixman_bool_t		 narrow)
   1.599 ++					pixman_bool_t		 narrow,
   1.600 ++					pixman_bool_t		 rgb16)
   1.601 + {
   1.602 +     pixman_combine_32_func_t f;
   1.603 + 
   1.604 +     do
   1.605 +     {
   1.606 + 	pixman_combine_32_func_t (*combiners[]) =
   1.607 + 	{
   1.608 + 	    (pixman_combine_32_func_t *)imp->combine_64,
   1.609 + 	    (pixman_combine_32_func_t *)imp->combine_64_ca,
   1.610 + 	    imp->combine_32,
   1.611 + 	    imp->combine_32_ca,
   1.612 ++	    (pixman_combine_32_func_t *)imp->combine_16,
   1.613 ++	    NULL,
   1.614 + 	};
   1.615 +-
   1.616 +-	f = combiners[component_alpha | (narrow << 1)][op];
   1.617 +-
   1.618 ++        if (rgb16) {
   1.619 ++            f = combiners[4][op];
   1.620 ++        } else {
   1.621 ++            f = combiners[component_alpha + (narrow << 1)][op];
   1.622 ++        }
   1.623 + 	imp = imp->delegate;
   1.624 +     }
   1.625 +     while (!f);
   1.626 + 
   1.627 +     return f;
   1.628 + }
   1.629 + 
   1.630 + pixman_bool_t
   1.631 +diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
   1.632 +--- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c
   1.633 ++++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
   1.634 +@@ -217,42 +217,185 @@ linear_get_scanline_narrow (pixman_iter_
   1.635 + 	}
   1.636 +     }
   1.637 + 
   1.638 +     iter->y++;
   1.639 + 
   1.640 +     return iter->buffer;
   1.641 + }
   1.642 + 
   1.643 ++static uint16_t convert_8888_to_0565(uint32_t color)
   1.644 ++{
   1.645 ++    return CONVERT_8888_TO_0565(color);
   1.646 ++}
   1.647 ++
   1.648 ++static uint32_t *
   1.649 ++linear_get_scanline_16 (pixman_iter_t  *iter,
   1.650 ++			const uint32_t *mask)
   1.651 ++{
   1.652 ++    pixman_image_t *image  = iter->image;
   1.653 ++    int             x      = iter->x;
   1.654 ++    int             y      = iter->y;
   1.655 ++    int             width  = iter->width;
   1.656 ++    uint16_t *      buffer = (uint16_t*)iter->buffer;
   1.657 ++
   1.658 ++    pixman_vector_t v, unit;
   1.659 ++    pixman_fixed_32_32_t l;
   1.660 ++    pixman_fixed_48_16_t dx, dy;
   1.661 ++    gradient_t *gradient = (gradient_t *)image;
   1.662 ++    linear_gradient_t *linear = (linear_gradient_t *)image;
   1.663 ++    uint16_t *end = buffer + width;
   1.664 ++    pixman_gradient_walker_t walker;
   1.665 ++
   1.666 ++    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
   1.667 ++
   1.668 ++    /* reference point is the center of the pixel */
   1.669 ++    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
   1.670 ++    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
   1.671 ++    v.vector[2] = pixman_fixed_1;
   1.672 ++
   1.673 ++    if (image->common.transform)
   1.674 ++    {
   1.675 ++	if (!pixman_transform_point_3d (image->common.transform, &v))
   1.676 ++	    return iter->buffer;
   1.677 ++
   1.678 ++	unit.vector[0] = image->common.transform->matrix[0][0];
   1.679 ++	unit.vector[1] = image->common.transform->matrix[1][0];
   1.680 ++	unit.vector[2] = image->common.transform->matrix[2][0];
   1.681 ++    }
   1.682 ++    else
   1.683 ++    {
   1.684 ++	unit.vector[0] = pixman_fixed_1;
   1.685 ++	unit.vector[1] = 0;
   1.686 ++	unit.vector[2] = 0;
   1.687 ++    }
   1.688 ++
   1.689 ++    dx = linear->p2.x - linear->p1.x;
   1.690 ++    dy = linear->p2.y - linear->p1.y;
   1.691 ++
   1.692 ++    l = dx * dx + dy * dy;
   1.693 ++
   1.694 ++    if (l == 0 || unit.vector[2] == 0)
   1.695 ++    {
   1.696 ++	/* affine transformation only */
   1.697 ++        pixman_fixed_32_32_t t, next_inc;
   1.698 ++	double inc;
   1.699 ++
   1.700 ++	if (l == 0 || v.vector[2] == 0)
   1.701 ++	{
   1.702 ++	    t = 0;
   1.703 ++	    inc = 0;
   1.704 ++	}
   1.705 ++	else
   1.706 ++	{
   1.707 ++	    double invden, v2;
   1.708 ++
   1.709 ++	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   1.710 ++		(l * (double) v.vector[2]);
   1.711 ++	    v2 = v.vector[2] * (1. / pixman_fixed_1);
   1.712 ++	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   1.713 ++		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   1.714 ++	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
   1.715 ++	}
   1.716 ++	next_inc = 0;
   1.717 ++
   1.718 ++	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
   1.719 ++	{
   1.720 ++	    register uint16_t color;
   1.721 ++
   1.722 ++	    color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
   1.723 ++	    while (buffer < end)
   1.724 ++		*buffer++ = color;
   1.725 ++	}
   1.726 ++	else
   1.727 ++	{
   1.728 ++	    int i;
   1.729 ++
   1.730 ++	    i = 0;
   1.731 ++	    while (buffer < end)
   1.732 ++	    {
   1.733 ++		if (!mask || *mask++)
   1.734 ++		{
   1.735 ++		    *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
   1.736 ++										  t + next_inc));
   1.737 ++		}
   1.738 ++		i++;
   1.739 ++		next_inc = inc * i;
   1.740 ++		buffer++;
   1.741 ++	    }
   1.742 ++	}
   1.743 ++    }
   1.744 ++    else
   1.745 ++    {
   1.746 ++	/* projective transformation */
   1.747 ++        double t;
   1.748 ++
   1.749 ++	t = 0;
   1.750 ++
   1.751 ++	while (buffer < end)
   1.752 ++	{
   1.753 ++	    if (!mask || *mask++)
   1.754 ++	    {
   1.755 ++	        if (v.vector[2] != 0)
   1.756 ++		{
   1.757 ++		    double invden, v2;
   1.758 ++
   1.759 ++		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   1.760 ++			(l * (double) v.vector[2]);
   1.761 ++		    v2 = v.vector[2] * (1. / pixman_fixed_1);
   1.762 ++		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   1.763 ++			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   1.764 ++		}
   1.765 ++
   1.766 ++		*buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
   1.767 ++	    }
   1.768 ++
   1.769 ++	    ++buffer;
   1.770 ++
   1.771 ++	    v.vector[0] += unit.vector[0];
   1.772 ++	    v.vector[1] += unit.vector[1];
   1.773 ++	    v.vector[2] += unit.vector[2];
   1.774 ++	}
   1.775 ++    }
   1.776 ++
   1.777 ++    iter->y++;
   1.778 ++
   1.779 ++    return iter->buffer;
   1.780 ++}
   1.781 ++
   1.782 + static uint32_t *
   1.783 + linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
   1.784 + {
   1.785 +     uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
   1.786 + 
   1.787 +     pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
   1.788 + 
   1.789 +     return buffer;
   1.790 + }
   1.791 + 
   1.792 + void
   1.793 + _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
   1.794 + {
   1.795 +     if (linear_gradient_is_horizontal (
   1.796 + 	    iter->image, iter->x, iter->y, iter->width, iter->height))
   1.797 +     {
   1.798 +-	if (iter->flags & ITER_NARROW)
   1.799 ++	if (iter->flags & ITER_16)
   1.800 ++	    linear_get_scanline_16 (iter, NULL);
   1.801 ++	else if (iter->flags & ITER_NARROW)
   1.802 + 	    linear_get_scanline_narrow (iter, NULL);
   1.803 + 	else
   1.804 + 	    linear_get_scanline_wide (iter, NULL);
   1.805 + 
   1.806 + 	iter->get_scanline = _pixman_iter_get_scanline_noop;
   1.807 +     }
   1.808 +     else
   1.809 +     {
   1.810 +-	if (iter->flags & ITER_NARROW)
   1.811 ++	if (iter->flags & ITER_16)
   1.812 ++	    iter->get_scanline = linear_get_scanline_16;
   1.813 ++	else if (iter->flags & ITER_NARROW)
   1.814 + 	    iter->get_scanline = linear_get_scanline_narrow;
   1.815 + 	else
   1.816 + 	    iter->get_scanline = linear_get_scanline_wide;
   1.817 +     }
   1.818 + }
   1.819 + 
   1.820 + PIXMAN_EXPORT pixman_image_t *
   1.821 + pixman_image_create_linear_gradient (pixman_point_fixed_t *        p1,
   1.822 +diff --git a/gfx/cairo/libpixman/src/pixman-private.h b/gfx/cairo/libpixman/src/pixman-private.h
   1.823 +--- a/gfx/cairo/libpixman/src/pixman-private.h
   1.824 ++++ b/gfx/cairo/libpixman/src/pixman-private.h
   1.825 +@@ -152,24 +152,28 @@ struct bits_image
   1.826 +     int                        height;
   1.827 +     uint32_t *                 bits;
   1.828 +     uint32_t *                 free_me;
   1.829 +     int                        rowstride;  /* in number of uint32_t's */
   1.830 + 
   1.831 +     fetch_scanline_t           get_scanline_32;
   1.832 +     fetch_scanline_t           get_scanline_64;
   1.833 + 
   1.834 ++    fetch_scanline_t           fetch_scanline_16;
   1.835 ++
   1.836 +     fetch_scanline_t           fetch_scanline_32;
   1.837 +     fetch_pixel_32_t	       fetch_pixel_32;
   1.838 +     store_scanline_t           store_scanline_32;
   1.839 + 
   1.840 +     fetch_scanline_t           fetch_scanline_64;
   1.841 +     fetch_pixel_64_t	       fetch_pixel_64;
   1.842 +     store_scanline_t           store_scanline_64;
   1.843 + 
   1.844 ++    store_scanline_t           store_scanline_16;
   1.845 ++
   1.846 +     /* Used for indirect access to the bits */
   1.847 +     pixman_read_memory_func_t  read_func;
   1.848 +     pixman_write_memory_func_t write_func;
   1.849 + };
   1.850 + 
   1.851 + union pixman_image
   1.852 + {
   1.853 +     image_type_t       type;
   1.854 +@@ -202,17 +206,24 @@ typedef enum
   1.855 +      * destination.
   1.856 +      *
   1.857 +      * When he destination is xRGB, this is useful knowledge, because then
   1.858 +      * we can treat it as if it were ARGB, which means in some cases we can
   1.859 +      * avoid copying it to a temporary buffer.
   1.860 +      */
   1.861 +     ITER_LOCALIZED_ALPHA =	(1 << 1),
   1.862 +     ITER_IGNORE_ALPHA =		(1 << 2),
   1.863 +-    ITER_IGNORE_RGB =		(1 << 3)
   1.864 ++    ITER_IGNORE_RGB =		(1 << 3),
   1.865 ++
   1.866 ++    /* With the addition of ITER_16 we now have two flags that to represent
   1.867 ++     * 3 pipelines. This means that there can be an invalid state when
   1.868 ++     * both ITER_NARROW and ITER_16 are set. In this case
   1.869 ++     * ITER_16 overrides NARROW and we should use the 16 bit pipeline.
   1.870 ++     * Note: ITER_16 still has a 32 bit mask, which is a bit weird. */
   1.871 ++    ITER_16 =			(1 << 4)
   1.872 + } iter_flags_t;
   1.873 + 
   1.874 + struct pixman_iter_t
   1.875 + {
   1.876 +     /* These are initialized by _pixman_implementation_{src,dest}_init */
   1.877 +     pixman_image_t *		image;
   1.878 +     uint32_t *			buffer;
   1.879 +     int				x, y;
   1.880 +@@ -429,16 +440,17 @@ typedef pixman_bool_t (*pixman_fill_func
   1.881 + 					     int                      x,
   1.882 + 					     int                      y,
   1.883 + 					     int                      width,
   1.884 + 					     int                      height,
   1.885 + 					     uint32_t                 xor);
   1.886 + typedef void (*pixman_iter_init_func_t) (pixman_implementation_t *imp,
   1.887 +                                          pixman_iter_t           *iter);
   1.888 + 
   1.889 ++void _pixman_setup_combiner_functions_16 (pixman_implementation_t *imp);
   1.890 + void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp);
   1.891 + void _pixman_setup_combiner_functions_64 (pixman_implementation_t *imp);
   1.892 + 
   1.893 + typedef struct
   1.894 + {
   1.895 +     pixman_op_t             op;
   1.896 +     pixman_format_code_t    src_format;
   1.897 +     uint32_t		    src_flags;
   1.898 +@@ -459,32 +471,34 @@ struct pixman_implementation_t
   1.899 +     pixman_fill_func_t		fill;
   1.900 +     pixman_iter_init_func_t     src_iter_init;
   1.901 +     pixman_iter_init_func_t     dest_iter_init;
   1.902 + 
   1.903 +     pixman_combine_32_func_t	combine_32[PIXMAN_N_OPERATORS];
   1.904 +     pixman_combine_32_func_t	combine_32_ca[PIXMAN_N_OPERATORS];
   1.905 +     pixman_combine_64_func_t	combine_64[PIXMAN_N_OPERATORS];
   1.906 +     pixman_combine_64_func_t	combine_64_ca[PIXMAN_N_OPERATORS];
   1.907 ++    pixman_combine_64_func_t	combine_16[PIXMAN_N_OPERATORS];
   1.908 + };
   1.909 + 
   1.910 + uint32_t
   1.911 + _pixman_image_get_solid (pixman_implementation_t *imp,
   1.912 + 			 pixman_image_t *         image,
   1.913 +                          pixman_format_code_t     format);
   1.914 + 
   1.915 + pixman_implementation_t *
   1.916 + _pixman_implementation_create (pixman_implementation_t *delegate,
   1.917 + 			       const pixman_fast_path_t *fast_paths);
   1.918 + 
   1.919 + pixman_combine_32_func_t
   1.920 + _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
   1.921 + 					pixman_op_t		 op,
   1.922 + 					pixman_bool_t		 component_alpha,
   1.923 +-					pixman_bool_t		 wide);
   1.924 ++					pixman_bool_t		 wide,
   1.925 ++					pixman_bool_t		 rgb16);
   1.926 + 
   1.927 + pixman_bool_t
   1.928 + _pixman_implementation_blt (pixman_implementation_t *imp,
   1.929 +                             uint32_t *               src_bits,
   1.930 +                             uint32_t *               dst_bits,
   1.931 +                             int                      src_stride,
   1.932 +                             int                      dst_stride,
   1.933 +                             int                      src_bpp,
   1.934 +@@ -613,16 +627,17 @@ uint32_t *
   1.935 + #define FAST_PATH_Y_UNIT_ZERO			(1 << 18)
   1.936 + #define FAST_PATH_BILINEAR_FILTER		(1 << 19)
   1.937 + #define FAST_PATH_ROTATE_90_TRANSFORM		(1 << 20)
   1.938 + #define FAST_PATH_ROTATE_180_TRANSFORM		(1 << 21)
   1.939 + #define FAST_PATH_ROTATE_270_TRANSFORM		(1 << 22)
   1.940 + #define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST	(1 << 23)
   1.941 + #define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR	(1 << 24)
   1.942 + #define FAST_PATH_BITS_IMAGE			(1 << 25)
   1.943 ++#define FAST_PATH_16_FORMAT			(1 << 26)
   1.944 + 
   1.945 + #define FAST_PATH_PAD_REPEAT						\
   1.946 +     (FAST_PATH_NO_NONE_REPEAT		|				\
   1.947 +      FAST_PATH_NO_NORMAL_REPEAT		|				\
   1.948 +      FAST_PATH_NO_REFLECT_REPEAT)
   1.949 + 
   1.950 + #define FAST_PATH_NORMAL_REPEAT						\
   1.951 +     (FAST_PATH_NO_NONE_REPEAT		|				\
   1.952 +diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   1.953 +--- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   1.954 ++++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   1.955 +@@ -395,35 +395,289 @@ radial_get_scanline_narrow (pixman_iter_
   1.956 + 	    v.vector[2] += unit.vector[2];
   1.957 + 	}
   1.958 +     }
   1.959 + 
   1.960 +     iter->y++;
   1.961 +     return iter->buffer;
   1.962 + }
   1.963 + 
   1.964 ++static uint16_t convert_8888_to_0565(uint32_t color)
   1.965 ++{
   1.966 ++    return CONVERT_8888_TO_0565(color);
   1.967 ++}
   1.968 ++
   1.969 ++static uint32_t *
   1.970 ++radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
   1.971 ++{
   1.972 ++    /*
   1.973 ++     * Implementation of radial gradients following the PDF specification.
   1.974 ++     * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
   1.975 ++     * Manual (PDF 32000-1:2008 at the time of this writing).
   1.976 ++     *
   1.977 ++     * In the radial gradient problem we are given two circles (c₁,r₁) and
   1.978 ++     * (c₂,r₂) that define the gradient itself.
   1.979 ++     *
   1.980 ++     * Mathematically the gradient can be defined as the family of circles
   1.981 ++     *
   1.982 ++     *     ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
   1.983 ++     *
   1.984 ++     * excluding those circles whose radius would be < 0. When a point
   1.985 ++     * belongs to more than one circle, the one with a bigger t is the only
   1.986 ++     * one that contributes to its color. When a point does not belong
   1.987 ++     * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
   1.988 ++     * Further limitations on the range of values for t are imposed when
   1.989 ++     * the gradient is not repeated, namely t must belong to [0,1].
   1.990 ++     *
   1.991 ++     * The graphical result is the same as drawing the valid (radius > 0)
   1.992 ++     * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
   1.993 ++     * is not repeated) using SOURCE operator composition.
   1.994 ++     *
   1.995 ++     * It looks like a cone pointing towards the viewer if the ending circle
   1.996 ++     * is smaller than the starting one, a cone pointing inside the page if
   1.997 ++     * the starting circle is the smaller one and like a cylinder if they
   1.998 ++     * have the same radius.
   1.999 ++     *
  1.1000 ++     * What we actually do is, given the point whose color we are interested
  1.1001 ++     * in, compute the t values for that point, solving for t in:
  1.1002 ++     *
  1.1003 ++     *     length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
  1.1004 ++     *
  1.1005 ++     * Let's rewrite it in a simpler way, by defining some auxiliary
  1.1006 ++     * variables:
  1.1007 ++     *
  1.1008 ++     *     cd = c₂ - c₁
  1.1009 ++     *     pd = p - c₁
  1.1010 ++     *     dr = r₂ - r₁
  1.1011 ++     *     length(t·cd - pd) = r₁ + t·dr
  1.1012 ++     *
  1.1013 ++     * which actually means
  1.1014 ++     *
  1.1015 ++     *     hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
  1.1016 ++     *
  1.1017 ++     * or
  1.1018 ++     *
  1.1019 ++     *     ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
  1.1020 ++     *
  1.1021 ++     * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
  1.1022 ++     *
  1.1023 ++     *     (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
  1.1024 ++     *
  1.1025 ++     * where we can actually expand the squares and solve for t:
  1.1026 ++     *
  1.1027 ++     *     t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
  1.1028 ++     *       = r₁² + 2·r₁·t·dr + t²·dr²
  1.1029 ++     *
  1.1030 ++     *     (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
  1.1031 ++     *         (pdx² + pdy² - r₁²) = 0
  1.1032 ++     *
  1.1033 ++     *     A = cdx² + cdy² - dr²
  1.1034 ++     *     B = pdx·cdx + pdy·cdy + r₁·dr
  1.1035 ++     *     C = pdx² + pdy² - r₁²
  1.1036 ++     *     At² - 2Bt + C = 0
  1.1037 ++     *
  1.1038 ++     * The solutions (unless the equation degenerates because of A = 0) are:
  1.1039 ++     *
  1.1040 ++     *     t = (B ± ⎷(B² - A·C)) / A
  1.1041 ++     *
  1.1042 ++     * The solution we are going to prefer is the bigger one, unless the
  1.1043 ++     * radius associated to it is negative (or it falls outside the valid t
  1.1044 ++     * range).
  1.1045 ++     *
  1.1046 ++     * Additional observations (useful for optimizations):
  1.1047 ++     * A does not depend on p
  1.1048 ++     *
  1.1049 ++     * A < 0 <=> one of the two circles completely contains the other one
  1.1050 ++     *   <=> for every p, the radiuses associated with the two t solutions
  1.1051 ++     *       have opposite sign
  1.1052 ++     */
  1.1053 ++    pixman_image_t *image = iter->image;
  1.1054 ++    int x = iter->x;
  1.1055 ++    int y = iter->y;
  1.1056 ++    int width = iter->width;
  1.1057 ++    uint16_t *buffer = iter->buffer;
  1.1058 ++
  1.1059 ++    gradient_t *gradient = (gradient_t *)image;
  1.1060 ++    radial_gradient_t *radial = (radial_gradient_t *)image;
  1.1061 ++    uint16_t *end = buffer + width;
  1.1062 ++    pixman_gradient_walker_t walker;
  1.1063 ++    pixman_vector_t v, unit;
  1.1064 ++
  1.1065 ++    /* reference point is the center of the pixel */
  1.1066 ++    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
  1.1067 ++    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
  1.1068 ++    v.vector[2] = pixman_fixed_1;
  1.1069 ++
  1.1070 ++    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
  1.1071 ++
  1.1072 ++    if (image->common.transform)
  1.1073 ++    {
  1.1074 ++	if (!pixman_transform_point_3d (image->common.transform, &v))
  1.1075 ++	    return iter->buffer;
  1.1076 ++
  1.1077 ++	unit.vector[0] = image->common.transform->matrix[0][0];
  1.1078 ++	unit.vector[1] = image->common.transform->matrix[1][0];
  1.1079 ++	unit.vector[2] = image->common.transform->matrix[2][0];
  1.1080 ++    }
  1.1081 ++    else
  1.1082 ++    {
  1.1083 ++	unit.vector[0] = pixman_fixed_1;
  1.1084 ++	unit.vector[1] = 0;
  1.1085 ++	unit.vector[2] = 0;
  1.1086 ++    }
  1.1087 ++
  1.1088 ++    if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
  1.1089 ++    {
  1.1090 ++	/*
  1.1091 ++	 * Given:
  1.1092 ++	 *
  1.1093 ++	 * t = (B ± ⎷(B² - A·C)) / A
  1.1094 ++	 *
  1.1095 ++	 * where
  1.1096 ++	 *
  1.1097 ++	 * A = cdx² + cdy² - dr²
  1.1098 ++	 * B = pdx·cdx + pdy·cdy + r₁·dr
  1.1099 ++	 * C = pdx² + pdy² - r₁²
  1.1100 ++	 * det = B² - A·C
  1.1101 ++	 *
  1.1102 ++	 * Since we have an affine transformation, we know that (pdx, pdy)
  1.1103 ++	 * increase linearly with each pixel,
  1.1104 ++	 *
  1.1105 ++	 * pdx = pdx₀ + n·ux,
  1.1106 ++	 * pdy = pdy₀ + n·uy,
  1.1107 ++	 *
  1.1108 ++	 * we can then express B, C and det through multiple differentiation.
  1.1109 ++	 */
  1.1110 ++	pixman_fixed_32_32_t b, db, c, dc, ddc;
  1.1111 ++
  1.1112 ++	/* warning: this computation may overflow */
  1.1113 ++	v.vector[0] -= radial->c1.x;
  1.1114 ++	v.vector[1] -= radial->c1.y;
  1.1115 ++
  1.1116 ++	/*
  1.1117 ++	 * B and C are computed and updated exactly.
  1.1118 ++	 * If fdot was used instead of dot, in the worst case it would
  1.1119 ++	 * lose 11 bits of precision in each of the multiplication and
  1.1120 ++	 * summing up would zero out all the bit that were preserved,
  1.1121 ++	 * thus making the result 0 instead of the correct one.
  1.1122 ++	 * This would mean a worst case of unbound relative error or
  1.1123 ++	 * about 2^10 absolute error
  1.1124 ++	 */
  1.1125 ++	b = dot (v.vector[0], v.vector[1], radial->c1.radius,
  1.1126 ++		 radial->delta.x, radial->delta.y, radial->delta.radius);
  1.1127 ++	db = dot (unit.vector[0], unit.vector[1], 0,
  1.1128 ++		  radial->delta.x, radial->delta.y, 0);
  1.1129 ++
  1.1130 ++	c = dot (v.vector[0], v.vector[1],
  1.1131 ++		 -((pixman_fixed_48_16_t) radial->c1.radius),
  1.1132 ++		 v.vector[0], v.vector[1], radial->c1.radius);
  1.1133 ++	dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
  1.1134 ++		  2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
  1.1135 ++		  0,
  1.1136 ++		  unit.vector[0], unit.vector[1], 0);
  1.1137 ++	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
  1.1138 ++		       unit.vector[0], unit.vector[1], 0);
  1.1139 ++
  1.1140 ++	while (buffer < end)
  1.1141 ++	{
  1.1142 ++	    if (!mask || *mask++)
  1.1143 ++	    {
  1.1144 ++		*buffer = convert_8888_to_0565(
  1.1145 ++			  radial_compute_color (radial->a, b, c,
  1.1146 ++						radial->inva,
  1.1147 ++						radial->delta.radius,
  1.1148 ++						radial->mindr,
  1.1149 ++						&walker,
  1.1150 ++						image->common.repeat));
  1.1151 ++	    }
  1.1152 ++
  1.1153 ++	    b += db;
  1.1154 ++	    c += dc;
  1.1155 ++	    dc += ddc;
  1.1156 ++	    ++buffer;
  1.1157 ++	}
  1.1158 ++    }
  1.1159 ++    else
  1.1160 ++    {
  1.1161 ++	/* projective */
  1.1162 ++	/* Warning:
  1.1163 ++	 * error propagation guarantees are much looser than in the affine case
  1.1164 ++	 */
  1.1165 ++	while (buffer < end)
  1.1166 ++	{
  1.1167 ++	    if (!mask || *mask++)
  1.1168 ++	    {
  1.1169 ++		if (v.vector[2] != 0)
  1.1170 ++		{
  1.1171 ++		    double pdx, pdy, invv2, b, c;
  1.1172 ++
  1.1173 ++		    invv2 = 1. * pixman_fixed_1 / v.vector[2];
  1.1174 ++
  1.1175 ++		    pdx = v.vector[0] * invv2 - radial->c1.x;
  1.1176 ++		    /*    / pixman_fixed_1 */
  1.1177 ++
  1.1178 ++		    pdy = v.vector[1] * invv2 - radial->c1.y;
  1.1179 ++		    /*    / pixman_fixed_1 */
  1.1180 ++
  1.1181 ++		    b = fdot (pdx, pdy, radial->c1.radius,
  1.1182 ++			      radial->delta.x, radial->delta.y,
  1.1183 ++			      radial->delta.radius);
  1.1184 ++		    /*  / pixman_fixed_1 / pixman_fixed_1 */
  1.1185 ++
  1.1186 ++		    c = fdot (pdx, pdy, -radial->c1.radius,
  1.1187 ++			      pdx, pdy, radial->c1.radius);
  1.1188 ++		    /*  / pixman_fixed_1 / pixman_fixed_1 */
  1.1189 ++
  1.1190 ++		    *buffer = convert_8888_to_0565 (
  1.1191 ++			      radial_compute_color (radial->a, b, c,
  1.1192 ++						    radial->inva,
  1.1193 ++						    radial->delta.radius,
  1.1194 ++						    radial->mindr,
  1.1195 ++						    &walker,
  1.1196 ++						    image->common.repeat));
  1.1197 ++		}
  1.1198 ++		else
  1.1199 ++		{
  1.1200 ++		    *buffer = 0;
  1.1201 ++		}
  1.1202 ++	    }
  1.1203 ++
  1.1204 ++	    ++buffer;
  1.1205 ++
  1.1206 ++	    v.vector[0] += unit.vector[0];
  1.1207 ++	    v.vector[1] += unit.vector[1];
  1.1208 ++	    v.vector[2] += unit.vector[2];
  1.1209 ++	}
  1.1210 ++    }
  1.1211 ++
  1.1212 ++    iter->y++;
  1.1213 ++    return iter->buffer;
  1.1214 ++}
  1.1215 + static uint32_t *
  1.1216 + radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
  1.1217 + {
  1.1218 +     uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
  1.1219 + 
  1.1220 +     pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
  1.1221 + 
  1.1222 +     return buffer;
  1.1223 + }
  1.1224 + 
  1.1225 + void
  1.1226 + _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
  1.1227 + {
  1.1228 +-    if (iter->flags & ITER_NARROW)
  1.1229 ++    if (iter->flags & ITER_16)
  1.1230 ++	iter->get_scanline = radial_get_scanline_16;
  1.1231 ++    else if (iter->flags & ITER_NARROW)
  1.1232 + 	iter->get_scanline = radial_get_scanline_narrow;
  1.1233 +     else
  1.1234 + 	iter->get_scanline = radial_get_scanline_wide;
  1.1235 + }
  1.1236 + 
  1.1237 ++
  1.1238 + PIXMAN_EXPORT pixman_image_t *
  1.1239 + pixman_image_create_radial_gradient (pixman_point_fixed_t *        inner,
  1.1240 +                                      pixman_point_fixed_t *        outer,
  1.1241 +                                      pixman_fixed_t                inner_radius,
  1.1242 +                                      pixman_fixed_t                outer_radius,
  1.1243 +                                      const pixman_gradient_stop_t *stops,
  1.1244 +                                      int                           n_stops)
  1.1245 + {

mercurial