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
7 ((values[i] >> 38) & 0x3ff) |
8 ((values[i] >> 12) & 0xffc00) |
9 ((values[i] << 14) & 0x3ff00000));
14 +store_scanline_16 (bits_image_t * image,
20 + uint16_t *bits = (uint16_t*)(image->bits + image->rowstride * y);
21 + uint16_t *values = (uint16_t *)v;
22 + uint16_t *pixel = bits + x;
25 + for (i = 0; i < width; ++i)
27 + WRITE (image, pixel++, values[i]);
32 +fetch_scanline_16 (pixman_image_t *image,
37 + const uint32_t *mask)
39 + const uint16_t *bits = (uint16_t*)(image->bits.bits + y * image->bits.rowstride);
40 + const uint16_t *pixel = bits + x;
42 + uint16_t *buffer = (uint16_t *)b;
44 + for (i = 0; i < width; ++i)
46 + *buffer++ = READ (image, pixel++);
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.
56 store_scanline_generic_64 (bits_image_t * image,
59 @@ -1044,32 +1082,47 @@ fetch_pixel_generic_lossy_32 (bits_image
60 pixman_contract (&result, &pixel64, 1);
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;
78 #define FORMAT_INFO(format) \
82 fetch_scanline_ ## format, \
83 fetch_scanline_generic_64, \
84 fetch_pixel_ ## format, fetch_pixel_generic_64, \
86 store_scanline_ ## format, store_scanline_generic_64 \
88 +#define FORMAT_INFO16(format) \
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 \
100 static const format_info_t accessors[] =
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),
112 FORMAT_INFO (r8g8b8),
113 FORMAT_INFO (b8g8r8),
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[] =
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 },
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,
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,
177 setup_accessors (bits_image_t *image)
179 const format_info_t *info = accessors;
181 while (info->format != PIXMAN_null)
183 if (info->format == image->format)
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;
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
205 _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
207 if (iter->flags & ITER_NARROW)
208 iter->get_scanline = src_get_scanline_narrow;
210 iter->get_scanline = src_get_scanline_wide;
215 +dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
217 + pixman_image_t *image = iter->image;
220 + int width = iter->width;
221 + uint32_t * buffer = iter->buffer;
223 + image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask);
225 + return iter->buffer;
229 dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
231 pixman_image_t *image = iter->image;
234 @@ -1327,16 +1342,30 @@ dest_get_scanline_wide (pixman_iter_t *i
243 +dest_write_back_16 (pixman_iter_t *iter)
245 + bits_image_t * image = &iter->image->bits;
248 + int width = iter->width;
249 + const uint32_t *buffer = iter->buffer;
251 + image->store_scanline_16 (image, x, y, width, buffer);
257 dest_write_back_narrow (pixman_iter_t *iter)
259 bits_image_t * image = &iter->image->bits;
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
272 _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter)
274 - if (iter->flags & ITER_NARROW)
275 + if (iter->flags & ITER_16)
277 + if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
278 + (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
280 + iter->get_scanline = _pixman_iter_get_scanline_noop;
284 + iter->get_scanline = dest_get_scanline_16;
286 + iter->write_back = dest_write_back_16;
288 + else if (iter->flags & ITER_NARROW)
290 if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
291 (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
293 iter->get_scanline = _pixman_iter_get_scanline_noop;
297 iter->get_scanline = dest_get_scanline_narrow;
301 iter->write_back = dest_write_back_narrow;
305 iter->get_scanline = dest_get_scanline_wide;
306 iter->write_back = dest_write_back_wide;
309 diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c
312 +++ b/gfx/cairo/libpixman/src/pixman-combine16.c
314 +#ifdef HAVE_CONFIG_H
321 +#include "pixman-private.h"
323 +#include "pixman-combine32.h"
325 +static force_inline uint32_t
326 +combine_mask (const uint32_t src, const uint32_t mask)
330 + m = mask >> A_SHIFT;
336 + UN8x4_MUL_UN8 (s, m);
341 +static inline uint32_t convert_0565_to_8888(uint16_t color)
343 + return CONVERT_0565_TO_8888(color);
346 +static inline uint16_t convert_8888_to_0565(uint32_t color)
348 + return CONVERT_8888_TO_0565(color);
352 +combine_src_u (pixman_implementation_t *imp,
355 + const uint32_t * src,
356 + const uint32_t * mask,
362 + memcpy (dest, src, width * sizeof (uint16_t));
365 + uint16_t *d = (uint16_t*)dest;
366 + uint16_t *src16 = (uint16_t*)src;
367 + for (i = 0; i < width; ++i)
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
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);
387 +combine_over_u (pixman_implementation_t *imp,
390 + const uint32_t * src,
391 + const uint32_t * mask,
397 + memcpy (dest, src, width * sizeof (uint16_t));
400 + uint16_t *d = (uint16_t*)dest;
401 + uint16_t *src16 = (uint16_t*)src;
402 + for (i = 0; i < width; ++i)
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
409 + } else if ((*mask & 0xff000000) == 0x00000000) {
410 + // keep the dest the same
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);
428 +_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp)
431 + for (i = 0; i < PIXMAN_N_OPERATORS; i++) {
432 + imp->combine_16[i] = NULL;
434 + imp->combine_16[PIXMAN_OP_SRC] = combine_src_u;
435 + imp->combine_16[PIXMAN_OP_OVER] = combine_over_u;
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;
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))
458 narrow = ITER_NARROW;
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
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))
481 if (width * Bpp > SCANLINE_BUFFER_LENGTH)
483 scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
485 if (!scanline_buffer)
489 src_buffer = scanline_buffer;
490 mask_buffer = src_buffer + width * Bpp;
491 dest_buffer = mask_buffer + width * Bpp;
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);
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));
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);
523 for (i = 0; i < height; ++i)
527 @@ -234,16 +249,17 @@ general_fill (pixman_implementation_t *i
531 pixman_implementation_t *
532 _pixman_implementation_create_general (void)
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;
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;
558 + if (image->bits.format == PIXMAN_r5g6b5)
559 + flags |= FAST_PATH_16_FORMAT;
564 code = PIXMAN_unknown;
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)
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;
591 pixman_combine_32_func_t
592 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
594 pixman_bool_t component_alpha,
595 - pixman_bool_t narrow)
596 + pixman_bool_t narrow,
597 + pixman_bool_t rgb16)
599 pixman_combine_32_func_t f;
603 pixman_combine_32_func_t (*combiners[]) =
605 (pixman_combine_32_func_t *)imp->combine_64,
606 (pixman_combine_32_func_t *)imp->combine_64_ca,
609 + (pixman_combine_32_func_t *)imp->combine_16,
613 - f = combiners[component_alpha | (narrow << 1)][op];
616 + f = combiners[4][op];
618 + f = combiners[component_alpha + (narrow << 1)][op];
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_
640 +static uint16_t convert_8888_to_0565(uint32_t color)
642 + return CONVERT_8888_TO_0565(color);
646 +linear_get_scanline_16 (pixman_iter_t *iter,
647 + const uint32_t *mask)
649 + pixman_image_t *image = iter->image;
652 + int width = iter->width;
653 + uint16_t * buffer = (uint16_t*)iter->buffer;
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;
663 + _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
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;
670 + if (image->common.transform)
672 + if (!pixman_transform_point_3d (image->common.transform, &v))
673 + return iter->buffer;
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];
681 + unit.vector[0] = pixman_fixed_1;
682 + unit.vector[1] = 0;
683 + unit.vector[2] = 0;
686 + dx = linear->p2.x - linear->p1.x;
687 + dy = linear->p2.y - linear->p1.y;
689 + l = dx * dx + dy * dy;
691 + if (l == 0 || unit.vector[2] == 0)
693 + /* affine transformation only */
694 + pixman_fixed_32_32_t t, next_inc;
697 + if (l == 0 || v.vector[2] == 0)
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;
715 + if (((pixman_fixed_32_32_t )(inc * width)) == 0)
717 + register uint16_t color;
719 + color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
720 + while (buffer < end)
728 + while (buffer < end)
730 + if (!mask || *mask++)
732 + *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
736 + next_inc = inc * i;
743 + /* projective transformation */
748 + while (buffer < end)
750 + if (!mask || *mask++)
752 + if (v.vector[2] != 0)
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;
763 + *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
768 + v.vector[0] += unit.vector[0];
769 + v.vector[1] += unit.vector[1];
770 + v.vector[2] += unit.vector[2];
776 + return iter->buffer;
780 linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
782 uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
784 pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
790 _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
792 if (linear_gradient_is_horizontal (
793 iter->image, iter->x, iter->y, iter->width, iter->height))
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);
801 linear_get_scanline_wide (iter, NULL);
803 iter->get_scanline = _pixman_iter_get_scanline_noop;
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;
813 iter->get_scanline = linear_get_scanline_wide;
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
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;
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;
843 /* Used for indirect access to the bits */
844 pixman_read_memory_func_t read_func;
845 pixman_write_memory_func_t write_func;
851 @@ -202,17 +206,24 @@ typedef enum
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.
858 ITER_LOCALIZED_ALPHA = (1 << 1),
859 ITER_IGNORE_ALPHA = (1 << 2),
860 - ITER_IGNORE_RGB = (1 << 3)
861 + ITER_IGNORE_RGB = (1 << 3),
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. */
873 /* These are initialized by _pixman_implementation_{src,dest}_init */
874 pixman_image_t * image;
877 @@ -429,16 +440,17 @@ typedef pixman_bool_t (*pixman_fill_func
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);
893 pixman_format_code_t src_format;
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];
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,
919 pixman_bool_t component_alpha,
920 - pixman_bool_t wide);
921 + pixman_bool_t wide,
922 + pixman_bool_t rgb16);
925 _pixman_implementation_blt (pixman_implementation_t *imp,
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];
961 +static uint16_t convert_8888_to_0565(uint32_t color)
963 + return CONVERT_8888_TO_0565(color);
967 +radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
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).
974 + * In the radial gradient problem we are given two circles (c₁,r₁) and
975 + * (c₂,r₂) that define the gradient itself.
977 + * Mathematically the gradient can be defined as the family of circles
979 + * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
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].
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.
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.
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:
1000 + * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
1002 + * Let's rewrite it in a simpler way, by defining some auxiliary
1008 + * length(t·cd - pd) = r₁ + t·dr
1010 + * which actually means
1012 + * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
1016 + * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
1018 + * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
1020 + * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
1022 + * where we can actually expand the squares and solve for t:
1024 + * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
1025 + * = r₁² + 2·r₁·t·dr + t²·dr²
1027 + * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
1028 + * (pdx² + pdy² - r₁²) = 0
1030 + * A = cdx² + cdy² - dr²
1031 + * B = pdx·cdx + pdy·cdy + r₁·dr
1032 + * C = pdx² + pdy² - r₁²
1033 + * At² - 2Bt + C = 0
1035 + * The solutions (unless the equation degenerates because of A = 0) are:
1037 + * t = (B ± ⎷(B² - A·C)) / A
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
1043 + * Additional observations (useful for optimizations):
1044 + * A does not depend on p
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
1050 + pixman_image_t *image = iter->image;
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)
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];
1080 + unit.vector[0] = pixman_fixed_1;
1081 + unit.vector[1] = 0;
1082 + unit.vector[2] = 0;
1085 + if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
1090 + * t = (B ± ⎷(B² - A·C)) / A
1094 + * A = cdx² + cdy² - dr²
1095 + * B = pdx·cdx + pdy·cdy + r₁·dr
1096 + * C = pdx² + pdy² - r₁²
1099 + * Since we have an affine transformation, we know that (pdx, pdy)
1100 + * increase linearly with each pixel,
1102 + * pdx = pdx₀ + n·ux,
1103 + * pdy = pdy₀ + n·uy,
1105 + * we can then express B, C and det through multiple differentiation.
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;
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
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],
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)
1139 + if (!mask || *mask++)
1141 + *buffer = convert_8888_to_0565(
1142 + radial_compute_color (radial->a, b, c,
1144 + radial->delta.radius,
1147 + image->common.repeat));
1160 + * error propagation guarantees are much looser than in the affine case
1162 + while (buffer < end)
1164 + if (!mask || *mask++)
1166 + if (v.vector[2] != 0)
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,
1190 + radial->delta.radius,
1193 + image->common.repeat));
1203 + v.vector[0] += unit.vector[0];
1204 + v.vector[1] += unit.vector[1];
1205 + v.vector[2] += unit.vector[2];
1210 + return iter->buffer;
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);
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;
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,