michael@0: diff --git a/gfx/cairo/libpixman/src/pixman-dither.h b/gfx/cairo/libpixman/src/pixman-dither.h michael@0: new file mode 100644 michael@0: --- /dev/null michael@0: +++ b/gfx/cairo/libpixman/src/pixman-dither.h michael@0: @@ -0,0 +1,51 @@ michael@0: +#define R16_BITS 5 michael@0: +#define G16_BITS 6 michael@0: +#define B16_BITS 5 michael@0: + michael@0: +#define R16_SHIFT (B16_BITS + G16_BITS) michael@0: +#define G16_SHIFT (B16_BITS) michael@0: +#define B16_SHIFT 0 michael@0: + michael@0: +#define MASK 0xff michael@0: +#define ONE_HALF 0x80 michael@0: + michael@0: +#define A_SHIFT 8 * 3 michael@0: +#define R_SHIFT 8 * 2 michael@0: +#define G_SHIFT 8 michael@0: +#define A_MASK 0xff000000 michael@0: +#define R_MASK 0xff0000 michael@0: +#define G_MASK 0xff00 michael@0: + michael@0: +#define RB_MASK 0xff00ff michael@0: +#define AG_MASK 0xff00ff00 michael@0: +#define RB_ONE_HALF 0x800080 michael@0: +#define RB_MASK_PLUS_ONE 0x10000100 michael@0: + michael@0: +#define ALPHA_8(x) ((x) >> A_SHIFT) michael@0: +#define RED_8(x) (((x) >> R_SHIFT) & MASK) michael@0: +#define GREEN_8(x) (((x) >> G_SHIFT) & MASK) michael@0: +#define BLUE_8(x) ((x) & MASK) michael@0: + michael@0: +// This uses the same dithering technique that Skia does. michael@0: +// It is essentially preturbing the lower bit based on the michael@0: +// high bit michael@0: +static inline uint16_t dither_32_to_16(uint32_t c) michael@0: +{ michael@0: + uint8_t b = BLUE_8(c); michael@0: + uint8_t g = GREEN_8(c); michael@0: + uint8_t r = RED_8(c); michael@0: + r = ((r << 1) - ((r >> (8 - R16_BITS) << (8 - R16_BITS)) | (r >> R16_BITS))) >> (8 - R16_BITS); michael@0: + g = ((g << 1) - ((g >> (8 - G16_BITS) << (8 - G16_BITS)) | (g >> G16_BITS))) >> (8 - G16_BITS); michael@0: + b = ((b << 1) - ((b >> (8 - B16_BITS) << (8 - B16_BITS)) | (b >> B16_BITS))) >> (8 - B16_BITS); michael@0: + return ((r << R16_SHIFT) | (g << G16_SHIFT) | (b << B16_SHIFT)); michael@0: +} michael@0: + michael@0: +static inline uint16_t dither_8888_to_0565(uint32_t color, pixman_bool_t toggle) michael@0: +{ michael@0: + // alternate between a preturbed truncation and a regular truncation michael@0: + if (toggle) { michael@0: + return dither_32_to_16(color); michael@0: + } else { michael@0: + return CONVERT_8888_TO_0565(color); michael@0: + } michael@0: +} 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: @@ -26,16 +26,18 @@ michael@0: */ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: #include michael@0: #include "pixman-private.h" michael@0: michael@0: +#include "pixman-dither.h" michael@0: + michael@0: static pixman_bool_t michael@0: linear_gradient_is_horizontal (pixman_image_t *image, michael@0: int x, michael@0: int y, michael@0: int width, michael@0: int height) michael@0: { michael@0: linear_gradient_t *linear = (linear_gradient_t *)image; michael@0: @@ -222,25 +224,28 @@ linear_get_scanline_narrow (pixman_iter_ 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: + 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: + pixman_bool_t toggle = ((x ^ y) & 1); 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: @@ -294,34 +299,47 @@ linear_get_scanline_16 (pixman_iter_t * 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: + register uint32_t color; michael@0: + uint16_t dither_diff; michael@0: + uint16_t color16; michael@0: + uint16_t color16b; 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: + color = _pixman_gradient_walker_pixel (&walker, t); michael@0: + color16 = dither_8888_to_0565(color, toggle); michael@0: + color16b = dither_8888_to_0565(color, toggle^1); michael@0: + // compute the difference michael@0: + dither_diff = color16 ^ color16b; michael@0: + while (buffer < end) { michael@0: + *buffer++ = color16; michael@0: + // use dither_diff to toggle between color16 and color16b michael@0: + color16 ^= dither_diff; michael@0: + toggle ^= 1; michael@0: + } 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: + *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, michael@0: + t + next_inc), michael@0: + toggle); michael@0: } michael@0: + toggle ^= 1; 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: @@ -340,18 +358,20 @@ linear_get_scanline_16 (pixman_iter_t * 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: + *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t), michael@0: + toggle); michael@0: } michael@0: + toggle ^= 1; 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: @@ -369,17 +389,18 @@ linear_get_scanline_wide (pixman_iter_t 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: + // XXX: we can't use this optimization when dithering michael@0: + if (0 && linear_gradient_is_horizontal ( michael@0: iter->image, iter->x, iter->y, iter->width, iter->height)) michael@0: { 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: 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: @@ -29,16 +29,18 @@ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include "pixman-private.h" michael@0: michael@0: +#include "pixman-dither.h" michael@0: + michael@0: static inline pixman_fixed_32_32_t michael@0: dot (pixman_fixed_48_16_t x1, michael@0: pixman_fixed_48_16_t y1, michael@0: pixman_fixed_48_16_t z1, michael@0: pixman_fixed_48_16_t x2, michael@0: pixman_fixed_48_16_t y2, michael@0: pixman_fixed_48_16_t z2) michael@0: { michael@0: @@ -489,16 +491,17 @@ radial_get_scanline_16 (pixman_iter_t *i 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: + pixman_bool_t toggle = ((x ^ y) & 1); 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: @@ -575,25 +578,27 @@ radial_get_scanline_16 (pixman_iter_t *i 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: + *buffer = dither_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: + image->common.repeat), michael@0: + toggle); michael@0: } michael@0: michael@0: + toggle ^= 1; 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: @@ -621,31 +626,33 @@ radial_get_scanline_16 (pixman_iter_t *i 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: + *buffer = dither_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: + image->common.repeat), michael@0: + toggle); michael@0: } michael@0: else michael@0: { michael@0: *buffer = 0; michael@0: } michael@0: } michael@0: michael@0: ++buffer; michael@0: + toggle ^= 1; 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: