1diff --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 } 12 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); 61 62 return result; 63 } 64 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; 77 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+ 99 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), 110 111 /* 24bpp formats */ 112 FORMAT_INFO (r8g8b8), 113 FORMAT_INFO (b8g8r8), 114 115 /* 16bpp formats */ 116- FORMAT_INFO (r5g6b5), 117- FORMAT_INFO (b5g6r5), 118+ FORMAT_INFO16 (r5g6b5), 119+ FORMAT_INFO16 (b5g6r5), 120 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[] = 129 130 /* 1bpp formats */ 131 FORMAT_INFO (a1), 132 FORMAT_INFO (g1), 133 134 /* Wide formats */ 135 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 }, 141 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 }, 147 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 }, 153 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 }, 159 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 }, 166 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 }, 172 173 { PIXMAN_null }, 174 }; 175 176 static void 177 setup_accessors (bits_image_t *image) 178 { 179 const format_info_t *info = accessors; 180 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; 193 194 return; 195 } 196 197 info++; 198 } 199diff --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 203 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 } 227 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 } 238 239 return iter->buffer; 240 } 241 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; 264 265@@ -1375,28 +1404,41 @@ dest_write_back_wide (pixman_iter_t *ite 266 } 267 268 iter->y++; 269 } 270 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 } 309diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c 310new 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+ 438diff --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; 453 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 } 466 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); 484 485 if (!scanline_buffer) 486 return; 487 } 488 489 src_buffer = scanline_buffer; 490 mask_buffer = src_buffer + width * Bpp; 491 dest_buffer = mask_buffer + width * Bpp; 492 493 /* src iter */ 494- src_flags = narrow | op_flags[op].src; 495+ src_flags = narrow | op_flags[op].src | rgb16; 496 497 _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image, 498 src_x, src_y, width, height, 499 src_buffer, src_flags); 500 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 505 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)); 509 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); 515 516 compose = _pixman_implementation_lookup_combiner ( 517- imp->toplevel, op, component_alpha, narrow); 518+ imp->toplevel, op, component_alpha, narrow, !!rgb16); 519 520 if (!compose) 521 return; 522 523 for (i = 0; i < height; ++i) 524 { 525 uint32_t *s, *m, *d; 526 527@@ -234,16 +249,17 @@ general_fill (pixman_implementation_t *i 528 return FALSE; 529 } 530 531 pixman_implementation_t * 532 _pixman_implementation_create_general (void) 533 { 534 pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); 535 536+ _pixman_setup_combiner_functions_16 (imp); 537 _pixman_setup_combiner_functions_32 (imp); 538 _pixman_setup_combiner_functions_64 (imp); 539 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; 544 545diff --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 } 551 552 if (image->bits.read_func || image->bits.write_func) 553 flags &= ~FAST_PATH_NO_ACCESSORS; 554 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; 562 563 case RADIAL: 564 code = PIXMAN_unknown; 565 566 /* 567 * As explained in pixman-radial-gradient.c, every point of 568 * the plane has a valid associated radius (and thus will be 569diff --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; 576 577 imp->fast_paths = fast_paths; 578 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 } 587 588 return imp; 589 } 590 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; 600 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); 623 624 return f; 625 } 626 627 pixman_bool_t 628diff --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 } 634 635 iter->y++; 636 637 return iter->buffer; 638 } 639 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); 783 784 pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); 785 786 return buffer; 787 } 788 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); 802 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 } 816 817 PIXMAN_EXPORT pixman_image_t * 818 pixman_image_create_linear_gradient (pixman_point_fixed_t * p1, 819diff --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 */ 827 828 fetch_scanline_t get_scanline_32; 829 fetch_scanline_t get_scanline_64; 830 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; 836 837 fetch_scanline_t fetch_scanline_64; 838 fetch_pixel_64_t fetch_pixel_64; 839 store_scanline_t store_scanline_64; 840 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 }; 847 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; 870 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); 885 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); 889 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; 899 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 }; 906 907 uint32_t 908 _pixman_image_get_solid (pixman_implementation_t *imp, 909 pixman_image_t * image, 910 pixman_format_code_t format); 911 912 pixman_implementation_t * 913 _pixman_implementation_create (pixman_implementation_t *delegate, 914 const pixman_fast_path_t *fast_paths); 915 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); 923 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) 941 942 #define FAST_PATH_PAD_REPEAT \ 943 (FAST_PATH_NO_NONE_REPEAT | \ 944 FAST_PATH_NO_NORMAL_REPEAT | \ 945 FAST_PATH_NO_REFLECT_REPEAT) 946 947 #define FAST_PATH_NORMAL_REPEAT \ 948 (FAST_PATH_NO_NONE_REPEAT | \ 949diff --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 } 956 957 iter->y++; 958 return iter->buffer; 959 } 960 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; 1055+ 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; 1061+ 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; 1066+ 1067+ _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); 1068+ 1069+ if (image->common.transform) 1070+ { 1071+ if (!pixman_transform_point_3d (image->common.transform, &v)) 1072+ return iter->buffer; 1073+ 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+ } 1084+ 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; 1108+ 1109+ /* warning: this computation may overflow */ 1110+ v.vector[0] -= radial->c1.x; 1111+ v.vector[1] -= radial->c1.y; 1112+ 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); 1126+ 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); 1136+ 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+ } 1149+ 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; 1169+ 1170+ invv2 = 1. * pixman_fixed_1 / v.vector[2]; 1171+ 1172+ pdx = v.vector[0] * invv2 - radial->c1.x; 1173+ /* / pixman_fixed_1 */ 1174+ 1175+ pdy = v.vector[1] * invv2 - radial->c1.y; 1176+ /* / pixman_fixed_1 */ 1177+ 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 */ 1182+ 1183+ c = fdot (pdx, pdy, -radial->c1.radius, 1184+ pdx, pdy, radial->c1.radius); 1185+ /* / pixman_fixed_1 / pixman_fixed_1 */ 1186+ 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+ } 1200+ 1201+ ++buffer; 1202+ 1203+ v.vector[0] += unit.vector[0]; 1204+ v.vector[1] += unit.vector[1]; 1205+ v.vector[2] += unit.vector[2]; 1206+ } 1207+ } 1208+ 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) 1214 { 1215 uint32_t *buffer = radial_get_scanline_narrow (iter, NULL); 1216 1217 pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); 1218 1219 return buffer; 1220 } 1221 1222 void 1223 _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) 1224 { 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; 1232 } 1233 1234+ 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) 1242 { 1243