diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/cairo/pixman-16-bit-pipeline.patch | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/cairo/pixman-16-bit-pipeline.patch')
-rw-r--r-- | gfx/cairo/pixman-16-bit-pipeline.patch | 1242 |
1 files changed, 1242 insertions, 0 deletions
diff --git a/gfx/cairo/pixman-16-bit-pipeline.patch b/gfx/cairo/pixman-16-bit-pipeline.patch new file mode 100644 index 0000000000..8a7878ca2f --- /dev/null +++ b/gfx/cairo/pixman-16-bit-pipeline.patch @@ -0,0 +1,1242 @@ +diff --git a/gfx/cairo/libpixman/src/pixman-access.c b/gfx/cairo/libpixman/src/pixman-access.c +--- a/gfx/cairo/libpixman/src/pixman-access.c ++++ b/gfx/cairo/libpixman/src/pixman-access.c +@@ -933,16 +933,54 @@ store_scanline_x2b10g10r10 (bits_image_t + { + WRITE (image, pixel++, + ((values[i] >> 38) & 0x3ff) | + ((values[i] >> 12) & 0xffc00) | + ((values[i] << 14) & 0x3ff00000)); + } + } + ++static void ++store_scanline_16 (bits_image_t * image, ++ int x, ++ int y, ++ int width, ++ const uint32_t *v) ++{ ++ uint16_t *bits = (uint16_t*)(image->bits + image->rowstride * y); ++ uint16_t *values = (uint16_t *)v; ++ uint16_t *pixel = bits + x; ++ int i; ++ ++ for (i = 0; i < width; ++i) ++ { ++ WRITE (image, pixel++, values[i]); ++ } ++} ++ ++static void ++fetch_scanline_16 (pixman_image_t *image, ++ int x, ++ int y, ++ int width, ++ uint32_t * b, ++ const uint32_t *mask) ++{ ++ const uint16_t *bits = (uint16_t*)(image->bits.bits + y * image->bits.rowstride); ++ const uint16_t *pixel = bits + x; ++ int i; ++ uint16_t *buffer = (uint16_t *)b; ++ ++ for (i = 0; i < width; ++i) ++ { ++ *buffer++ = READ (image, pixel++); ++ } ++} ++ ++ + /* + * Contracts a 64bpp image to 32bpp and then stores it using a regular 32-bit + * store proc. Despite the type, this function expects a uint64_t buffer. + */ + static void + store_scanline_generic_64 (bits_image_t * image, + int x, + int y, +@@ -1044,32 +1082,47 @@ fetch_pixel_generic_lossy_32 (bits_image + pixman_contract (&result, &pixel64, 1); + + return result; + } + + typedef struct + { + pixman_format_code_t format; ++ fetch_scanline_t fetch_scanline_16; + fetch_scanline_t fetch_scanline_32; + fetch_scanline_t fetch_scanline_64; + fetch_pixel_32_t fetch_pixel_32; + fetch_pixel_64_t fetch_pixel_64; ++ store_scanline_t store_scanline_16; + store_scanline_t store_scanline_32; + store_scanline_t store_scanline_64; + } format_info_t; + + #define FORMAT_INFO(format) \ + { \ + PIXMAN_ ## format, \ ++ NULL, \ + fetch_scanline_ ## format, \ + fetch_scanline_generic_64, \ + fetch_pixel_ ## format, fetch_pixel_generic_64, \ ++ NULL, \ + store_scanline_ ## format, store_scanline_generic_64 \ + } ++#define FORMAT_INFO16(format) \ ++ { \ ++ PIXMAN_ ## format, \ ++ fetch_scanline_16, \ ++ fetch_scanline_ ## format, \ ++ fetch_scanline_generic_64, \ ++ fetch_pixel_ ## format, fetch_pixel_generic_64, \ ++ store_scanline_16, \ ++ store_scanline_ ## format, store_scanline_generic_64 \ ++ } ++ + + static const format_info_t accessors[] = + { + /* 32 bpp formats */ + FORMAT_INFO (a8r8g8b8), + FORMAT_INFO (x8r8g8b8), + FORMAT_INFO (a8b8g8r8), + FORMAT_INFO (x8b8g8r8), +@@ -1079,18 +1132,18 @@ static const format_info_t accessors[] = + FORMAT_INFO (r8g8b8x8), + FORMAT_INFO (x14r6g6b6), + + /* 24bpp formats */ + FORMAT_INFO (r8g8b8), + FORMAT_INFO (b8g8r8), + + /* 16bpp formats */ +- FORMAT_INFO (r5g6b5), +- FORMAT_INFO (b5g6r5), ++ FORMAT_INFO16 (r5g6b5), ++ FORMAT_INFO16 (b5g6r5), + + FORMAT_INFO (a1r5g5b5), + FORMAT_INFO (x1r5g5b5), + FORMAT_INFO (a1b5g5r5), + FORMAT_INFO (x1b5g5r5), + FORMAT_INFO (a4r4g4b4), + FORMAT_INFO (x4r4g4b4), + FORMAT_INFO (a4b4g4r4), +@@ -1132,62 +1185,64 @@ static const format_info_t accessors[] = + + /* 1bpp formats */ + FORMAT_INFO (a1), + FORMAT_INFO (g1), + + /* Wide formats */ + + { PIXMAN_a2r10g10b10, +- NULL, fetch_scanline_a2r10g10b10, ++ NULL, NULL, fetch_scanline_a2r10g10b10, + fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10, + NULL, store_scanline_a2r10g10b10 }, + + { PIXMAN_x2r10g10b10, +- NULL, fetch_scanline_x2r10g10b10, ++ NULL, NULL, fetch_scanline_x2r10g10b10, + fetch_pixel_generic_lossy_32, fetch_pixel_x2r10g10b10, + NULL, store_scanline_x2r10g10b10 }, + + { PIXMAN_a2b10g10r10, +- NULL, fetch_scanline_a2b10g10r10, ++ NULL, NULL, fetch_scanline_a2b10g10r10, + fetch_pixel_generic_lossy_32, fetch_pixel_a2b10g10r10, + NULL, store_scanline_a2b10g10r10 }, + + { PIXMAN_x2b10g10r10, +- NULL, fetch_scanline_x2b10g10r10, ++ NULL, NULL, fetch_scanline_x2b10g10r10, + fetch_pixel_generic_lossy_32, fetch_pixel_x2b10g10r10, + NULL, store_scanline_x2b10g10r10 }, + + /* YUV formats */ + { PIXMAN_yuy2, +- fetch_scanline_yuy2, fetch_scanline_generic_64, ++ NULL, fetch_scanline_yuy2, fetch_scanline_generic_64, + fetch_pixel_yuy2, fetch_pixel_generic_64, + NULL, NULL }, + + { PIXMAN_yv12, +- fetch_scanline_yv12, fetch_scanline_generic_64, ++ NULL, fetch_scanline_yv12, fetch_scanline_generic_64, + fetch_pixel_yv12, fetch_pixel_generic_64, + NULL, NULL }, + + { PIXMAN_null }, + }; + + static void + setup_accessors (bits_image_t *image) + { + const format_info_t *info = accessors; + + while (info->format != PIXMAN_null) + { + if (info->format == image->format) + { ++ image->fetch_scanline_16 = info->fetch_scanline_16; + image->fetch_scanline_32 = info->fetch_scanline_32; + image->fetch_scanline_64 = info->fetch_scanline_64; + image->fetch_pixel_32 = info->fetch_pixel_32; + image->fetch_pixel_64 = info->fetch_pixel_64; ++ image->store_scanline_16 = info->store_scanline_16; + image->store_scanline_32 = info->store_scanline_32; + image->store_scanline_64 = info->store_scanline_64; + + return; + } + + info++; + } +diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c +--- a/gfx/cairo/libpixman/src/pixman-bits-image.c ++++ b/gfx/cairo/libpixman/src/pixman-bits-image.c +@@ -1247,16 +1247,31 @@ src_get_scanline_wide (pixman_iter_t *it + + void + _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) + { + if (iter->flags & ITER_NARROW) + iter->get_scanline = src_get_scanline_narrow; + else + iter->get_scanline = src_get_scanline_wide; ++ ++} ++ ++static uint32_t * ++dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) ++{ ++ pixman_image_t *image = iter->image; ++ int x = iter->x; ++ int y = iter->y; ++ int width = iter->width; ++ uint32_t * buffer = iter->buffer; ++ ++ image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask); ++ ++ return iter->buffer; + } + + static uint32_t * + dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) + { + pixman_image_t *image = iter->image; + int x = iter->x; + int y = iter->y; +@@ -1327,16 +1342,30 @@ dest_get_scanline_wide (pixman_iter_t *i + free (alpha); + } + } + + return iter->buffer; + } + + static void ++dest_write_back_16 (pixman_iter_t *iter) ++{ ++ bits_image_t * image = &iter->image->bits; ++ int x = iter->x; ++ int y = iter->y; ++ int width = iter->width; ++ const uint32_t *buffer = iter->buffer; ++ ++ image->store_scanline_16 (image, x, y, width, buffer); ++ ++ iter->y++; ++} ++ ++static void + dest_write_back_narrow (pixman_iter_t *iter) + { + bits_image_t * image = &iter->image->bits; + int x = iter->x; + int y = iter->y; + int width = iter->width; + const uint32_t *buffer = iter->buffer; + +@@ -1375,28 +1404,41 @@ dest_write_back_wide (pixman_iter_t *ite + } + + iter->y++; + } + + void + _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) + { +- if (iter->flags & ITER_NARROW) ++ if (iter->flags & ITER_16) ++ { ++ if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == ++ (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ++ { ++ iter->get_scanline = _pixman_iter_get_scanline_noop; ++ } ++ else ++ { ++ iter->get_scanline = dest_get_scanline_16; ++ } ++ iter->write_back = dest_write_back_16; ++ } ++ else if (iter->flags & ITER_NARROW) + { + if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == + (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) + { + iter->get_scanline = _pixman_iter_get_scanline_noop; + } + else + { + iter->get_scanline = dest_get_scanline_narrow; + } +- ++ + iter->write_back = dest_write_back_narrow; + } + else + { + iter->get_scanline = dest_get_scanline_wide; + iter->write_back = dest_write_back_wide; + } + } +diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c +new file mode 100644 +--- /dev/null ++++ b/gfx/cairo/libpixman/src/pixman-combine16.c +@@ -0,0 +1,124 @@ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <math.h> ++#include <string.h> ++ ++#include "pixman-private.h" ++ ++#include "pixman-combine32.h" ++ ++static force_inline uint32_t ++combine_mask (const uint32_t src, const uint32_t mask) ++{ ++ uint32_t s, m; ++ ++ m = mask >> A_SHIFT; ++ ++ if (!m) ++ return 0; ++ s = src; ++ ++ UN8x4_MUL_UN8 (s, m); ++ ++ return s; ++} ++ ++static inline uint32_t convert_0565_to_8888(uint16_t color) ++{ ++ return CONVERT_0565_TO_8888(color); ++} ++ ++static inline uint16_t convert_8888_to_0565(uint32_t color) ++{ ++ return CONVERT_8888_TO_0565(color); ++} ++ ++static void ++combine_src_u (pixman_implementation_t *imp, ++ pixman_op_t op, ++ uint32_t * dest, ++ const uint32_t * src, ++ const uint32_t * mask, ++ int width) ++{ ++ int i; ++ ++ if (!mask) ++ memcpy (dest, src, width * sizeof (uint16_t)); ++ else ++ { ++ uint16_t *d = (uint16_t*)dest; ++ uint16_t *src16 = (uint16_t*)src; ++ for (i = 0; i < width; ++i) ++ { ++ if ((*mask & 0xff000000) == 0xff000000) { ++ // it's likely worth special casing ++ // fully opaque because it avoids ++ // the cost of conversion as well the multiplication ++ *(d + i) = *src16; ++ } else { ++ // the mask is still 32bits ++ uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask); ++ *(d + i) = convert_8888_to_0565(s); ++ } ++ mask++; ++ src16++; ++ } ++ } ++ ++} ++ ++static void ++combine_over_u (pixman_implementation_t *imp, ++ pixman_op_t op, ++ uint32_t * dest, ++ const uint32_t * src, ++ const uint32_t * mask, ++ int width) ++{ ++ int i; ++ ++ if (!mask) ++ memcpy (dest, src, width * sizeof (uint16_t)); ++ else ++ { ++ uint16_t *d = (uint16_t*)dest; ++ uint16_t *src16 = (uint16_t*)src; ++ for (i = 0; i < width; ++i) ++ { ++ if ((*mask & 0xff000000) == 0xff000000) { ++ // it's likely worth special casing ++ // fully opaque because it avoids ++ // the cost of conversion as well the multiplication ++ *(d + i) = *src16; ++ } else if ((*mask & 0xff000000) == 0x00000000) { ++ // keep the dest the same ++ } else { ++ // the mask is still 32bits ++ uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask); ++ uint32_t ia = ALPHA_8 (~s); ++ uint32_t d32 = convert_0565_to_8888(*(d + i)); ++ UN8x4_MUL_UN8_ADD_UN8x4 (d32, ia, s); ++ *(d + i) = convert_8888_to_0565(d32); ++ } ++ mask++; ++ src16++; ++ } ++ } ++ ++} ++ ++ ++void ++_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp) ++{ ++ int i; ++ for (i = 0; i < PIXMAN_N_OPERATORS; i++) { ++ imp->combine_16[i] = NULL; ++ } ++ imp->combine_16[PIXMAN_OP_SRC] = combine_src_u; ++ imp->combine_16[PIXMAN_OP_OVER] = combine_over_u; ++} ++ +diff --git a/gfx/cairo/libpixman/src/pixman-general.c b/gfx/cairo/libpixman/src/pixman-general.c +--- a/gfx/cairo/libpixman/src/pixman-general.c ++++ b/gfx/cairo/libpixman/src/pixman-general.c +@@ -106,46 +106,61 @@ general_composite_rect (pixman_implemen + PIXMAN_COMPOSITE_ARGS (info); + uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8]; + uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; + uint8_t *src_buffer, *mask_buffer, *dest_buffer; + pixman_iter_t src_iter, mask_iter, dest_iter; + pixman_combine_32_func_t compose; + pixman_bool_t component_alpha; + iter_flags_t narrow, src_flags; ++ iter_flags_t rgb16; + int Bpp; + int i; + + if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && + (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && + (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)) + { + narrow = ITER_NARROW; + Bpp = 4; + } + else + { + narrow = 0; + Bpp = 8; + } + ++ // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps ++ // by having it deal more specifically with different intermediate formats ++ if ( ++ (dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) && ++ ( op == PIXMAN_OP_SRC || ++ (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE)) ++ ) ++ ) { ++ rgb16 = ITER_16; ++ } else { ++ rgb16 = 0; ++ } ++ ++ + if (width * Bpp > SCANLINE_BUFFER_LENGTH) + { + scanline_buffer = pixman_malloc_abc (width, 3, Bpp); + + if (!scanline_buffer) + return; + } + + src_buffer = scanline_buffer; + mask_buffer = src_buffer + width * Bpp; + dest_buffer = mask_buffer + width * Bpp; + + /* src iter */ +- src_flags = narrow | op_flags[op].src; ++ src_flags = narrow | op_flags[op].src | rgb16; + + _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image, + src_x, src_y, width, height, + src_buffer, src_flags); + + /* mask iter */ + if ((src_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == + (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) +@@ -164,20 +179,20 @@ general_composite_rect (pixman_implemen + + _pixman_implementation_src_iter_init ( + imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height, + mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB)); + + /* dest iter */ + _pixman_implementation_dest_iter_init ( + imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, +- dest_buffer, narrow | op_flags[op].dst); ++ dest_buffer, narrow | op_flags[op].dst | rgb16); + + compose = _pixman_implementation_lookup_combiner ( +- imp->toplevel, op, component_alpha, narrow); ++ imp->toplevel, op, component_alpha, narrow, !!rgb16); + + if (!compose) + return; + + for (i = 0; i < height; ++i) + { + uint32_t *s, *m, *d; + +@@ -234,16 +249,17 @@ general_fill (pixman_implementation_t *i + return FALSE; + } + + pixman_implementation_t * + _pixman_implementation_create_general (void) + { + pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); + ++ _pixman_setup_combiner_functions_16 (imp); + _pixman_setup_combiner_functions_32 (imp); + _pixman_setup_combiner_functions_64 (imp); + + imp->blt = general_blt; + imp->fill = general_fill; + imp->src_iter_init = general_src_iter_init; + imp->dest_iter_init = general_dest_iter_init; + +diff --git a/gfx/cairo/libpixman/src/pixman-image.c b/gfx/cairo/libpixman/src/pixman-image.c +--- a/gfx/cairo/libpixman/src/pixman-image.c ++++ b/gfx/cairo/libpixman/src/pixman-image.c +@@ -451,16 +451,20 @@ compute_image_info (pixman_image_t *imag + flags |= FAST_PATH_IS_OPAQUE; + } + + if (image->bits.read_func || image->bits.write_func) + flags &= ~FAST_PATH_NO_ACCESSORS; + + if (PIXMAN_FORMAT_IS_WIDE (image->bits.format)) + flags &= ~FAST_PATH_NARROW_FORMAT; ++ ++ if (image->bits.format == PIXMAN_r5g6b5) ++ flags |= FAST_PATH_16_FORMAT; ++ + break; + + case RADIAL: + code = PIXMAN_unknown; + + /* + * As explained in pixman-radial-gradient.c, every point of + * the plane has a valid associated radius (and thus will be +diff --git a/gfx/cairo/libpixman/src/pixman-implementation.c b/gfx/cairo/libpixman/src/pixman-implementation.c +--- a/gfx/cairo/libpixman/src/pixman-implementation.c ++++ b/gfx/cairo/libpixman/src/pixman-implementation.c +@@ -101,45 +101,51 @@ pixman_implementation_t * + imp->fill = delegate_fill; + imp->src_iter_init = delegate_src_iter_init; + imp->dest_iter_init = delegate_dest_iter_init; + + imp->fast_paths = fast_paths; + + for (i = 0; i < PIXMAN_N_OPERATORS; ++i) + { ++ imp->combine_16[i] = NULL; + imp->combine_32[i] = NULL; + imp->combine_64[i] = NULL; + imp->combine_32_ca[i] = NULL; + imp->combine_64_ca[i] = NULL; + } + + return imp; + } + + pixman_combine_32_func_t + _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, + pixman_op_t op, + pixman_bool_t component_alpha, +- pixman_bool_t narrow) ++ pixman_bool_t narrow, ++ pixman_bool_t rgb16) + { + pixman_combine_32_func_t f; + + do + { + pixman_combine_32_func_t (*combiners[]) = + { + (pixman_combine_32_func_t *)imp->combine_64, + (pixman_combine_32_func_t *)imp->combine_64_ca, + imp->combine_32, + imp->combine_32_ca, ++ (pixman_combine_32_func_t *)imp->combine_16, ++ NULL, + }; +- +- f = combiners[component_alpha | (narrow << 1)][op]; +- ++ if (rgb16) { ++ f = combiners[4][op]; ++ } else { ++ f = combiners[component_alpha + (narrow << 1)][op]; ++ } + imp = imp->delegate; + } + while (!f); + + return f; + } + + pixman_bool_t +diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c +--- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c ++++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c +@@ -217,42 +217,185 @@ linear_get_scanline_narrow (pixman_iter_ + } + } + + iter->y++; + + return iter->buffer; + } + ++static uint16_t convert_8888_to_0565(uint32_t color) ++{ ++ return CONVERT_8888_TO_0565(color); ++} ++ ++static uint32_t * ++linear_get_scanline_16 (pixman_iter_t *iter, ++ const uint32_t *mask) ++{ ++ pixman_image_t *image = iter->image; ++ int x = iter->x; ++ int y = iter->y; ++ int width = iter->width; ++ uint16_t * buffer = (uint16_t*)iter->buffer; ++ ++ pixman_vector_t v, unit; ++ pixman_fixed_32_32_t l; ++ pixman_fixed_48_16_t dx, dy; ++ gradient_t *gradient = (gradient_t *)image; ++ linear_gradient_t *linear = (linear_gradient_t *)image; ++ uint16_t *end = buffer + width; ++ pixman_gradient_walker_t walker; ++ ++ _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); ++ ++ /* reference point is the center of the pixel */ ++ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; ++ v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; ++ v.vector[2] = pixman_fixed_1; ++ ++ if (image->common.transform) ++ { ++ if (!pixman_transform_point_3d (image->common.transform, &v)) ++ return iter->buffer; ++ ++ unit.vector[0] = image->common.transform->matrix[0][0]; ++ unit.vector[1] = image->common.transform->matrix[1][0]; ++ unit.vector[2] = image->common.transform->matrix[2][0]; ++ } ++ else ++ { ++ unit.vector[0] = pixman_fixed_1; ++ unit.vector[1] = 0; ++ unit.vector[2] = 0; ++ } ++ ++ dx = linear->p2.x - linear->p1.x; ++ dy = linear->p2.y - linear->p1.y; ++ ++ l = dx * dx + dy * dy; ++ ++ if (l == 0 || unit.vector[2] == 0) ++ { ++ /* affine transformation only */ ++ pixman_fixed_32_32_t t, next_inc; ++ double inc; ++ ++ if (l == 0 || v.vector[2] == 0) ++ { ++ t = 0; ++ inc = 0; ++ } ++ else ++ { ++ double invden, v2; ++ ++ invden = pixman_fixed_1 * (double) pixman_fixed_1 / ++ (l * (double) v.vector[2]); ++ v2 = v.vector[2] * (1. / pixman_fixed_1); ++ t = ((dx * v.vector[0] + dy * v.vector[1]) - ++ (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; ++ inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; ++ } ++ next_inc = 0; ++ ++ if (((pixman_fixed_32_32_t )(inc * width)) == 0) ++ { ++ register uint16_t color; ++ ++ color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t)); ++ while (buffer < end) ++ *buffer++ = color; ++ } ++ else ++ { ++ int i; ++ ++ i = 0; ++ while (buffer < end) ++ { ++ if (!mask || *mask++) ++ { ++ *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, ++ t + next_inc)); ++ } ++ i++; ++ next_inc = inc * i; ++ buffer++; ++ } ++ } ++ } ++ else ++ { ++ /* projective transformation */ ++ double t; ++ ++ t = 0; ++ ++ while (buffer < end) ++ { ++ if (!mask || *mask++) ++ { ++ if (v.vector[2] != 0) ++ { ++ double invden, v2; ++ ++ invden = pixman_fixed_1 * (double) pixman_fixed_1 / ++ (l * (double) v.vector[2]); ++ v2 = v.vector[2] * (1. / pixman_fixed_1); ++ t = ((dx * v.vector[0] + dy * v.vector[1]) - ++ (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; ++ } ++ ++ *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t)); ++ } ++ ++ ++buffer; ++ ++ v.vector[0] += unit.vector[0]; ++ v.vector[1] += unit.vector[1]; ++ v.vector[2] += unit.vector[2]; ++ } ++ } ++ ++ iter->y++; ++ ++ return iter->buffer; ++} ++ + static uint32_t * + linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) + { + uint32_t *buffer = linear_get_scanline_narrow (iter, NULL); + + pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); + + return buffer; + } + + void + _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) + { + if (linear_gradient_is_horizontal ( + iter->image, iter->x, iter->y, iter->width, iter->height)) + { +- if (iter->flags & ITER_NARROW) ++ if (iter->flags & ITER_16) ++ linear_get_scanline_16 (iter, NULL); ++ else if (iter->flags & ITER_NARROW) + linear_get_scanline_narrow (iter, NULL); + else + linear_get_scanline_wide (iter, NULL); + + iter->get_scanline = _pixman_iter_get_scanline_noop; + } + else + { +- if (iter->flags & ITER_NARROW) ++ if (iter->flags & ITER_16) ++ iter->get_scanline = linear_get_scanline_16; ++ else if (iter->flags & ITER_NARROW) + iter->get_scanline = linear_get_scanline_narrow; + else + iter->get_scanline = linear_get_scanline_wide; + } + } + + PIXMAN_EXPORT pixman_image_t * + pixman_image_create_linear_gradient (pixman_point_fixed_t * p1, +diff --git a/gfx/cairo/libpixman/src/pixman-private.h b/gfx/cairo/libpixman/src/pixman-private.h +--- a/gfx/cairo/libpixman/src/pixman-private.h ++++ b/gfx/cairo/libpixman/src/pixman-private.h +@@ -152,24 +152,28 @@ struct bits_image + int height; + uint32_t * bits; + uint32_t * free_me; + int rowstride; /* in number of uint32_t's */ + + fetch_scanline_t get_scanline_32; + fetch_scanline_t get_scanline_64; + ++ fetch_scanline_t fetch_scanline_16; ++ + fetch_scanline_t fetch_scanline_32; + fetch_pixel_32_t fetch_pixel_32; + store_scanline_t store_scanline_32; + + fetch_scanline_t fetch_scanline_64; + fetch_pixel_64_t fetch_pixel_64; + store_scanline_t store_scanline_64; + ++ store_scanline_t store_scanline_16; ++ + /* Used for indirect access to the bits */ + pixman_read_memory_func_t read_func; + pixman_write_memory_func_t write_func; + }; + + union pixman_image + { + image_type_t type; +@@ -202,17 +206,24 @@ typedef enum + * destination. + * + * When he destination is xRGB, this is useful knowledge, because then + * we can treat it as if it were ARGB, which means in some cases we can + * avoid copying it to a temporary buffer. + */ + ITER_LOCALIZED_ALPHA = (1 << 1), + ITER_IGNORE_ALPHA = (1 << 2), +- ITER_IGNORE_RGB = (1 << 3) ++ ITER_IGNORE_RGB = (1 << 3), ++ ++ /* With the addition of ITER_16 we now have two flags that to represent ++ * 3 pipelines. This means that there can be an invalid state when ++ * both ITER_NARROW and ITER_16 are set. In this case ++ * ITER_16 overrides NARROW and we should use the 16 bit pipeline. ++ * Note: ITER_16 still has a 32 bit mask, which is a bit weird. */ ++ ITER_16 = (1 << 4) + } iter_flags_t; + + struct pixman_iter_t + { + /* These are initialized by _pixman_implementation_{src,dest}_init */ + pixman_image_t * image; + uint32_t * buffer; + int x, y; +@@ -429,16 +440,17 @@ typedef pixman_bool_t (*pixman_fill_func + int x, + int y, + int width, + int height, + uint32_t xor); + typedef void (*pixman_iter_init_func_t) (pixman_implementation_t *imp, + pixman_iter_t *iter); + ++void _pixman_setup_combiner_functions_16 (pixman_implementation_t *imp); + void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp); + void _pixman_setup_combiner_functions_64 (pixman_implementation_t *imp); + + typedef struct + { + pixman_op_t op; + pixman_format_code_t src_format; + uint32_t src_flags; +@@ -459,32 +471,34 @@ struct pixman_implementation_t + pixman_fill_func_t fill; + pixman_iter_init_func_t src_iter_init; + pixman_iter_init_func_t dest_iter_init; + + pixman_combine_32_func_t combine_32[PIXMAN_N_OPERATORS]; + pixman_combine_32_func_t combine_32_ca[PIXMAN_N_OPERATORS]; + pixman_combine_64_func_t combine_64[PIXMAN_N_OPERATORS]; + pixman_combine_64_func_t combine_64_ca[PIXMAN_N_OPERATORS]; ++ pixman_combine_64_func_t combine_16[PIXMAN_N_OPERATORS]; + }; + + uint32_t + _pixman_image_get_solid (pixman_implementation_t *imp, + pixman_image_t * image, + pixman_format_code_t format); + + pixman_implementation_t * + _pixman_implementation_create (pixman_implementation_t *delegate, + const pixman_fast_path_t *fast_paths); + + pixman_combine_32_func_t + _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, + pixman_op_t op, + pixman_bool_t component_alpha, +- pixman_bool_t wide); ++ pixman_bool_t wide, ++ pixman_bool_t rgb16); + + pixman_bool_t + _pixman_implementation_blt (pixman_implementation_t *imp, + uint32_t * src_bits, + uint32_t * dst_bits, + int src_stride, + int dst_stride, + int src_bpp, +@@ -613,16 +627,17 @@ uint32_t * + #define FAST_PATH_Y_UNIT_ZERO (1 << 18) + #define FAST_PATH_BILINEAR_FILTER (1 << 19) + #define FAST_PATH_ROTATE_90_TRANSFORM (1 << 20) + #define FAST_PATH_ROTATE_180_TRANSFORM (1 << 21) + #define FAST_PATH_ROTATE_270_TRANSFORM (1 << 22) + #define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST (1 << 23) + #define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR (1 << 24) + #define FAST_PATH_BITS_IMAGE (1 << 25) ++#define FAST_PATH_16_FORMAT (1 << 26) + + #define FAST_PATH_PAD_REPEAT \ + (FAST_PATH_NO_NONE_REPEAT | \ + FAST_PATH_NO_NORMAL_REPEAT | \ + FAST_PATH_NO_REFLECT_REPEAT) + + #define FAST_PATH_NORMAL_REPEAT \ + (FAST_PATH_NO_NONE_REPEAT | \ +diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c +--- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c ++++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c +@@ -395,35 +395,289 @@ radial_get_scanline_narrow (pixman_iter_ + v.vector[2] += unit.vector[2]; + } + } + + iter->y++; + return iter->buffer; + } + ++static uint16_t convert_8888_to_0565(uint32_t color) ++{ ++ return CONVERT_8888_TO_0565(color); ++} ++ ++static uint32_t * ++radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) ++{ ++ /* ++ * Implementation of radial gradients following the PDF specification. ++ * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference ++ * Manual (PDF 32000-1:2008 at the time of this writing). ++ * ++ * In the radial gradient problem we are given two circles (c₁,r₁) and ++ * (c₂,r₂) that define the gradient itself. ++ * ++ * Mathematically the gradient can be defined as the family of circles ++ * ++ * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂) ++ * ++ * excluding those circles whose radius would be < 0. When a point ++ * belongs to more than one circle, the one with a bigger t is the only ++ * one that contributes to its color. When a point does not belong ++ * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0). ++ * Further limitations on the range of values for t are imposed when ++ * the gradient is not repeated, namely t must belong to [0,1]. ++ * ++ * The graphical result is the same as drawing the valid (radius > 0) ++ * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient ++ * is not repeated) using SOURCE operator composition. ++ * ++ * It looks like a cone pointing towards the viewer if the ending circle ++ * is smaller than the starting one, a cone pointing inside the page if ++ * the starting circle is the smaller one and like a cylinder if they ++ * have the same radius. ++ * ++ * What we actually do is, given the point whose color we are interested ++ * in, compute the t values for that point, solving for t in: ++ * ++ * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂ ++ * ++ * Let's rewrite it in a simpler way, by defining some auxiliary ++ * variables: ++ * ++ * cd = c₂ - c₁ ++ * pd = p - c₁ ++ * dr = r₂ - r₁ ++ * length(t·cd - pd) = r₁ + t·dr ++ * ++ * which actually means ++ * ++ * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr ++ * ++ * or ++ * ++ * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr. ++ * ++ * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes: ++ * ++ * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)² ++ * ++ * where we can actually expand the squares and solve for t: ++ * ++ * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² = ++ * = r₁² + 2·r₁·t·dr + t²·dr² ++ * ++ * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t + ++ * (pdx² + pdy² - r₁²) = 0 ++ * ++ * A = cdx² + cdy² - dr² ++ * B = pdx·cdx + pdy·cdy + r₁·dr ++ * C = pdx² + pdy² - r₁² ++ * At² - 2Bt + C = 0 ++ * ++ * The solutions (unless the equation degenerates because of A = 0) are: ++ * ++ * t = (B ± ⎷(B² - A·C)) / A ++ * ++ * The solution we are going to prefer is the bigger one, unless the ++ * radius associated to it is negative (or it falls outside the valid t ++ * range). ++ * ++ * Additional observations (useful for optimizations): ++ * A does not depend on p ++ * ++ * A < 0 <=> one of the two circles completely contains the other one ++ * <=> for every p, the radiuses associated with the two t solutions ++ * have opposite sign ++ */ ++ pixman_image_t *image = iter->image; ++ int x = iter->x; ++ int y = iter->y; ++ int width = iter->width; ++ uint16_t *buffer = iter->buffer; ++ ++ gradient_t *gradient = (gradient_t *)image; ++ radial_gradient_t *radial = (radial_gradient_t *)image; ++ uint16_t *end = buffer + width; ++ pixman_gradient_walker_t walker; ++ pixman_vector_t v, unit; ++ ++ /* reference point is the center of the pixel */ ++ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; ++ v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; ++ v.vector[2] = pixman_fixed_1; ++ ++ _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); ++ ++ if (image->common.transform) ++ { ++ if (!pixman_transform_point_3d (image->common.transform, &v)) ++ return iter->buffer; ++ ++ unit.vector[0] = image->common.transform->matrix[0][0]; ++ unit.vector[1] = image->common.transform->matrix[1][0]; ++ unit.vector[2] = image->common.transform->matrix[2][0]; ++ } ++ else ++ { ++ unit.vector[0] = pixman_fixed_1; ++ unit.vector[1] = 0; ++ unit.vector[2] = 0; ++ } ++ ++ if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1) ++ { ++ /* ++ * Given: ++ * ++ * t = (B ± ⎷(B² - A·C)) / A ++ * ++ * where ++ * ++ * A = cdx² + cdy² - dr² ++ * B = pdx·cdx + pdy·cdy + r₁·dr ++ * C = pdx² + pdy² - r₁² ++ * det = B² - A·C ++ * ++ * Since we have an affine transformation, we know that (pdx, pdy) ++ * increase linearly with each pixel, ++ * ++ * pdx = pdx₀ + n·ux, ++ * pdy = pdy₀ + n·uy, ++ * ++ * we can then express B, C and det through multiple differentiation. ++ */ ++ pixman_fixed_32_32_t b, db, c, dc, ddc; ++ ++ /* warning: this computation may overflow */ ++ v.vector[0] -= radial->c1.x; ++ v.vector[1] -= radial->c1.y; ++ ++ /* ++ * B and C are computed and updated exactly. ++ * If fdot was used instead of dot, in the worst case it would ++ * lose 11 bits of precision in each of the multiplication and ++ * summing up would zero out all the bit that were preserved, ++ * thus making the result 0 instead of the correct one. ++ * This would mean a worst case of unbound relative error or ++ * about 2^10 absolute error ++ */ ++ b = dot (v.vector[0], v.vector[1], radial->c1.radius, ++ radial->delta.x, radial->delta.y, radial->delta.radius); ++ db = dot (unit.vector[0], unit.vector[1], 0, ++ radial->delta.x, radial->delta.y, 0); ++ ++ c = dot (v.vector[0], v.vector[1], ++ -((pixman_fixed_48_16_t) radial->c1.radius), ++ v.vector[0], v.vector[1], radial->c1.radius); ++ dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0], ++ 2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1], ++ 0, ++ unit.vector[0], unit.vector[1], 0); ++ ddc = 2 * dot (unit.vector[0], unit.vector[1], 0, ++ unit.vector[0], unit.vector[1], 0); ++ ++ while (buffer < end) ++ { ++ if (!mask || *mask++) ++ { ++ *buffer = convert_8888_to_0565( ++ radial_compute_color (radial->a, b, c, ++ radial->inva, ++ radial->delta.radius, ++ radial->mindr, ++ &walker, ++ image->common.repeat)); ++ } ++ ++ b += db; ++ c += dc; ++ dc += ddc; ++ ++buffer; ++ } ++ } ++ else ++ { ++ /* projective */ ++ /* Warning: ++ * error propagation guarantees are much looser than in the affine case ++ */ ++ while (buffer < end) ++ { ++ if (!mask || *mask++) ++ { ++ if (v.vector[2] != 0) ++ { ++ double pdx, pdy, invv2, b, c; ++ ++ invv2 = 1. * pixman_fixed_1 / v.vector[2]; ++ ++ pdx = v.vector[0] * invv2 - radial->c1.x; ++ /* / pixman_fixed_1 */ ++ ++ pdy = v.vector[1] * invv2 - radial->c1.y; ++ /* / pixman_fixed_1 */ ++ ++ b = fdot (pdx, pdy, radial->c1.radius, ++ radial->delta.x, radial->delta.y, ++ radial->delta.radius); ++ /* / pixman_fixed_1 / pixman_fixed_1 */ ++ ++ c = fdot (pdx, pdy, -radial->c1.radius, ++ pdx, pdy, radial->c1.radius); ++ /* / pixman_fixed_1 / pixman_fixed_1 */ ++ ++ *buffer = convert_8888_to_0565 ( ++ radial_compute_color (radial->a, b, c, ++ radial->inva, ++ radial->delta.radius, ++ radial->mindr, ++ &walker, ++ image->common.repeat)); ++ } ++ else ++ { ++ *buffer = 0; ++ } ++ } ++ ++ ++buffer; ++ ++ v.vector[0] += unit.vector[0]; ++ v.vector[1] += unit.vector[1]; ++ v.vector[2] += unit.vector[2]; ++ } ++ } ++ ++ iter->y++; ++ return iter->buffer; ++} + static uint32_t * + radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) + { + uint32_t *buffer = radial_get_scanline_narrow (iter, NULL); + + pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); + + return buffer; + } + + void + _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) + { +- if (iter->flags & ITER_NARROW) ++ if (iter->flags & ITER_16) ++ iter->get_scanline = radial_get_scanline_16; ++ else if (iter->flags & ITER_NARROW) + iter->get_scanline = radial_get_scanline_narrow; + else + iter->get_scanline = radial_get_scanline_wide; + } + ++ + PIXMAN_EXPORT pixman_image_t * + pixman_image_create_radial_gradient (pixman_point_fixed_t * inner, + pixman_point_fixed_t * outer, + pixman_fixed_t inner_radius, + pixman_fixed_t outer_radius, + const pixman_gradient_stop_t *stops, + int n_stops) + { |