|
1 diff --git a/gfx/cairo/libpixman/src/pixman-dither.h b/gfx/cairo/libpixman/src/pixman-dither.h |
|
2 new 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 +} |
|
57 diff --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); |
|
204 diff --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 |