gfx/cairo/pixman-dither.patch

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/cairo/pixman-dither.patch	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,310 @@
     1.4 +diff --git a/gfx/cairo/libpixman/src/pixman-dither.h b/gfx/cairo/libpixman/src/pixman-dither.h
     1.5 +new file mode 100644
     1.6 +--- /dev/null
     1.7 ++++ b/gfx/cairo/libpixman/src/pixman-dither.h
     1.8 +@@ -0,0 +1,51 @@
     1.9 ++#define R16_BITS     5
    1.10 ++#define G16_BITS     6
    1.11 ++#define B16_BITS     5
    1.12 ++
    1.13 ++#define R16_SHIFT    (B16_BITS + G16_BITS)
    1.14 ++#define G16_SHIFT    (B16_BITS)
    1.15 ++#define B16_SHIFT    0
    1.16 ++
    1.17 ++#define MASK 0xff
    1.18 ++#define ONE_HALF 0x80
    1.19 ++
    1.20 ++#define A_SHIFT 8 * 3
    1.21 ++#define R_SHIFT 8 * 2
    1.22 ++#define G_SHIFT 8
    1.23 ++#define A_MASK 0xff000000
    1.24 ++#define R_MASK 0xff0000
    1.25 ++#define G_MASK 0xff00
    1.26 ++
    1.27 ++#define RB_MASK 0xff00ff
    1.28 ++#define AG_MASK 0xff00ff00
    1.29 ++#define RB_ONE_HALF 0x800080
    1.30 ++#define RB_MASK_PLUS_ONE 0x10000100
    1.31 ++
    1.32 ++#define ALPHA_8(x) ((x) >> A_SHIFT)
    1.33 ++#define RED_8(x) (((x) >> R_SHIFT) & MASK)
    1.34 ++#define GREEN_8(x) (((x) >> G_SHIFT) & MASK)
    1.35 ++#define BLUE_8(x) ((x) & MASK)
    1.36 ++
    1.37 ++// This uses the same dithering technique that Skia does.
    1.38 ++// It is essentially preturbing the lower bit based on the
    1.39 ++// high bit
    1.40 ++static inline uint16_t dither_32_to_16(uint32_t c)
    1.41 ++{
    1.42 ++    uint8_t b = BLUE_8(c);
    1.43 ++    uint8_t g = GREEN_8(c);
    1.44 ++    uint8_t r = RED_8(c);
    1.45 ++    r = ((r << 1) - ((r >> (8 - R16_BITS) << (8 - R16_BITS)) | (r >> R16_BITS))) >> (8 - R16_BITS);
    1.46 ++    g = ((g << 1) - ((g >> (8 - G16_BITS) << (8 - G16_BITS)) | (g >> G16_BITS))) >> (8 - G16_BITS);
    1.47 ++    b = ((b << 1) - ((b >> (8 - B16_BITS) << (8 - B16_BITS)) | (b >> B16_BITS))) >> (8 - B16_BITS);
    1.48 ++    return ((r << R16_SHIFT) | (g << G16_SHIFT) | (b << B16_SHIFT));
    1.49 ++}
    1.50 ++
    1.51 ++static inline uint16_t dither_8888_to_0565(uint32_t color, pixman_bool_t toggle)
    1.52 ++{
    1.53 ++    // alternate between a preturbed truncation and a regular truncation
    1.54 ++    if (toggle) {
    1.55 ++	return dither_32_to_16(color);
    1.56 ++    } else {
    1.57 ++	return CONVERT_8888_TO_0565(color);
    1.58 ++    }
    1.59 ++}
    1.60 +diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
    1.61 +--- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c
    1.62 ++++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c
    1.63 +@@ -26,16 +26,18 @@
    1.64 +  */
    1.65 + 
    1.66 + #ifdef HAVE_CONFIG_H
    1.67 + #include <config.h>
    1.68 + #endif
    1.69 + #include <stdlib.h>
    1.70 + #include "pixman-private.h"
    1.71 + 
    1.72 ++#include "pixman-dither.h"
    1.73 ++
    1.74 + static pixman_bool_t
    1.75 + linear_gradient_is_horizontal (pixman_image_t *image,
    1.76 + 			       int             x,
    1.77 + 			       int             y,
    1.78 + 			       int             width,
    1.79 + 			       int             height)
    1.80 + {
    1.81 +     linear_gradient_t *linear = (linear_gradient_t *)image;
    1.82 +@@ -222,25 +224,28 @@ linear_get_scanline_narrow (pixman_iter_
    1.83 +     return iter->buffer;
    1.84 + }
    1.85 + 
    1.86 + static uint16_t convert_8888_to_0565(uint32_t color)
    1.87 + {
    1.88 +     return CONVERT_8888_TO_0565(color);
    1.89 + }
    1.90 + 
    1.91 ++
    1.92 ++
    1.93 + static uint32_t *
    1.94 + linear_get_scanline_16 (pixman_iter_t  *iter,
    1.95 + 			const uint32_t *mask)
    1.96 + {
    1.97 +     pixman_image_t *image  = iter->image;
    1.98 +     int             x      = iter->x;
    1.99 +     int             y      = iter->y;
   1.100 +     int             width  = iter->width;
   1.101 +     uint16_t *      buffer = (uint16_t*)iter->buffer;
   1.102 ++    pixman_bool_t   toggle = ((x ^ y) & 1);
   1.103 + 
   1.104 +     pixman_vector_t v, unit;
   1.105 +     pixman_fixed_32_32_t l;
   1.106 +     pixman_fixed_48_16_t dx, dy;
   1.107 +     gradient_t *gradient = (gradient_t *)image;
   1.108 +     linear_gradient_t *linear = (linear_gradient_t *)image;
   1.109 +     uint16_t *end = buffer + width;
   1.110 +     pixman_gradient_walker_t walker;
   1.111 +@@ -294,34 +299,47 @@ linear_get_scanline_16 (pixman_iter_t  *
   1.112 + 	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   1.113 + 		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   1.114 + 	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
   1.115 + 	}
   1.116 + 	next_inc = 0;
   1.117 + 
   1.118 + 	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
   1.119 + 	{
   1.120 +-	    register uint16_t color;
   1.121 ++	    register uint32_t color;
   1.122 ++	    uint16_t dither_diff;
   1.123 ++	    uint16_t color16;
   1.124 ++	    uint16_t color16b;
   1.125 + 
   1.126 +-	    color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
   1.127 +-	    while (buffer < end)
   1.128 +-		*buffer++ = color;
   1.129 ++	    color = _pixman_gradient_walker_pixel (&walker, t);
   1.130 ++	    color16 = dither_8888_to_0565(color, toggle);
   1.131 ++	    color16b = dither_8888_to_0565(color, toggle^1);
   1.132 ++	    // compute the difference
   1.133 ++	    dither_diff =  color16 ^ color16b;
   1.134 ++	    while (buffer < end) {
   1.135 ++		*buffer++ = color16;
   1.136 ++		// use dither_diff to toggle between color16 and color16b
   1.137 ++		color16 ^= dither_diff;
   1.138 ++		toggle ^= 1;
   1.139 ++	    }
   1.140 + 	}
   1.141 + 	else
   1.142 + 	{
   1.143 + 	    int i;
   1.144 + 
   1.145 + 	    i = 0;
   1.146 + 	    while (buffer < end)
   1.147 + 	    {
   1.148 + 		if (!mask || *mask++)
   1.149 + 		{
   1.150 +-		    *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
   1.151 +-										  t + next_inc));
   1.152 ++		    *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
   1.153 ++										 t + next_inc),
   1.154 ++						  toggle);
   1.155 + 		}
   1.156 ++		toggle ^= 1;
   1.157 + 		i++;
   1.158 + 		next_inc = inc * i;
   1.159 + 		buffer++;
   1.160 + 	    }
   1.161 + 	}
   1.162 +     }
   1.163 +     else
   1.164 +     {
   1.165 +@@ -340,18 +358,20 @@ linear_get_scanline_16 (pixman_iter_t  *
   1.166 + 
   1.167 + 		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
   1.168 + 			(l * (double) v.vector[2]);
   1.169 + 		    v2 = v.vector[2] * (1. / pixman_fixed_1);
   1.170 + 		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
   1.171 + 			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
   1.172 + 		}
   1.173 + 
   1.174 +-		*buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t));
   1.175 ++		*buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t),
   1.176 ++					      toggle);
   1.177 + 	    }
   1.178 ++	    toggle ^= 1;
   1.179 + 
   1.180 + 	    ++buffer;
   1.181 + 
   1.182 + 	    v.vector[0] += unit.vector[0];
   1.183 + 	    v.vector[1] += unit.vector[1];
   1.184 + 	    v.vector[2] += unit.vector[2];
   1.185 + 	}
   1.186 +     }
   1.187 +@@ -369,17 +389,18 @@ linear_get_scanline_wide (pixman_iter_t 
   1.188 +     pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
   1.189 + 
   1.190 +     return buffer;
   1.191 + }
   1.192 + 
   1.193 + void
   1.194 + _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t  *iter)
   1.195 + {
   1.196 +-    if (linear_gradient_is_horizontal (
   1.197 ++    // XXX: we can't use this optimization when dithering
   1.198 ++    if (0 && linear_gradient_is_horizontal (
   1.199 + 	    iter->image, iter->x, iter->y, iter->width, iter->height))
   1.200 +     {
   1.201 + 	if (iter->flags & ITER_16)
   1.202 + 	    linear_get_scanline_16 (iter, NULL);
   1.203 + 	else if (iter->flags & ITER_NARROW)
   1.204 + 	    linear_get_scanline_narrow (iter, NULL);
   1.205 + 	else
   1.206 + 	    linear_get_scanline_wide (iter, NULL);
   1.207 +diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   1.208 +--- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   1.209 ++++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c
   1.210 +@@ -29,16 +29,18 @@
   1.211 + 
   1.212 + #ifdef HAVE_CONFIG_H
   1.213 + #include <config.h>
   1.214 + #endif
   1.215 + #include <stdlib.h>
   1.216 + #include <math.h>
   1.217 + #include "pixman-private.h"
   1.218 + 
   1.219 ++#include "pixman-dither.h"
   1.220 ++
   1.221 + static inline pixman_fixed_32_32_t
   1.222 + dot (pixman_fixed_48_16_t x1,
   1.223 +      pixman_fixed_48_16_t y1,
   1.224 +      pixman_fixed_48_16_t z1,
   1.225 +      pixman_fixed_48_16_t x2,
   1.226 +      pixman_fixed_48_16_t y2,
   1.227 +      pixman_fixed_48_16_t z2)
   1.228 + {
   1.229 +@@ -489,16 +491,17 @@ radial_get_scanline_16 (pixman_iter_t *i
   1.230 +      *   <=> for every p, the radiuses associated with the two t solutions
   1.231 +      *       have opposite sign
   1.232 +      */
   1.233 +     pixman_image_t *image = iter->image;
   1.234 +     int x = iter->x;
   1.235 +     int y = iter->y;
   1.236 +     int width = iter->width;
   1.237 +     uint16_t *buffer = iter->buffer;
   1.238 ++    pixman_bool_t toggle = ((x ^ y) & 1);
   1.239 + 
   1.240 +     gradient_t *gradient = (gradient_t *)image;
   1.241 +     radial_gradient_t *radial = (radial_gradient_t *)image;
   1.242 +     uint16_t *end = buffer + width;
   1.243 +     pixman_gradient_walker_t walker;
   1.244 +     pixman_vector_t v, unit;
   1.245 + 
   1.246 +     /* reference point is the center of the pixel */
   1.247 +@@ -575,25 +578,27 @@ radial_get_scanline_16 (pixman_iter_t *i
   1.248 + 		  unit.vector[0], unit.vector[1], 0);
   1.249 + 	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
   1.250 + 		       unit.vector[0], unit.vector[1], 0);
   1.251 + 
   1.252 + 	while (buffer < end)
   1.253 + 	{
   1.254 + 	    if (!mask || *mask++)
   1.255 + 	    {
   1.256 +-		*buffer = convert_8888_to_0565(
   1.257 ++		*buffer = dither_8888_to_0565(
   1.258 + 			  radial_compute_color (radial->a, b, c,
   1.259 + 						radial->inva,
   1.260 + 						radial->delta.radius,
   1.261 + 						radial->mindr,
   1.262 + 						&walker,
   1.263 +-						image->common.repeat));
   1.264 ++						image->common.repeat),
   1.265 ++			  toggle);
   1.266 + 	    }
   1.267 + 
   1.268 ++	    toggle ^= 1;
   1.269 + 	    b += db;
   1.270 + 	    c += dc;
   1.271 + 	    dc += ddc;
   1.272 + 	    ++buffer;
   1.273 + 	}
   1.274 +     }
   1.275 +     else
   1.276 +     {
   1.277 +@@ -621,31 +626,33 @@ radial_get_scanline_16 (pixman_iter_t *i
   1.278 + 			      radial->delta.x, radial->delta.y,
   1.279 + 			      radial->delta.radius);
   1.280 + 		    /*  / pixman_fixed_1 / pixman_fixed_1 */
   1.281 + 
   1.282 + 		    c = fdot (pdx, pdy, -radial->c1.radius,
   1.283 + 			      pdx, pdy, radial->c1.radius);
   1.284 + 		    /*  / pixman_fixed_1 / pixman_fixed_1 */
   1.285 + 
   1.286 +-		    *buffer = convert_8888_to_0565 (
   1.287 ++		    *buffer = dither_8888_to_0565 (
   1.288 + 			      radial_compute_color (radial->a, b, c,
   1.289 + 						    radial->inva,
   1.290 + 						    radial->delta.radius,
   1.291 + 						    radial->mindr,
   1.292 + 						    &walker,
   1.293 +-						    image->common.repeat));
   1.294 ++						    image->common.repeat),
   1.295 ++			      toggle);
   1.296 + 		}
   1.297 + 		else
   1.298 + 		{
   1.299 + 		    *buffer = 0;
   1.300 + 		}
   1.301 + 	    }
   1.302 + 
   1.303 + 	    ++buffer;
   1.304 ++	    toggle ^= 1;
   1.305 + 
   1.306 + 	    v.vector[0] += unit.vector[0];
   1.307 + 	    v.vector[1] += unit.vector[1];
   1.308 + 	    v.vector[2] += unit.vector[2];
   1.309 + 	}
   1.310 +     }
   1.311 + 
   1.312 +     iter->y++;
   1.313 +

mercurial