mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
ba4ec6e202
This is to support dithering 16 bit gradients with decent performance.
1243 lines
36 KiB
Diff
1243 lines
36 KiB
Diff
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)
|
|
{
|