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