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 +