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

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

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

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

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

mercurial