1diff --git a/gfx/cairo/libpixman/src/pixman-dither.h b/gfx/cairo/libpixman/src/pixman-dither.h 2new file mode 100644 3--- /dev/null 4+++ b/gfx/cairo/libpixman/src/pixman-dither.h 5@@ -0,0 +1,51 @@ 6+#define R16_BITS 5 7+#define G16_BITS 6 8+#define B16_BITS 5 9+ 10+#define R16_SHIFT (B16_BITS + G16_BITS) 11+#define G16_SHIFT (B16_BITS) 12+#define B16_SHIFT 0 13+ 14+#define MASK 0xff 15+#define ONE_HALF 0x80 16+ 17+#define A_SHIFT 8 * 3 18+#define R_SHIFT 8 * 2 19+#define G_SHIFT 8 20+#define A_MASK 0xff000000 21+#define R_MASK 0xff0000 22+#define G_MASK 0xff00 23+ 24+#define RB_MASK 0xff00ff 25+#define AG_MASK 0xff00ff00 26+#define RB_ONE_HALF 0x800080 27+#define RB_MASK_PLUS_ONE 0x10000100 28+ 29+#define ALPHA_8(x) ((x) >> A_SHIFT) 30+#define RED_8(x) (((x) >> R_SHIFT) & MASK) 31+#define GREEN_8(x) (((x) >> G_SHIFT) & MASK) 32+#define BLUE_8(x) ((x) & MASK) 33+ 34+// This uses the same dithering technique that Skia does. 35+// It is essentially preturbing the lower bit based on the 36+// high bit 37+static inline uint16_t dither_32_to_16(uint32_t c) 38+{ 39+ uint8_t b = BLUE_8(c); 40+ uint8_t g = GREEN_8(c); 41+ uint8_t r = RED_8(c); 42+ r = ((r << 1) - ((r >> (8 - R16_BITS) << (8 - R16_BITS)) | (r >> R16_BITS))) >> (8 - R16_BITS); 43+ g = ((g << 1) - ((g >> (8 - G16_BITS) << (8 - G16_BITS)) | (g >> G16_BITS))) >> (8 - G16_BITS); 44+ b = ((b << 1) - ((b >> (8 - B16_BITS) << (8 - B16_BITS)) | (b >> B16_BITS))) >> (8 - B16_BITS); 45+ return ((r << R16_SHIFT) | (g << G16_SHIFT) | (b << B16_SHIFT)); 46+} 47+ 48+static inline uint16_t dither_8888_to_0565(uint32_t color, pixman_bool_t toggle) 49+{ 50+ // alternate between a preturbed truncation and a regular truncation 51+ if (toggle) { 52+ return dither_32_to_16(color); 53+ } else { 54+ return CONVERT_8888_TO_0565(color); 55+ } 56+} 57diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c 58--- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c 59+++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c 60@@ -26,16 +26,18 @@ 61 */ 62 63 #ifdef HAVE_CONFIG_H 64 #include <config.h> 65 #endif 66 #include <stdlib.h> 67 #include "pixman-private.h" 68 69+#include "pixman-dither.h" 70+ 71 static pixman_bool_t 72 linear_gradient_is_horizontal (pixman_image_t *image, 73 int x, 74 int y, 75 int width, 76 int height) 77 { 78 linear_gradient_t *linear = (linear_gradient_t *)image; 79@@ -222,25 +224,28 @@ linear_get_scanline_narrow (pixman_iter_ 80 return iter->buffer; 81 } 82 83 static uint16_t convert_8888_to_0565(uint32_t color) 84 { 85 return CONVERT_8888_TO_0565(color); 86 } 87 88+ 89+ 90 static uint32_t * 91 linear_get_scanline_16 (pixman_iter_t *iter, 92 const uint32_t *mask) 93 { 94 pixman_image_t *image = iter->image; 95 int x = iter->x; 96 int y = iter->y; 97 int width = iter->width; 98 uint16_t * buffer = (uint16_t*)iter->buffer; 99+ pixman_bool_t toggle = ((x ^ y) & 1); 100 101 pixman_vector_t v, unit; 102 pixman_fixed_32_32_t l; 103 pixman_fixed_48_16_t dx, dy; 104 gradient_t *gradient = (gradient_t *)image; 105 linear_gradient_t *linear = (linear_gradient_t *)image; 106 uint16_t *end = buffer + width; 107 pixman_gradient_walker_t walker; 108@@ -294,34 +299,47 @@ linear_get_scanline_16 (pixman_iter_t * 109 t = ((dx * v.vector[0] + dy * v.vector[1]) - 110 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; 111 inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; 112 } 113 next_inc = 0; 114 115 if (((pixman_fixed_32_32_t )(inc * width)) == 0) 116 { 117- register uint16_t color; 118+ register uint32_t color; 119+ uint16_t dither_diff; 120+ uint16_t color16; 121+ uint16_t color16b; 122 123- color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t)); 124- while (buffer < end) 125- *buffer++ = color; 126+ color = _pixman_gradient_walker_pixel (&walker, t); 127+ color16 = dither_8888_to_0565(color, toggle); 128+ color16b = dither_8888_to_0565(color, toggle^1); 129+ // compute the difference 130+ dither_diff = color16 ^ color16b; 131+ while (buffer < end) { 132+ *buffer++ = color16; 133+ // use dither_diff to toggle between color16 and color16b 134+ color16 ^= dither_diff; 135+ toggle ^= 1; 136+ } 137 } 138 else 139 { 140 int i; 141 142 i = 0; 143 while (buffer < end) 144 { 145 if (!mask || *mask++) 146 { 147- *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, 148- t + next_inc)); 149+ *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, 150+ t + next_inc), 151+ toggle); 152 } 153+ toggle ^= 1; 154 i++; 155 next_inc = inc * i; 156 buffer++; 157 } 158 } 159 } 160 else 161 { 162@@ -340,18 +358,20 @@ linear_get_scanline_16 (pixman_iter_t * 163 164 invden = pixman_fixed_1 * (double) pixman_fixed_1 / 165 (l * (double) v.vector[2]); 166 v2 = v.vector[2] * (1. / pixman_fixed_1); 167 t = ((dx * v.vector[0] + dy * v.vector[1]) - 168 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; 169 } 170 171- *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t)); 172+ *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t), 173+ toggle); 174 } 175+ toggle ^= 1; 176 177 ++buffer; 178 179 v.vector[0] += unit.vector[0]; 180 v.vector[1] += unit.vector[1]; 181 v.vector[2] += unit.vector[2]; 182 } 183 } 184@@ -369,17 +389,18 @@ linear_get_scanline_wide (pixman_iter_t 185 pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); 186 187 return buffer; 188 } 189 190 void 191 _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) 192 { 193- if (linear_gradient_is_horizontal ( 194+ // XXX: we can't use this optimization when dithering 195+ if (0 && linear_gradient_is_horizontal ( 196 iter->image, iter->x, iter->y, iter->width, iter->height)) 197 { 198 if (iter->flags & ITER_16) 199 linear_get_scanline_16 (iter, NULL); 200 else if (iter->flags & ITER_NARROW) 201 linear_get_scanline_narrow (iter, NULL); 202 else 203 linear_get_scanline_wide (iter, NULL); 204diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c 205--- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c 206+++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c 207@@ -29,16 +29,18 @@ 208 209 #ifdef HAVE_CONFIG_H 210 #include <config.h> 211 #endif 212 #include <stdlib.h> 213 #include <math.h> 214 #include "pixman-private.h" 215 216+#include "pixman-dither.h" 217+ 218 static inline pixman_fixed_32_32_t 219 dot (pixman_fixed_48_16_t x1, 220 pixman_fixed_48_16_t y1, 221 pixman_fixed_48_16_t z1, 222 pixman_fixed_48_16_t x2, 223 pixman_fixed_48_16_t y2, 224 pixman_fixed_48_16_t z2) 225 { 226@@ -489,16 +491,17 @@ radial_get_scanline_16 (pixman_iter_t *i 227 * <=> for every p, the radiuses associated with the two t solutions 228 * have opposite sign 229 */ 230 pixman_image_t *image = iter->image; 231 int x = iter->x; 232 int y = iter->y; 233 int width = iter->width; 234 uint16_t *buffer = iter->buffer; 235+ pixman_bool_t toggle = ((x ^ y) & 1); 236 237 gradient_t *gradient = (gradient_t *)image; 238 radial_gradient_t *radial = (radial_gradient_t *)image; 239 uint16_t *end = buffer + width; 240 pixman_gradient_walker_t walker; 241 pixman_vector_t v, unit; 242 243 /* reference point is the center of the pixel */ 244@@ -575,25 +578,27 @@ radial_get_scanline_16 (pixman_iter_t *i 245 unit.vector[0], unit.vector[1], 0); 246 ddc = 2 * dot (unit.vector[0], unit.vector[1], 0, 247 unit.vector[0], unit.vector[1], 0); 248 249 while (buffer < end) 250 { 251 if (!mask || *mask++) 252 { 253- *buffer = convert_8888_to_0565( 254+ *buffer = dither_8888_to_0565( 255 radial_compute_color (radial->a, b, c, 256 radial->inva, 257 radial->delta.radius, 258 radial->mindr, 259 &walker, 260- image->common.repeat)); 261+ image->common.repeat), 262+ toggle); 263 } 264 265+ toggle ^= 1; 266 b += db; 267 c += dc; 268 dc += ddc; 269 ++buffer; 270 } 271 } 272 else 273 { 274@@ -621,31 +626,33 @@ radial_get_scanline_16 (pixman_iter_t *i 275 radial->delta.x, radial->delta.y, 276 radial->delta.radius); 277 /* / pixman_fixed_1 / pixman_fixed_1 */ 278 279 c = fdot (pdx, pdy, -radial->c1.radius, 280 pdx, pdy, radial->c1.radius); 281 /* / pixman_fixed_1 / pixman_fixed_1 */ 282 283- *buffer = convert_8888_to_0565 ( 284+ *buffer = dither_8888_to_0565 ( 285 radial_compute_color (radial->a, b, c, 286 radial->inva, 287 radial->delta.radius, 288 radial->mindr, 289 &walker, 290- image->common.repeat)); 291+ image->common.repeat), 292+ toggle); 293 } 294 else 295 { 296 *buffer = 0; 297 } 298 } 299 300 ++buffer; 301+ toggle ^= 1; 302 303 v.vector[0] += unit.vector[0]; 304 v.vector[1] += unit.vector[1]; 305 v.vector[2] += unit.vector[2]; 306 } 307 } 308 309 iter->y++; 310 311