summaryrefslogtreecommitdiffstats
path: root/gfx/cairo/pixman-dither.patch
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/cairo/pixman-dither.patch')
-rw-r--r--gfx/cairo/pixman-dither.patch310
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++;
+