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