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

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 diff --git a/gfx/cairo/libpixman/src/pixman-access.c b/gfx/cairo/libpixman/src/pixman-access.c
     2 --- a/gfx/cairo/libpixman/src/pixman-access.c
     3 +++ b/gfx/cairo/libpixman/src/pixman-access.c
     4 @@ -933,16 +933,54 @@ store_scanline_x2b10g10r10 (bits_image_t
     5      {
     6  	WRITE (image, pixel++,
     7  	       ((values[i] >> 38) & 0x3ff) |
     8  	       ((values[i] >> 12) & 0xffc00) |
     9  	       ((values[i] << 14) & 0x3ff00000));
    10      }
    11  }
    13 +static void
    14 +store_scanline_16 (bits_image_t *  image,
    15 +		   int             x,
    16 +		   int             y,
    17 +		   int             width,
    18 +		   const uint32_t *v)
    19 +{
    20 +    uint16_t *bits = (uint16_t*)(image->bits + image->rowstride * y);
    21 +    uint16_t *values = (uint16_t *)v;
    22 +    uint16_t *pixel = bits + x;
    23 +    int i;
    24 +
    25 +    for (i = 0; i < width; ++i)
    26 +    {
    27 +	WRITE (image, pixel++, values[i]);
    28 +    }
    29 +}
    30 +
    31 +static void
    32 +fetch_scanline_16 (pixman_image_t *image,
    33 +                            int             x,
    34 +                            int             y,
    35 +                            int             width,
    36 +                            uint32_t *      b,
    37 +                            const uint32_t *mask)
    38 +{
    39 +    const uint16_t *bits = (uint16_t*)(image->bits.bits + y * image->bits.rowstride);
    40 +    const uint16_t *pixel = bits + x;
    41 +    int i;
    42 +    uint16_t *buffer = (uint16_t *)b;
    43 +
    44 +    for (i = 0; i < width; ++i)
    45 +    {
    46 +	*buffer++ = READ (image, pixel++);
    47 +    }
    48 +}
    49 +
    50 +
    51  /*
    52   * Contracts a 64bpp image to 32bpp and then stores it using a regular 32-bit
    53   * store proc. Despite the type, this function expects a uint64_t buffer.
    54   */
    55  static void
    56  store_scanline_generic_64 (bits_image_t *  image,
    57                             int             x,
    58                             int             y,
    59 @@ -1044,32 +1082,47 @@ fetch_pixel_generic_lossy_32 (bits_image
    60      pixman_contract (&result, &pixel64, 1);
    62      return result;
    63  }
    65  typedef struct
    66  {
    67      pixman_format_code_t	format;
    68 +    fetch_scanline_t		fetch_scanline_16;
    69      fetch_scanline_t		fetch_scanline_32;
    70      fetch_scanline_t		fetch_scanline_64;
    71      fetch_pixel_32_t		fetch_pixel_32;
    72      fetch_pixel_64_t		fetch_pixel_64;
    73 +    store_scanline_t		store_scanline_16;
    74      store_scanline_t		store_scanline_32;
    75      store_scanline_t		store_scanline_64;
    76  } format_info_t;
    78  #define FORMAT_INFO(format) 						\
    79      {									\
    80  	PIXMAN_ ## format,						\
    81 +	    NULL,							\
    82  	    fetch_scanline_ ## format,					\
    83  	    fetch_scanline_generic_64,					\
    84  	    fetch_pixel_ ## format, fetch_pixel_generic_64,		\
    85 +	    NULL,							\
    86  	    store_scanline_ ## format, store_scanline_generic_64	\
    87      }
    88 +#define FORMAT_INFO16(format) 						\
    89 +    {									\
    90 +	PIXMAN_ ## format,						\
    91 +	    fetch_scanline_16,						\
    92 +	    fetch_scanline_ ## format,					\
    93 +	    fetch_scanline_generic_64,					\
    94 +	    fetch_pixel_ ## format, fetch_pixel_generic_64,		\
    95 +	    store_scanline_16,						\
    96 +	    store_scanline_ ## format, store_scanline_generic_64	\
    97 +    }
    98 +
   100  static const format_info_t accessors[] =
   101  {
   102  /* 32 bpp formats */
   103      FORMAT_INFO (a8r8g8b8),
   104      FORMAT_INFO (x8r8g8b8),
   105      FORMAT_INFO (a8b8g8r8),
   106      FORMAT_INFO (x8b8g8r8),
   107 @@ -1079,18 +1132,18 @@ static const format_info_t accessors[] =
   108      FORMAT_INFO (r8g8b8x8),
   109      FORMAT_INFO (x14r6g6b6),
   111  /* 24bpp formats */
   112      FORMAT_INFO (r8g8b8),
   113      FORMAT_INFO (b8g8r8),
   115  /* 16bpp formats */
   116 -    FORMAT_INFO (r5g6b5),
   117 -    FORMAT_INFO (b5g6r5),
   118 +    FORMAT_INFO16 (r5g6b5),
   119 +    FORMAT_INFO16 (b5g6r5),
   121      FORMAT_INFO (a1r5g5b5),
   122      FORMAT_INFO (x1r5g5b5),
   123      FORMAT_INFO (a1b5g5r5),
   124      FORMAT_INFO (x1b5g5r5),
   125      FORMAT_INFO (a4r4g4b4),
   126      FORMAT_INFO (x4r4g4b4),
   127      FORMAT_INFO (a4b4g4r4),
   128 @@ -1132,62 +1185,64 @@ static const format_info_t accessors[] =
   130  /* 1bpp formats */
   131      FORMAT_INFO (a1),
   132      FORMAT_INFO (g1),
   134  /* Wide formats */
   136      { PIXMAN_a2r10g10b10,
   137 -      NULL, fetch_scanline_a2r10g10b10,
   138 +      NULL, NULL, fetch_scanline_a2r10g10b10,
   139        fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10,
   140        NULL, store_scanline_a2r10g10b10 },
   142      { PIXMAN_x2r10g10b10,
   143 -      NULL, fetch_scanline_x2r10g10b10,
   144 +      NULL, NULL, fetch_scanline_x2r10g10b10,
   145        fetch_pixel_generic_lossy_32, fetch_pixel_x2r10g10b10,
   146        NULL, store_scanline_x2r10g10b10 },
   148      { PIXMAN_a2b10g10r10,
   149 -      NULL, fetch_scanline_a2b10g10r10,
   150 +      NULL, NULL, fetch_scanline_a2b10g10r10,
   151        fetch_pixel_generic_lossy_32, fetch_pixel_a2b10g10r10,
   152        NULL, store_scanline_a2b10g10r10 },
   154      { PIXMAN_x2b10g10r10,
   155 -      NULL, fetch_scanline_x2b10g10r10,
   156 +      NULL, NULL, fetch_scanline_x2b10g10r10,
   157        fetch_pixel_generic_lossy_32, fetch_pixel_x2b10g10r10,
   158        NULL, store_scanline_x2b10g10r10 },
   160  /* YUV formats */
   161      { PIXMAN_yuy2,
   162 -      fetch_scanline_yuy2, fetch_scanline_generic_64,
   163 +      NULL, fetch_scanline_yuy2, fetch_scanline_generic_64,
   164        fetch_pixel_yuy2, fetch_pixel_generic_64,
   165        NULL, NULL },
   167      { PIXMAN_yv12,
   168 -      fetch_scanline_yv12, fetch_scanline_generic_64,
   169 +      NULL, fetch_scanline_yv12, fetch_scanline_generic_64,
   170        fetch_pixel_yv12, fetch_pixel_generic_64,
   171        NULL, NULL },
   173      { PIXMAN_null },
   174  };
   176  static void
   177  setup_accessors (bits_image_t *image)
   178  {
   179      const format_info_t *info = accessors;
   181      while (info->format != PIXMAN_null)
   182      {
   183  	if (info->format == image->format)
   184  	{
   185 +	    image->fetch_scanline_16 = info->fetch_scanline_16;
   186  	    image->fetch_scanline_32 = info->fetch_scanline_32;
   187  	    image->fetch_scanline_64 = info->fetch_scanline_64;
   188  	    image->fetch_pixel_32 = info->fetch_pixel_32;
   189  	    image->fetch_pixel_64 = info->fetch_pixel_64;
   190 +	    image->store_scanline_16 = info->store_scanline_16;
   191  	    image->store_scanline_32 = info->store_scanline_32;
   192  	    image->store_scanline_64 = info->store_scanline_64;
   194  	    return;
   195  	}
   197  	info++;
   198      }
   199 diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c
   200 --- a/gfx/cairo/libpixman/src/pixman-bits-image.c
   201 +++ b/gfx/cairo/libpixman/src/pixman-bits-image.c
   202 @@ -1247,16 +1247,31 @@ src_get_scanline_wide (pixman_iter_t *it
   204  void
   205  _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
   206  {
   207      if (iter->flags & ITER_NARROW)
   208  	iter->get_scanline = src_get_scanline_narrow;
   209      else
   210  	iter->get_scanline = src_get_scanline_wide;
   211 +
   212 +}
   213 +
   214 +static uint32_t *
   215 +dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
   216 +{
   217 +    pixman_image_t *image  = iter->image;
   218 +    int             x      = iter->x;
   219 +    int             y      = iter->y;
   220 +    int             width  = iter->width;
   221 +    uint32_t *	    buffer = iter->buffer;
   222 +
   223 +    image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask);
   224 +
   225 +    return iter->buffer;
   226  }
   228  static uint32_t *
   229  dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
   230  {
   231      pixman_image_t *image  = iter->image;
   232      int             x      = iter->x;
   233      int             y      = iter->y;
   234 @@ -1327,16 +1342,30 @@ dest_get_scanline_wide (pixman_iter_t *i
   235  	    free (alpha);
   236  	}
   237      }
   239      return iter->buffer;
   240  }
   242  static void
   243 +dest_write_back_16 (pixman_iter_t *iter)
   244 +{
   245 +    bits_image_t *  image  = &iter->image->bits;
   246 +    int             x      = iter->x;
   247 +    int             y      = iter->y;
   248 +    int             width  = iter->width;
   249 +    const uint32_t *buffer = iter->buffer;
   250 +
   251 +    image->store_scanline_16 (image, x, y, width, buffer);
   252 +
   253 +    iter->y++;
   254 +}
   255 +
   256 +static void
   257  dest_write_back_narrow (pixman_iter_t *iter)
   258  {
   259      bits_image_t *  image  = &iter->image->bits;
   260      int             x      = iter->x;
   261      int             y      = iter->y;
   262      int             width  = iter->width;
   263      const uint32_t *buffer = iter->buffer;
   265 @@ -1375,28 +1404,41 @@ dest_write_back_wide (pixman_iter_t *ite
   266      }
   268      iter->y++;
   269  }
   271  void
   272  _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter)
   273  {
   274 -    if (iter->flags & ITER_NARROW)
   275 +    if (iter->flags & ITER_16)
   276 +    {
   277 +        if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
   278 +	    (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
   279 +	{
   280 +            iter->get_scanline = _pixman_iter_get_scanline_noop;
   281 +        }
   282 +        else
   283 +        {
   284 +	    iter->get_scanline = dest_get_scanline_16;
   285 +        }
   286 +	iter->write_back = dest_write_back_16;
   287 +    }
   288 +    else if (iter->flags & ITER_NARROW)
   289      {
   290  	if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
   291  	    (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
   292  	{
   293  	    iter->get_scanline = _pixman_iter_get_scanline_noop;
   294  	}
   295  	else
   296  	{
   297  	    iter->get_scanline = dest_get_scanline_narrow;
   298  	}
   299 -	
   300 +
   301  	iter->write_back = dest_write_back_narrow;
   302      }
   303      else
   304      {
   305  	iter->get_scanline = dest_get_scanline_wide;
   306  	iter->write_back = dest_write_back_wide;
   307      }
   308  }
   309 diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c
   310 new file mode 100644
   311 --- /dev/null
   312 +++ b/gfx/cairo/libpixman/src/pixman-combine16.c
   313 @@ -0,0 +1,124 @@
   314 +#ifdef HAVE_CONFIG_H
   315 +#include <config.h>
   316 +#endif
   317 +
   318 +#include <math.h>
   319 +#include <string.h>
   320 +
   321 +#include "pixman-private.h"
   322 +
   323 +#include "pixman-combine32.h"
   324 +
   325 +static force_inline uint32_t
   326 +combine_mask (const uint32_t src, const uint32_t mask)
   327 +{
   328 +    uint32_t s, m;
   329 +
   330 +    m = mask >> A_SHIFT;
   331 +
   332 +    if (!m)
   333 +	return 0;
   334 +    s = src;
   335 +
   336 +    UN8x4_MUL_UN8 (s, m);
   337 +
   338 +    return s;
   339 +}
   340 +
   341 +static inline uint32_t convert_0565_to_8888(uint16_t color)
   342 +{
   343 +    return CONVERT_0565_TO_8888(color);
   344 +}
   345 +
   346 +static inline uint16_t convert_8888_to_0565(uint32_t color)
   347 +{
   348 +    return CONVERT_8888_TO_0565(color);
   349 +}
   350 +
   351 +static void
   352 +combine_src_u (pixman_implementation_t *imp,
   353 +               pixman_op_t              op,
   354 +               uint32_t *               dest,
   355 +               const uint32_t *         src,
   356 +               const uint32_t *         mask,
   357 +               int                      width)
   358 +{
   359 +    int i;
   360 +
   361 +    if (!mask)
   362 +	memcpy (dest, src, width * sizeof (uint16_t));
   363 +    else
   364 +    {
   365 +	uint16_t *d = (uint16_t*)dest;
   366 +	uint16_t *src16 = (uint16_t*)src;
   367 +	for (i = 0; i < width; ++i)
   368 +	{
   369 +	    if ((*mask & 0xff000000) == 0xff000000) {
   370 +		// it's likely worth special casing
   371 +		// fully opaque because it avoids
   372 +		// the cost of conversion as well the multiplication
   373 +		*(d + i) = *src16;
   374 +	    } else {
   375 +		// the mask is still 32bits
   376 +		uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask);
   377 +		*(d + i) = convert_8888_to_0565(s);
   378 +	    }
   379 +	    mask++;
   380 +	    src16++;
   381 +	}
   382 +    }
   383 +
   384 +}
   385 +
   386 +static void
   387 +combine_over_u (pixman_implementation_t *imp,
   388 +               pixman_op_t              op,
   389 +               uint32_t *                dest,
   390 +               const uint32_t *          src,
   391 +               const uint32_t *          mask,
   392 +               int                      width)
   393 +{
   394 +    int i;
   395 +
   396 +    if (!mask)
   397 +	memcpy (dest, src, width * sizeof (uint16_t));
   398 +    else
   399 +    {
   400 +	uint16_t *d = (uint16_t*)dest;
   401 +	uint16_t *src16 = (uint16_t*)src;
   402 +	for (i = 0; i < width; ++i)
   403 +	{
   404 +	    if ((*mask & 0xff000000) == 0xff000000) {
   405 +		// it's likely worth special casing
   406 +		// fully opaque because it avoids
   407 +		// the cost of conversion as well the multiplication
   408 +		*(d + i) = *src16;
   409 +	    } else if ((*mask & 0xff000000) == 0x00000000) {
   410 +		// keep the dest the same
   411 +	    } else {
   412 +		// the mask is still 32bits
   413 +		uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask);
   414 +		uint32_t ia = ALPHA_8 (~s);
   415 +		uint32_t d32 = convert_0565_to_8888(*(d + i));
   416 +		UN8x4_MUL_UN8_ADD_UN8x4 (d32, ia, s);
   417 +		*(d + i) = convert_8888_to_0565(d32);
   418 +	    }
   419 +	    mask++;
   420 +	    src16++;
   421 +	}
   422 +    }
   423 +
   424 +}
   425 +
   426 +
   427 +void
   428 +_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp)
   429 +{
   430 +    int i;
   431 +    for (i = 0; i < PIXMAN_N_OPERATORS; i++) {
   432 +	imp->combine_16[i] = NULL;
   433 +    }
   434 +    imp->combine_16[PIXMAN_OP_SRC] = combine_src_u;
   435 +    imp->combine_16[PIXMAN_OP_OVER] = combine_over_u;
   436 +}
   437 +
   438 diff --git a/gfx/cairo/libpixman/src/pixman-general.c b/gfx/cairo/libpixman/src/pixman-general.c
   439 --- a/gfx/cairo/libpixman/src/pixman-general.c
   440 +++ b/gfx/cairo/libpixman/src/pixman-general.c
   441 @@ -106,46 +106,61 @@ general_composite_rect  (pixman_implemen
   442      PIXMAN_COMPOSITE_ARGS (info);
   443      uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8];
   444      uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer;
   445      uint8_t *src_buffer, *mask_buffer, *dest_buffer;
   446      pixman_iter_t src_iter, mask_iter, dest_iter;
   447      pixman_combine_32_func_t compose;
   448      pixman_bool_t component_alpha;
   449      iter_flags_t narrow, src_flags;
   450 +    iter_flags_t rgb16;
   451      int Bpp;
   452      int i;
   454      if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT)		    &&
   455  	(!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) &&
   456  	(dest_image->common.flags & FAST_PATH_NARROW_FORMAT))
   457      {
   458  	narrow = ITER_NARROW;
   459  	Bpp = 4;
   460      }
   461      else
   462      {
   463  	narrow = 0;
   464  	Bpp = 8;
   465      }
   467 +    // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps
   468 +    // by having it deal more specifically with different intermediate formats
   469 +    if (
   470 +	(dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) &&
   471 +	( op == PIXMAN_OP_SRC ||
   472 +         (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE))
   473 +	)
   474 +	) {
   475 +	rgb16 = ITER_16;
   476 +    } else {
   477 +	rgb16 = 0;
   478 +    }
   479 +
   480 +
   481      if (width * Bpp > SCANLINE_BUFFER_LENGTH)
   482      {
   483  	scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
   485  	if (!scanline_buffer)
   486  	    return;
   487      }
   489      src_buffer = scanline_buffer;
   490      mask_buffer = src_buffer + width * Bpp;
   491      dest_buffer = mask_buffer + width * Bpp;
   493      /* src iter */
   494 -    src_flags = narrow | op_flags[op].src;
   495 +    src_flags = narrow | op_flags[op].src | rgb16;
   497      _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image,
   498  					  src_x, src_y, width, height,
   499  					  src_buffer, src_flags);
   501      /* mask iter */
   502      if ((src_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
   503  	(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
   504 @@ -164,20 +179,20 @@ general_composite_rect  (pixman_implemen
   506      _pixman_implementation_src_iter_init (
   507  	imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height,
   508  	mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB));
   510      /* dest iter */
   511      _pixman_implementation_dest_iter_init (
   512  	imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height,
   513 -	dest_buffer, narrow | op_flags[op].dst);
   514 +	dest_buffer, narrow | op_flags[op].dst | rgb16);
   516      compose = _pixman_implementation_lookup_combiner (
   517 -	imp->toplevel, op, component_alpha, narrow);
   518 +	imp->toplevel, op, component_alpha, narrow, !!rgb16);
   520      if (!compose)
   521  	return;
   523      for (i = 0; i < height; ++i)
   524      {
   525  	uint32_t *s, *m, *d;
   527 @@ -234,16 +249,17 @@ general_fill (pixman_implementation_t *i
   528      return FALSE;
   529  }
   531  pixman_implementation_t *
   532  _pixman_implementation_create_general (void)
   533  {
   534      pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
   536 +    _pixman_setup_combiner_functions_16 (imp);
   537      _pixman_setup_combiner_functions_32 (imp);
   538      _pixman_setup_combiner_functions_64 (imp);
   540      imp->blt = general_blt;
   541      imp->fill = general_fill;
   542      imp->src_iter_init = general_src_iter_init;
   543      imp->dest_iter_init = general_dest_iter_init;
   545 diff --git a/gfx/cairo/libpixman/src/pixman-image.c b/gfx/cairo/libpixman/src/pixman-image.c
   546 --- a/gfx/cairo/libpixman/src/pixman-image.c
   547 +++ b/gfx/cairo/libpixman/src/pixman-image.c
   548 @@ -451,16 +451,20 @@ compute_image_info (pixman_image_t *imag
   549  		flags |= FAST_PATH_IS_OPAQUE;
   550  	}
   552  	if (image->bits.read_func || image->bits.write_func)
   553  	    flags &= ~FAST_PATH_NO_ACCESSORS;
   555  	if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
   556  	    flags &= ~FAST_PATH_NARROW_FORMAT;
   557 +
   558 +	if (image->bits.format == PIXMAN_r5g6b5)
   559 +	    flags |= FAST_PATH_16_FORMAT;
   560 +
   561  	break;
   563      case RADIAL:
   564  	code = PIXMAN_unknown;
   566  	/*
   567  	 * As explained in pixman-radial-gradient.c, every point of
   568  	 * the plane has a valid associated radius (and thus will be
   569 diff --git a/gfx/cairo/libpixman/src/pixman-implementation.c b/gfx/cairo/libpixman/src/pixman-implementation.c
   570 --- a/gfx/cairo/libpixman/src/pixman-implementation.c
   571 +++ b/gfx/cairo/libpixman/src/pixman-implementation.c
   572 @@ -101,45 +101,51 @@ pixman_implementation_t *
   573      imp->fill = delegate_fill;
   574      imp->src_iter_init = delegate_src_iter_init;
   575      imp->dest_iter_init = delegate_dest_iter_init;
   577      imp->fast_paths = fast_paths;
   579      for (i = 0; i < PIXMAN_N_OPERATORS; ++i)
   580      {
   581 +	imp->combine_16[i] = NULL;
   582  	imp->combine_32[i] = NULL;
   583  	imp->combine_64[i] = NULL;
   584  	imp->combine_32_ca[i] = NULL;
   585  	imp->combine_64_ca[i] = NULL;
   586      }
   588      return imp;
   589  }
   591  pixman_combine_32_func_t
   592  _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
   593  					pixman_op_t		 op,
   594  					pixman_bool_t		 component_alpha,
   595 -					pixman_bool_t		 narrow)
   596 +					pixman_bool_t		 narrow,
   597 +					pixman_bool_t		 rgb16)
   598  {
   599      pixman_combine_32_func_t f;
   601      do
   602      {
   603  	pixman_combine_32_func_t (*combiners[]) =
   604  	{
   605  	    (pixman_combine_32_func_t *)imp->combine_64,
   606  	    (pixman_combine_32_func_t *)imp->combine_64_ca,
   607  	    imp->combine_32,
   608  	    imp->combine_32_ca,
   609 +	    (pixman_combine_32_func_t *)imp->combine_16,
   610 +	    NULL,
   611  	};
   612 -
   613 -	f = combiners[component_alpha | (narrow << 1)][op];
   614 -
   615 +        if (rgb16) {
   616 +            f = combiners[4][op];
   617 +        } else {
   618 +            f = combiners[component_alpha + (narrow << 1)][op];
   619 +        }
   620  	imp = imp->delegate;
   621      }
   622      while (!f);
   624      return f;
   625  }
   627  pixman_bool_t
   628 diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
   629 --- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c
   630 +++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
   631 @@ -217,42 +217,185 @@ linear_get_scanline_narrow (pixman_iter_
   632  	}
   633      }
   635      iter->y++;
   637      return iter->buffer;
   638  }
   640 +static uint16_t convert_8888_to_0565(uint32_t color)
   641 +{
   642 +    return CONVERT_8888_TO_0565(color);
   643 +}
   644 +
   645 +static uint32_t *
   646 +linear_get_scanline_16 (pixman_iter_t  *iter,
   647 +			const uint32_t *mask)
   648 +{
   649 +    pixman_image_t *image  = iter->image;
   650 +    int             x      = iter->x;
   651 +    int             y      = iter->y;
   652 +    int             width  = iter->width;
   653 +    uint16_t *      buffer = (uint16_t*)iter->buffer;
   654 +
   655 +    pixman_vector_t v, unit;
   656 +    pixman_fixed_32_32_t l;
   657 +    pixman_fixed_48_16_t dx, dy;
   658 +    gradient_t *gradient = (gradient_t *)image;
   659 +    linear_gradient_t *linear = (linear_gradient_t *)image;
   660 +    uint16_t *end = buffer + width;
   661 +    pixman_gradient_walker_t walker;
   662 +
   663 +    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
   664 +
   665 +    /* reference point is the center of the pixel */
   666 +    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
   667 +    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
   668 +    v.vector[2] = pixman_fixed_1;
   669 +
   670 +    if (image->common.transform)
   671 +    {
   672 +	if (!pixman_transform_point_3d (image->common.transform, &v))
   673 +	    return iter->buffer;
   674 +
   675 +	unit.vector[0] = image->common.transform->matrix[0][0];
   676 +	unit.vector[1] = image->common.transform->matrix[1][0];
   677 +	unit.vector[2] = image->common.transform->matrix[2][0];
   678 +    }
   679 +    else
   680 +    {
   681 +	unit.vector[0] = pixman_fixed_1;
   682 +	unit.vector[1] = 0;
   683 +	unit.vector[2] = 0;
   684 +    }
   685 +
   686 +    dx = linear->p2.x - linear->p1.x;
   687 +    dy = linear->p2.y - linear->p1.y;
   688 +
   689 +    l = dx * dx + dy * dy;
   690 +
   691 +    if (l == 0 || unit.vector[2] == 0)
   692 +    {
   693 +	/* affine transformation only */
   694 +        pixman_fixed_32_32_t t, next_inc;
   695 +	double inc;
   696 +
   697 +	if (l == 0 || v.vector[2] == 0)
   698 +	{
   699 +	    t = 0;
   700 +	    inc = 0;
   701 +	}
   702 +	else
   703 +	{
   704 +	    double invden, v2;
   705 +
   706 +	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   707 +		(l * (double) v.vector[2]);
   708 +	    v2 = v.vector[2] * (1. / pixman_fixed_1);
   709 +	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   710 +		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   711 +	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
   712 +	}
   713 +	next_inc = 0;
   714 +
   715 +	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
   716 +	{
   717 +	    register uint16_t color;
   718 +
   719 +	    color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
   720 +	    while (buffer < end)
   721 +		*buffer++ = color;
   722 +	}
   723 +	else
   724 +	{
   725 +	    int i;
   726 +
   727 +	    i = 0;
   728 +	    while (buffer < end)
   729 +	    {
   730 +		if (!mask || *mask++)
   731 +		{
   732 +		    *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
   733 +										  t + next_inc));
   734 +		}
   735 +		i++;
   736 +		next_inc = inc * i;
   737 +		buffer++;
   738 +	    }
   739 +	}
   740 +    }
   741 +    else
   742 +    {
   743 +	/* projective transformation */
   744 +        double t;
   745 +
   746 +	t = 0;
   747 +
   748 +	while (buffer < end)
   749 +	{
   750 +	    if (!mask || *mask++)
   751 +	    {
   752 +	        if (v.vector[2] != 0)
   753 +		{
   754 +		    double invden, v2;
   755 +
   756 +		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   757 +			(l * (double) v.vector[2]);
   758 +		    v2 = v.vector[2] * (1. / pixman_fixed_1);
   759 +		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   760 +			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   761 +		}
   762 +
   763 +		*buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
   764 +	    }
   765 +
   766 +	    ++buffer;
   767 +
   768 +	    v.vector[0] += unit.vector[0];
   769 +	    v.vector[1] += unit.vector[1];
   770 +	    v.vector[2] += unit.vector[2];
   771 +	}
   772 +    }
   773 +
   774 +    iter->y++;
   775 +
   776 +    return iter->buffer;
   777 +}
   778 +
   779  static uint32_t *
   780  linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
   781  {
   782      uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
   784      pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
   786      return buffer;
   787  }
   789  void
   790  _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
   791  {
   792      if (linear_gradient_is_horizontal (
   793  	    iter->image, iter->x, iter->y, iter->width, iter->height))
   794      {
   795 -	if (iter->flags & ITER_NARROW)
   796 +	if (iter->flags & ITER_16)
   797 +	    linear_get_scanline_16 (iter, NULL);
   798 +	else if (iter->flags & ITER_NARROW)
   799  	    linear_get_scanline_narrow (iter, NULL);
   800  	else
   801  	    linear_get_scanline_wide (iter, NULL);
   803  	iter->get_scanline = _pixman_iter_get_scanline_noop;
   804      }
   805      else
   806      {
   807 -	if (iter->flags & ITER_NARROW)
   808 +	if (iter->flags & ITER_16)
   809 +	    iter->get_scanline = linear_get_scanline_16;
   810 +	else if (iter->flags & ITER_NARROW)
   811  	    iter->get_scanline = linear_get_scanline_narrow;
   812  	else
   813  	    iter->get_scanline = linear_get_scanline_wide;
   814      }
   815  }
   817  PIXMAN_EXPORT pixman_image_t *
   818  pixman_image_create_linear_gradient (pixman_point_fixed_t *        p1,
   819 diff --git a/gfx/cairo/libpixman/src/pixman-private.h b/gfx/cairo/libpixman/src/pixman-private.h
   820 --- a/gfx/cairo/libpixman/src/pixman-private.h
   821 +++ b/gfx/cairo/libpixman/src/pixman-private.h
   822 @@ -152,24 +152,28 @@ struct bits_image
   823      int                        height;
   824      uint32_t *                 bits;
   825      uint32_t *                 free_me;
   826      int                        rowstride;  /* in number of uint32_t's */
   828      fetch_scanline_t           get_scanline_32;
   829      fetch_scanline_t           get_scanline_64;
   831 +    fetch_scanline_t           fetch_scanline_16;
   832 +
   833      fetch_scanline_t           fetch_scanline_32;
   834      fetch_pixel_32_t	       fetch_pixel_32;
   835      store_scanline_t           store_scanline_32;
   837      fetch_scanline_t           fetch_scanline_64;
   838      fetch_pixel_64_t	       fetch_pixel_64;
   839      store_scanline_t           store_scanline_64;
   841 +    store_scanline_t           store_scanline_16;
   842 +
   843      /* Used for indirect access to the bits */
   844      pixman_read_memory_func_t  read_func;
   845      pixman_write_memory_func_t write_func;
   846  };
   848  union pixman_image
   849  {
   850      image_type_t       type;
   851 @@ -202,17 +206,24 @@ typedef enum
   852       * destination.
   853       *
   854       * When he destination is xRGB, this is useful knowledge, because then
   855       * we can treat it as if it were ARGB, which means in some cases we can
   856       * avoid copying it to a temporary buffer.
   857       */
   858      ITER_LOCALIZED_ALPHA =	(1 << 1),
   859      ITER_IGNORE_ALPHA =		(1 << 2),
   860 -    ITER_IGNORE_RGB =		(1 << 3)
   861 +    ITER_IGNORE_RGB =		(1 << 3),
   862 +
   863 +    /* With the addition of ITER_16 we now have two flags that to represent
   864 +     * 3 pipelines. This means that there can be an invalid state when
   865 +     * both ITER_NARROW and ITER_16 are set. In this case
   866 +     * ITER_16 overrides NARROW and we should use the 16 bit pipeline.
   867 +     * Note: ITER_16 still has a 32 bit mask, which is a bit weird. */
   868 +    ITER_16 =			(1 << 4)
   869  } iter_flags_t;
   871  struct pixman_iter_t
   872  {
   873      /* These are initialized by _pixman_implementation_{src,dest}_init */
   874      pixman_image_t *		image;
   875      uint32_t *			buffer;
   876      int				x, y;
   877 @@ -429,16 +440,17 @@ typedef pixman_bool_t (*pixman_fill_func
   878  					     int                      x,
   879  					     int                      y,
   880  					     int                      width,
   881  					     int                      height,
   882  					     uint32_t                 xor);
   883  typedef void (*pixman_iter_init_func_t) (pixman_implementation_t *imp,
   884                                           pixman_iter_t           *iter);
   886 +void _pixman_setup_combiner_functions_16 (pixman_implementation_t *imp);
   887  void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp);
   888  void _pixman_setup_combiner_functions_64 (pixman_implementation_t *imp);
   890  typedef struct
   891  {
   892      pixman_op_t             op;
   893      pixman_format_code_t    src_format;
   894      uint32_t		    src_flags;
   895 @@ -459,32 +471,34 @@ struct pixman_implementation_t
   896      pixman_fill_func_t		fill;
   897      pixman_iter_init_func_t     src_iter_init;
   898      pixman_iter_init_func_t     dest_iter_init;
   900      pixman_combine_32_func_t	combine_32[PIXMAN_N_OPERATORS];
   901      pixman_combine_32_func_t	combine_32_ca[PIXMAN_N_OPERATORS];
   902      pixman_combine_64_func_t	combine_64[PIXMAN_N_OPERATORS];
   903      pixman_combine_64_func_t	combine_64_ca[PIXMAN_N_OPERATORS];
   904 +    pixman_combine_64_func_t	combine_16[PIXMAN_N_OPERATORS];
   905  };
   907  uint32_t
   908  _pixman_image_get_solid (pixman_implementation_t *imp,
   909  			 pixman_image_t *         image,
   910                           pixman_format_code_t     format);
   912  pixman_implementation_t *
   913  _pixman_implementation_create (pixman_implementation_t *delegate,
   914  			       const pixman_fast_path_t *fast_paths);
   916  pixman_combine_32_func_t
   917  _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
   918  					pixman_op_t		 op,
   919  					pixman_bool_t		 component_alpha,
   920 -					pixman_bool_t		 wide);
   921 +					pixman_bool_t		 wide,
   922 +					pixman_bool_t		 rgb16);
   924  pixman_bool_t
   925  _pixman_implementation_blt (pixman_implementation_t *imp,
   926                              uint32_t *               src_bits,
   927                              uint32_t *               dst_bits,
   928                              int                      src_stride,
   929                              int                      dst_stride,
   930                              int                      src_bpp,
   931 @@ -613,16 +627,17 @@ uint32_t *
   932  #define FAST_PATH_Y_UNIT_ZERO			(1 << 18)
   933  #define FAST_PATH_BILINEAR_FILTER		(1 << 19)
   934  #define FAST_PATH_ROTATE_90_TRANSFORM		(1 << 20)
   935  #define FAST_PATH_ROTATE_180_TRANSFORM		(1 << 21)
   936  #define FAST_PATH_ROTATE_270_TRANSFORM		(1 << 22)
   937  #define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST	(1 << 23)
   938  #define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR	(1 << 24)
   939  #define FAST_PATH_BITS_IMAGE			(1 << 25)
   940 +#define FAST_PATH_16_FORMAT			(1 << 26)
   942  #define FAST_PATH_PAD_REPEAT						\
   943      (FAST_PATH_NO_NONE_REPEAT		|				\
   944       FAST_PATH_NO_NORMAL_REPEAT		|				\
   945       FAST_PATH_NO_REFLECT_REPEAT)
   947  #define FAST_PATH_NORMAL_REPEAT						\
   948      (FAST_PATH_NO_NONE_REPEAT		|				\
   949 diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   950 --- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   951 +++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   952 @@ -395,35 +395,289 @@ radial_get_scanline_narrow (pixman_iter_
   953  	    v.vector[2] += unit.vector[2];
   954  	}
   955      }
   957      iter->y++;
   958      return iter->buffer;
   959  }
   961 +static uint16_t convert_8888_to_0565(uint32_t color)
   962 +{
   963 +    return CONVERT_8888_TO_0565(color);
   964 +}
   965 +
   966 +static uint32_t *
   967 +radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
   968 +{
   969 +    /*
   970 +     * Implementation of radial gradients following the PDF specification.
   971 +     * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
   972 +     * Manual (PDF 32000-1:2008 at the time of this writing).
   973 +     *
   974 +     * In the radial gradient problem we are given two circles (c₁,r₁) and
   975 +     * (c₂,r₂) that define the gradient itself.
   976 +     *
   977 +     * Mathematically the gradient can be defined as the family of circles
   978 +     *
   979 +     *     ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
   980 +     *
   981 +     * excluding those circles whose radius would be < 0. When a point
   982 +     * belongs to more than one circle, the one with a bigger t is the only
   983 +     * one that contributes to its color. When a point does not belong
   984 +     * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
   985 +     * Further limitations on the range of values for t are imposed when
   986 +     * the gradient is not repeated, namely t must belong to [0,1].
   987 +     *
   988 +     * The graphical result is the same as drawing the valid (radius > 0)
   989 +     * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
   990 +     * is not repeated) using SOURCE operator composition.
   991 +     *
   992 +     * It looks like a cone pointing towards the viewer if the ending circle
   993 +     * is smaller than the starting one, a cone pointing inside the page if
   994 +     * the starting circle is the smaller one and like a cylinder if they
   995 +     * have the same radius.
   996 +     *
   997 +     * What we actually do is, given the point whose color we are interested
   998 +     * in, compute the t values for that point, solving for t in:
   999 +     *
  1000 +     *     length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
  1001 +     *
  1002 +     * Let's rewrite it in a simpler way, by defining some auxiliary
  1003 +     * variables:
  1004 +     *
  1005 +     *     cd = c₂ - c₁
  1006 +     *     pd = p - c₁
  1007 +     *     dr = r₂ - r₁
  1008 +     *     length(t·cd - pd) = r₁ + t·dr
  1009 +     *
  1010 +     * which actually means
  1011 +     *
  1012 +     *     hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
  1013 +     *
  1014 +     * or
  1015 +     *
  1016 +     *     ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
  1017 +     *
  1018 +     * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
  1019 +     *
  1020 +     *     (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
  1021 +     *
  1022 +     * where we can actually expand the squares and solve for t:
  1023 +     *
  1024 +     *     t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
  1025 +     *       = r₁² + 2·r₁·t·dr + t²·dr²
  1026 +     *
  1027 +     *     (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
  1028 +     *         (pdx² + pdy² - r₁²) = 0
  1029 +     *
  1030 +     *     A = cdx² + cdy² - dr²
  1031 +     *     B = pdx·cdx + pdy·cdy + r₁·dr
  1032 +     *     C = pdx² + pdy² - r₁²
  1033 +     *     At² - 2Bt + C = 0
  1034 +     *
  1035 +     * The solutions (unless the equation degenerates because of A = 0) are:
  1036 +     *
  1037 +     *     t = (B ± ⎷(B² - A·C)) / A
  1038 +     *
  1039 +     * The solution we are going to prefer is the bigger one, unless the
  1040 +     * radius associated to it is negative (or it falls outside the valid t
  1041 +     * range).
  1042 +     *
  1043 +     * Additional observations (useful for optimizations):
  1044 +     * A does not depend on p
  1045 +     *
  1046 +     * A < 0 <=> one of the two circles completely contains the other one
  1047 +     *   <=> for every p, the radiuses associated with the two t solutions
  1048 +     *       have opposite sign
  1049 +     */
  1050 +    pixman_image_t *image = iter->image;
  1051 +    int x = iter->x;
  1052 +    int y = iter->y;
  1053 +    int width = iter->width;
  1054 +    uint16_t *buffer = iter->buffer;
  1056 +    gradient_t *gradient = (gradient_t *)image;
  1057 +    radial_gradient_t *radial = (radial_gradient_t *)image;
  1058 +    uint16_t *end = buffer + width;
  1059 +    pixman_gradient_walker_t walker;
  1060 +    pixman_vector_t v, unit;
  1062 +    /* reference point is the center of the pixel */
  1063 +    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
  1064 +    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
  1065 +    v.vector[2] = pixman_fixed_1;
  1067 +    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
  1069 +    if (image->common.transform)
  1070 +    {
  1071 +	if (!pixman_transform_point_3d (image->common.transform, &v))
  1072 +	    return iter->buffer;
  1074 +	unit.vector[0] = image->common.transform->matrix[0][0];
  1075 +	unit.vector[1] = image->common.transform->matrix[1][0];
  1076 +	unit.vector[2] = image->common.transform->matrix[2][0];
  1077 +    }
  1078 +    else
  1079 +    {
  1080 +	unit.vector[0] = pixman_fixed_1;
  1081 +	unit.vector[1] = 0;
  1082 +	unit.vector[2] = 0;
  1083 +    }
  1085 +    if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
  1086 +    {
  1087 +	/*
  1088 +	 * Given:
  1089 +	 *
  1090 +	 * t = (B ± ⎷(B² - A·C)) / A
  1091 +	 *
  1092 +	 * where
  1093 +	 *
  1094 +	 * A = cdx² + cdy² - dr²
  1095 +	 * B = pdx·cdx + pdy·cdy + r₁·dr
  1096 +	 * C = pdx² + pdy² - r₁²
  1097 +	 * det = B² - A·C
  1098 +	 *
  1099 +	 * Since we have an affine transformation, we know that (pdx, pdy)
  1100 +	 * increase linearly with each pixel,
  1101 +	 *
  1102 +	 * pdx = pdx₀ + n·ux,
  1103 +	 * pdy = pdy₀ + n·uy,
  1104 +	 *
  1105 +	 * we can then express B, C and det through multiple differentiation.
  1106 +	 */
  1107 +	pixman_fixed_32_32_t b, db, c, dc, ddc;
  1109 +	/* warning: this computation may overflow */
  1110 +	v.vector[0] -= radial->c1.x;
  1111 +	v.vector[1] -= radial->c1.y;
  1113 +	/*
  1114 +	 * B and C are computed and updated exactly.
  1115 +	 * If fdot was used instead of dot, in the worst case it would
  1116 +	 * lose 11 bits of precision in each of the multiplication and
  1117 +	 * summing up would zero out all the bit that were preserved,
  1118 +	 * thus making the result 0 instead of the correct one.
  1119 +	 * This would mean a worst case of unbound relative error or
  1120 +	 * about 2^10 absolute error
  1121 +	 */
  1122 +	b = dot (v.vector[0], v.vector[1], radial->c1.radius,
  1123 +		 radial->delta.x, radial->delta.y, radial->delta.radius);
  1124 +	db = dot (unit.vector[0], unit.vector[1], 0,
  1125 +		  radial->delta.x, radial->delta.y, 0);
  1127 +	c = dot (v.vector[0], v.vector[1],
  1128 +		 -((pixman_fixed_48_16_t) radial->c1.radius),
  1129 +		 v.vector[0], v.vector[1], radial->c1.radius);
  1130 +	dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
  1131 +		  2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
  1132 +		  0,
  1133 +		  unit.vector[0], unit.vector[1], 0);
  1134 +	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
  1135 +		       unit.vector[0], unit.vector[1], 0);
  1137 +	while (buffer < end)
  1138 +	{
  1139 +	    if (!mask || *mask++)
  1140 +	    {
  1141 +		*buffer = convert_8888_to_0565(
  1142 +			  radial_compute_color (radial->a, b, c,
  1143 +						radial->inva,
  1144 +						radial->delta.radius,
  1145 +						radial->mindr,
  1146 +						&walker,
  1147 +						image->common.repeat));
  1148 +	    }
  1150 +	    b += db;
  1151 +	    c += dc;
  1152 +	    dc += ddc;
  1153 +	    ++buffer;
  1154 +	}
  1155 +    }
  1156 +    else
  1157 +    {
  1158 +	/* projective */
  1159 +	/* Warning:
  1160 +	 * error propagation guarantees are much looser than in the affine case
  1161 +	 */
  1162 +	while (buffer < end)
  1163 +	{
  1164 +	    if (!mask || *mask++)
  1165 +	    {
  1166 +		if (v.vector[2] != 0)
  1167 +		{
  1168 +		    double pdx, pdy, invv2, b, c;
  1170 +		    invv2 = 1. * pixman_fixed_1 / v.vector[2];
  1172 +		    pdx = v.vector[0] * invv2 - radial->c1.x;
  1173 +		    /*    / pixman_fixed_1 */
  1175 +		    pdy = v.vector[1] * invv2 - radial->c1.y;
  1176 +		    /*    / pixman_fixed_1 */
  1178 +		    b = fdot (pdx, pdy, radial->c1.radius,
  1179 +			      radial->delta.x, radial->delta.y,
  1180 +			      radial->delta.radius);
  1181 +		    /*  / pixman_fixed_1 / pixman_fixed_1 */
  1183 +		    c = fdot (pdx, pdy, -radial->c1.radius,
  1184 +			      pdx, pdy, radial->c1.radius);
  1185 +		    /*  / pixman_fixed_1 / pixman_fixed_1 */
  1187 +		    *buffer = convert_8888_to_0565 (
  1188 +			      radial_compute_color (radial->a, b, c,
  1189 +						    radial->inva,
  1190 +						    radial->delta.radius,
  1191 +						    radial->mindr,
  1192 +						    &walker,
  1193 +						    image->common.repeat));
  1194 +		}
  1195 +		else
  1196 +		{
  1197 +		    *buffer = 0;
  1198 +		}
  1199 +	    }
  1201 +	    ++buffer;
  1203 +	    v.vector[0] += unit.vector[0];
  1204 +	    v.vector[1] += unit.vector[1];
  1205 +	    v.vector[2] += unit.vector[2];
  1206 +	}
  1207 +    }
  1209 +    iter->y++;
  1210 +    return iter->buffer;
  1211 +}
  1212  static uint32_t *
  1213  radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
  1215      uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
  1217      pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
  1219      return buffer;
  1222  void
  1223  _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
  1225 -    if (iter->flags & ITER_NARROW)
  1226 +    if (iter->flags & ITER_16)
  1227 +	iter->get_scanline = radial_get_scanline_16;
  1228 +    else if (iter->flags & ITER_NARROW)
  1229  	iter->get_scanline = radial_get_scanline_narrow;
  1230      else
  1231  	iter->get_scanline = radial_get_scanline_wide;
  1235  PIXMAN_EXPORT pixman_image_t *
  1236  pixman_image_create_radial_gradient (pixman_point_fixed_t *        inner,
  1237                                       pixman_point_fixed_t *        outer,
  1238                                       pixman_fixed_t                inner_radius,
  1239                                       pixman_fixed_t                outer_radius,
  1240                                       const pixman_gradient_stop_t *stops,
  1241                                       int                           n_stops)

mercurial