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