|
1 diff --git a/gfx/cairo/libpixman/src/pixman-access.c b/gfx/cairo/libpixman/src/pixman-access.c |
|
2 --- a/gfx/cairo/libpixman/src/pixman-access.c |
|
3 +++ b/gfx/cairo/libpixman/src/pixman-access.c |
|
4 @@ -933,16 +933,54 @@ store_scanline_x2b10g10r10 (bits_image_t |
|
5 { |
|
6 WRITE (image, pixel++, |
|
7 ((values[i] >> 38) & 0x3ff) | |
|
8 ((values[i] >> 12) & 0xffc00) | |
|
9 ((values[i] << 14) & 0x3ff00000)); |
|
10 } |
|
11 } |
|
12 |
|
13 +static void |
|
14 +store_scanline_16 (bits_image_t * image, |
|
15 + int x, |
|
16 + int y, |
|
17 + int width, |
|
18 + const uint32_t *v) |
|
19 +{ |
|
20 + uint16_t *bits = (uint16_t*)(image->bits + image->rowstride * y); |
|
21 + uint16_t *values = (uint16_t *)v; |
|
22 + uint16_t *pixel = bits + x; |
|
23 + int i; |
|
24 + |
|
25 + for (i = 0; i < width; ++i) |
|
26 + { |
|
27 + WRITE (image, pixel++, values[i]); |
|
28 + } |
|
29 +} |
|
30 + |
|
31 +static void |
|
32 +fetch_scanline_16 (pixman_image_t *image, |
|
33 + int x, |
|
34 + int y, |
|
35 + int width, |
|
36 + uint32_t * b, |
|
37 + const uint32_t *mask) |
|
38 +{ |
|
39 + const uint16_t *bits = (uint16_t*)(image->bits.bits + y * image->bits.rowstride); |
|
40 + const uint16_t *pixel = bits + x; |
|
41 + int i; |
|
42 + uint16_t *buffer = (uint16_t *)b; |
|
43 + |
|
44 + for (i = 0; i < width; ++i) |
|
45 + { |
|
46 + *buffer++ = READ (image, pixel++); |
|
47 + } |
|
48 +} |
|
49 + |
|
50 + |
|
51 /* |
|
52 * Contracts a 64bpp image to 32bpp and then stores it using a regular 32-bit |
|
53 * store proc. Despite the type, this function expects a uint64_t buffer. |
|
54 */ |
|
55 static void |
|
56 store_scanline_generic_64 (bits_image_t * image, |
|
57 int x, |
|
58 int y, |
|
59 @@ -1044,32 +1082,47 @@ fetch_pixel_generic_lossy_32 (bits_image |
|
60 pixman_contract (&result, &pixel64, 1); |
|
61 |
|
62 return result; |
|
63 } |
|
64 |
|
65 typedef struct |
|
66 { |
|
67 pixman_format_code_t format; |
|
68 + fetch_scanline_t fetch_scanline_16; |
|
69 fetch_scanline_t fetch_scanline_32; |
|
70 fetch_scanline_t fetch_scanline_64; |
|
71 fetch_pixel_32_t fetch_pixel_32; |
|
72 fetch_pixel_64_t fetch_pixel_64; |
|
73 + store_scanline_t store_scanline_16; |
|
74 store_scanline_t store_scanline_32; |
|
75 store_scanline_t store_scanline_64; |
|
76 } format_info_t; |
|
77 |
|
78 #define FORMAT_INFO(format) \ |
|
79 { \ |
|
80 PIXMAN_ ## format, \ |
|
81 + NULL, \ |
|
82 fetch_scanline_ ## format, \ |
|
83 fetch_scanline_generic_64, \ |
|
84 fetch_pixel_ ## format, fetch_pixel_generic_64, \ |
|
85 + NULL, \ |
|
86 store_scanline_ ## format, store_scanline_generic_64 \ |
|
87 } |
|
88 +#define FORMAT_INFO16(format) \ |
|
89 + { \ |
|
90 + PIXMAN_ ## format, \ |
|
91 + fetch_scanline_16, \ |
|
92 + fetch_scanline_ ## format, \ |
|
93 + fetch_scanline_generic_64, \ |
|
94 + fetch_pixel_ ## format, fetch_pixel_generic_64, \ |
|
95 + store_scanline_16, \ |
|
96 + store_scanline_ ## format, store_scanline_generic_64 \ |
|
97 + } |
|
98 + |
|
99 |
|
100 static const format_info_t accessors[] = |
|
101 { |
|
102 /* 32 bpp formats */ |
|
103 FORMAT_INFO (a8r8g8b8), |
|
104 FORMAT_INFO (x8r8g8b8), |
|
105 FORMAT_INFO (a8b8g8r8), |
|
106 FORMAT_INFO (x8b8g8r8), |
|
107 @@ -1079,18 +1132,18 @@ static const format_info_t accessors[] = |
|
108 FORMAT_INFO (r8g8b8x8), |
|
109 FORMAT_INFO (x14r6g6b6), |
|
110 |
|
111 /* 24bpp formats */ |
|
112 FORMAT_INFO (r8g8b8), |
|
113 FORMAT_INFO (b8g8r8), |
|
114 |
|
115 /* 16bpp formats */ |
|
116 - FORMAT_INFO (r5g6b5), |
|
117 - FORMAT_INFO (b5g6r5), |
|
118 + FORMAT_INFO16 (r5g6b5), |
|
119 + FORMAT_INFO16 (b5g6r5), |
|
120 |
|
121 FORMAT_INFO (a1r5g5b5), |
|
122 FORMAT_INFO (x1r5g5b5), |
|
123 FORMAT_INFO (a1b5g5r5), |
|
124 FORMAT_INFO (x1b5g5r5), |
|
125 FORMAT_INFO (a4r4g4b4), |
|
126 FORMAT_INFO (x4r4g4b4), |
|
127 FORMAT_INFO (a4b4g4r4), |
|
128 @@ -1132,62 +1185,64 @@ static const format_info_t accessors[] = |
|
129 |
|
130 /* 1bpp formats */ |
|
131 FORMAT_INFO (a1), |
|
132 FORMAT_INFO (g1), |
|
133 |
|
134 /* Wide formats */ |
|
135 |
|
136 { PIXMAN_a2r10g10b10, |
|
137 - NULL, fetch_scanline_a2r10g10b10, |
|
138 + NULL, NULL, fetch_scanline_a2r10g10b10, |
|
139 fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10, |
|
140 NULL, store_scanline_a2r10g10b10 }, |
|
141 |
|
142 { PIXMAN_x2r10g10b10, |
|
143 - NULL, fetch_scanline_x2r10g10b10, |
|
144 + NULL, NULL, fetch_scanline_x2r10g10b10, |
|
145 fetch_pixel_generic_lossy_32, fetch_pixel_x2r10g10b10, |
|
146 NULL, store_scanline_x2r10g10b10 }, |
|
147 |
|
148 { PIXMAN_a2b10g10r10, |
|
149 - NULL, fetch_scanline_a2b10g10r10, |
|
150 + NULL, NULL, fetch_scanline_a2b10g10r10, |
|
151 fetch_pixel_generic_lossy_32, fetch_pixel_a2b10g10r10, |
|
152 NULL, store_scanline_a2b10g10r10 }, |
|
153 |
|
154 { PIXMAN_x2b10g10r10, |
|
155 - NULL, fetch_scanline_x2b10g10r10, |
|
156 + NULL, NULL, fetch_scanline_x2b10g10r10, |
|
157 fetch_pixel_generic_lossy_32, fetch_pixel_x2b10g10r10, |
|
158 NULL, store_scanline_x2b10g10r10 }, |
|
159 |
|
160 /* YUV formats */ |
|
161 { PIXMAN_yuy2, |
|
162 - fetch_scanline_yuy2, fetch_scanline_generic_64, |
|
163 + NULL, fetch_scanline_yuy2, fetch_scanline_generic_64, |
|
164 fetch_pixel_yuy2, fetch_pixel_generic_64, |
|
165 NULL, NULL }, |
|
166 |
|
167 { PIXMAN_yv12, |
|
168 - fetch_scanline_yv12, fetch_scanline_generic_64, |
|
169 + NULL, fetch_scanline_yv12, fetch_scanline_generic_64, |
|
170 fetch_pixel_yv12, fetch_pixel_generic_64, |
|
171 NULL, NULL }, |
|
172 |
|
173 { PIXMAN_null }, |
|
174 }; |
|
175 |
|
176 static void |
|
177 setup_accessors (bits_image_t *image) |
|
178 { |
|
179 const format_info_t *info = accessors; |
|
180 |
|
181 while (info->format != PIXMAN_null) |
|
182 { |
|
183 if (info->format == image->format) |
|
184 { |
|
185 + image->fetch_scanline_16 = info->fetch_scanline_16; |
|
186 image->fetch_scanline_32 = info->fetch_scanline_32; |
|
187 image->fetch_scanline_64 = info->fetch_scanline_64; |
|
188 image->fetch_pixel_32 = info->fetch_pixel_32; |
|
189 image->fetch_pixel_64 = info->fetch_pixel_64; |
|
190 + image->store_scanline_16 = info->store_scanline_16; |
|
191 image->store_scanline_32 = info->store_scanline_32; |
|
192 image->store_scanline_64 = info->store_scanline_64; |
|
193 |
|
194 return; |
|
195 } |
|
196 |
|
197 info++; |
|
198 } |
|
199 diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c |
|
200 --- a/gfx/cairo/libpixman/src/pixman-bits-image.c |
|
201 +++ b/gfx/cairo/libpixman/src/pixman-bits-image.c |
|
202 @@ -1247,16 +1247,31 @@ src_get_scanline_wide (pixman_iter_t *it |
|
203 |
|
204 void |
|
205 _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
|
206 { |
|
207 if (iter->flags & ITER_NARROW) |
|
208 iter->get_scanline = src_get_scanline_narrow; |
|
209 else |
|
210 iter->get_scanline = src_get_scanline_wide; |
|
211 + |
|
212 +} |
|
213 + |
|
214 +static uint32_t * |
|
215 +dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) |
|
216 +{ |
|
217 + pixman_image_t *image = iter->image; |
|
218 + int x = iter->x; |
|
219 + int y = iter->y; |
|
220 + int width = iter->width; |
|
221 + uint32_t * buffer = iter->buffer; |
|
222 + |
|
223 + image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask); |
|
224 + |
|
225 + return iter->buffer; |
|
226 } |
|
227 |
|
228 static uint32_t * |
|
229 dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) |
|
230 { |
|
231 pixman_image_t *image = iter->image; |
|
232 int x = iter->x; |
|
233 int y = iter->y; |
|
234 @@ -1327,16 +1342,30 @@ dest_get_scanline_wide (pixman_iter_t *i |
|
235 free (alpha); |
|
236 } |
|
237 } |
|
238 |
|
239 return iter->buffer; |
|
240 } |
|
241 |
|
242 static void |
|
243 +dest_write_back_16 (pixman_iter_t *iter) |
|
244 +{ |
|
245 + bits_image_t * image = &iter->image->bits; |
|
246 + int x = iter->x; |
|
247 + int y = iter->y; |
|
248 + int width = iter->width; |
|
249 + const uint32_t *buffer = iter->buffer; |
|
250 + |
|
251 + image->store_scanline_16 (image, x, y, width, buffer); |
|
252 + |
|
253 + iter->y++; |
|
254 +} |
|
255 + |
|
256 +static void |
|
257 dest_write_back_narrow (pixman_iter_t *iter) |
|
258 { |
|
259 bits_image_t * image = &iter->image->bits; |
|
260 int x = iter->x; |
|
261 int y = iter->y; |
|
262 int width = iter->width; |
|
263 const uint32_t *buffer = iter->buffer; |
|
264 |
|
265 @@ -1375,28 +1404,41 @@ dest_write_back_wide (pixman_iter_t *ite |
|
266 } |
|
267 |
|
268 iter->y++; |
|
269 } |
|
270 |
|
271 void |
|
272 _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
|
273 { |
|
274 - if (iter->flags & ITER_NARROW) |
|
275 + if (iter->flags & ITER_16) |
|
276 + { |
|
277 + if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == |
|
278 + (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) |
|
279 + { |
|
280 + iter->get_scanline = _pixman_iter_get_scanline_noop; |
|
281 + } |
|
282 + else |
|
283 + { |
|
284 + iter->get_scanline = dest_get_scanline_16; |
|
285 + } |
|
286 + iter->write_back = dest_write_back_16; |
|
287 + } |
|
288 + else if (iter->flags & ITER_NARROW) |
|
289 { |
|
290 if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == |
|
291 (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) |
|
292 { |
|
293 iter->get_scanline = _pixman_iter_get_scanline_noop; |
|
294 } |
|
295 else |
|
296 { |
|
297 iter->get_scanline = dest_get_scanline_narrow; |
|
298 } |
|
299 - |
|
300 + |
|
301 iter->write_back = dest_write_back_narrow; |
|
302 } |
|
303 else |
|
304 { |
|
305 iter->get_scanline = dest_get_scanline_wide; |
|
306 iter->write_back = dest_write_back_wide; |
|
307 } |
|
308 } |
|
309 diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c |
|
310 new file mode 100644 |
|
311 --- /dev/null |
|
312 +++ b/gfx/cairo/libpixman/src/pixman-combine16.c |
|
313 @@ -0,0 +1,124 @@ |
|
314 +#ifdef HAVE_CONFIG_H |
|
315 +#include <config.h> |
|
316 +#endif |
|
317 + |
|
318 +#include <math.h> |
|
319 +#include <string.h> |
|
320 + |
|
321 +#include "pixman-private.h" |
|
322 + |
|
323 +#include "pixman-combine32.h" |
|
324 + |
|
325 +static force_inline uint32_t |
|
326 +combine_mask (const uint32_t src, const uint32_t mask) |
|
327 +{ |
|
328 + uint32_t s, m; |
|
329 + |
|
330 + m = mask >> A_SHIFT; |
|
331 + |
|
332 + if (!m) |
|
333 + return 0; |
|
334 + s = src; |
|
335 + |
|
336 + UN8x4_MUL_UN8 (s, m); |
|
337 + |
|
338 + return s; |
|
339 +} |
|
340 + |
|
341 +static inline uint32_t convert_0565_to_8888(uint16_t color) |
|
342 +{ |
|
343 + return CONVERT_0565_TO_8888(color); |
|
344 +} |
|
345 + |
|
346 +static inline uint16_t convert_8888_to_0565(uint32_t color) |
|
347 +{ |
|
348 + return CONVERT_8888_TO_0565(color); |
|
349 +} |
|
350 + |
|
351 +static void |
|
352 +combine_src_u (pixman_implementation_t *imp, |
|
353 + pixman_op_t op, |
|
354 + uint32_t * dest, |
|
355 + const uint32_t * src, |
|
356 + const uint32_t * mask, |
|
357 + int width) |
|
358 +{ |
|
359 + int i; |
|
360 + |
|
361 + if (!mask) |
|
362 + memcpy (dest, src, width * sizeof (uint16_t)); |
|
363 + else |
|
364 + { |
|
365 + uint16_t *d = (uint16_t*)dest; |
|
366 + uint16_t *src16 = (uint16_t*)src; |
|
367 + for (i = 0; i < width; ++i) |
|
368 + { |
|
369 + if ((*mask & 0xff000000) == 0xff000000) { |
|
370 + // it's likely worth special casing |
|
371 + // fully opaque because it avoids |
|
372 + // the cost of conversion as well the multiplication |
|
373 + *(d + i) = *src16; |
|
374 + } else { |
|
375 + // the mask is still 32bits |
|
376 + uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask); |
|
377 + *(d + i) = convert_8888_to_0565(s); |
|
378 + } |
|
379 + mask++; |
|
380 + src16++; |
|
381 + } |
|
382 + } |
|
383 + |
|
384 +} |
|
385 + |
|
386 +static void |
|
387 +combine_over_u (pixman_implementation_t *imp, |
|
388 + pixman_op_t op, |
|
389 + uint32_t * dest, |
|
390 + const uint32_t * src, |
|
391 + const uint32_t * mask, |
|
392 + int width) |
|
393 +{ |
|
394 + int i; |
|
395 + |
|
396 + if (!mask) |
|
397 + memcpy (dest, src, width * sizeof (uint16_t)); |
|
398 + else |
|
399 + { |
|
400 + uint16_t *d = (uint16_t*)dest; |
|
401 + uint16_t *src16 = (uint16_t*)src; |
|
402 + for (i = 0; i < width; ++i) |
|
403 + { |
|
404 + if ((*mask & 0xff000000) == 0xff000000) { |
|
405 + // it's likely worth special casing |
|
406 + // fully opaque because it avoids |
|
407 + // the cost of conversion as well the multiplication |
|
408 + *(d + i) = *src16; |
|
409 + } else if ((*mask & 0xff000000) == 0x00000000) { |
|
410 + // keep the dest the same |
|
411 + } else { |
|
412 + // the mask is still 32bits |
|
413 + uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask); |
|
414 + uint32_t ia = ALPHA_8 (~s); |
|
415 + uint32_t d32 = convert_0565_to_8888(*(d + i)); |
|
416 + UN8x4_MUL_UN8_ADD_UN8x4 (d32, ia, s); |
|
417 + *(d + i) = convert_8888_to_0565(d32); |
|
418 + } |
|
419 + mask++; |
|
420 + src16++; |
|
421 + } |
|
422 + } |
|
423 + |
|
424 +} |
|
425 + |
|
426 + |
|
427 +void |
|
428 +_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp) |
|
429 +{ |
|
430 + int i; |
|
431 + for (i = 0; i < PIXMAN_N_OPERATORS; i++) { |
|
432 + imp->combine_16[i] = NULL; |
|
433 + } |
|
434 + imp->combine_16[PIXMAN_OP_SRC] = combine_src_u; |
|
435 + imp->combine_16[PIXMAN_OP_OVER] = combine_over_u; |
|
436 +} |
|
437 + |
|
438 diff --git a/gfx/cairo/libpixman/src/pixman-general.c b/gfx/cairo/libpixman/src/pixman-general.c |
|
439 --- a/gfx/cairo/libpixman/src/pixman-general.c |
|
440 +++ b/gfx/cairo/libpixman/src/pixman-general.c |
|
441 @@ -106,46 +106,61 @@ general_composite_rect (pixman_implemen |
|
442 PIXMAN_COMPOSITE_ARGS (info); |
|
443 uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8]; |
|
444 uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; |
|
445 uint8_t *src_buffer, *mask_buffer, *dest_buffer; |
|
446 pixman_iter_t src_iter, mask_iter, dest_iter; |
|
447 pixman_combine_32_func_t compose; |
|
448 pixman_bool_t component_alpha; |
|
449 iter_flags_t narrow, src_flags; |
|
450 + iter_flags_t rgb16; |
|
451 int Bpp; |
|
452 int i; |
|
453 |
|
454 if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && |
|
455 (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && |
|
456 (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)) |
|
457 { |
|
458 narrow = ITER_NARROW; |
|
459 Bpp = 4; |
|
460 } |
|
461 else |
|
462 { |
|
463 narrow = 0; |
|
464 Bpp = 8; |
|
465 } |
|
466 |
|
467 + // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps |
|
468 + // by having it deal more specifically with different intermediate formats |
|
469 + if ( |
|
470 + (dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) && |
|
471 + ( op == PIXMAN_OP_SRC || |
|
472 + (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE)) |
|
473 + ) |
|
474 + ) { |
|
475 + rgb16 = ITER_16; |
|
476 + } else { |
|
477 + rgb16 = 0; |
|
478 + } |
|
479 + |
|
480 + |
|
481 if (width * Bpp > SCANLINE_BUFFER_LENGTH) |
|
482 { |
|
483 scanline_buffer = pixman_malloc_abc (width, 3, Bpp); |
|
484 |
|
485 if (!scanline_buffer) |
|
486 return; |
|
487 } |
|
488 |
|
489 src_buffer = scanline_buffer; |
|
490 mask_buffer = src_buffer + width * Bpp; |
|
491 dest_buffer = mask_buffer + width * Bpp; |
|
492 |
|
493 /* src iter */ |
|
494 - src_flags = narrow | op_flags[op].src; |
|
495 + src_flags = narrow | op_flags[op].src | rgb16; |
|
496 |
|
497 _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image, |
|
498 src_x, src_y, width, height, |
|
499 src_buffer, src_flags); |
|
500 |
|
501 /* mask iter */ |
|
502 if ((src_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == |
|
503 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) |
|
504 @@ -164,20 +179,20 @@ general_composite_rect (pixman_implemen |
|
505 |
|
506 _pixman_implementation_src_iter_init ( |
|
507 imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height, |
|
508 mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB)); |
|
509 |
|
510 /* dest iter */ |
|
511 _pixman_implementation_dest_iter_init ( |
|
512 imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, |
|
513 - dest_buffer, narrow | op_flags[op].dst); |
|
514 + dest_buffer, narrow | op_flags[op].dst | rgb16); |
|
515 |
|
516 compose = _pixman_implementation_lookup_combiner ( |
|
517 - imp->toplevel, op, component_alpha, narrow); |
|
518 + imp->toplevel, op, component_alpha, narrow, !!rgb16); |
|
519 |
|
520 if (!compose) |
|
521 return; |
|
522 |
|
523 for (i = 0; i < height; ++i) |
|
524 { |
|
525 uint32_t *s, *m, *d; |
|
526 |
|
527 @@ -234,16 +249,17 @@ general_fill (pixman_implementation_t *i |
|
528 return FALSE; |
|
529 } |
|
530 |
|
531 pixman_implementation_t * |
|
532 _pixman_implementation_create_general (void) |
|
533 { |
|
534 pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); |
|
535 |
|
536 + _pixman_setup_combiner_functions_16 (imp); |
|
537 _pixman_setup_combiner_functions_32 (imp); |
|
538 _pixman_setup_combiner_functions_64 (imp); |
|
539 |
|
540 imp->blt = general_blt; |
|
541 imp->fill = general_fill; |
|
542 imp->src_iter_init = general_src_iter_init; |
|
543 imp->dest_iter_init = general_dest_iter_init; |
|
544 |
|
545 diff --git a/gfx/cairo/libpixman/src/pixman-image.c b/gfx/cairo/libpixman/src/pixman-image.c |
|
546 --- a/gfx/cairo/libpixman/src/pixman-image.c |
|
547 +++ b/gfx/cairo/libpixman/src/pixman-image.c |
|
548 @@ -451,16 +451,20 @@ compute_image_info (pixman_image_t *imag |
|
549 flags |= FAST_PATH_IS_OPAQUE; |
|
550 } |
|
551 |
|
552 if (image->bits.read_func || image->bits.write_func) |
|
553 flags &= ~FAST_PATH_NO_ACCESSORS; |
|
554 |
|
555 if (PIXMAN_FORMAT_IS_WIDE (image->bits.format)) |
|
556 flags &= ~FAST_PATH_NARROW_FORMAT; |
|
557 + |
|
558 + if (image->bits.format == PIXMAN_r5g6b5) |
|
559 + flags |= FAST_PATH_16_FORMAT; |
|
560 + |
|
561 break; |
|
562 |
|
563 case RADIAL: |
|
564 code = PIXMAN_unknown; |
|
565 |
|
566 /* |
|
567 * As explained in pixman-radial-gradient.c, every point of |
|
568 * the plane has a valid associated radius (and thus will be |
|
569 diff --git a/gfx/cairo/libpixman/src/pixman-implementation.c b/gfx/cairo/libpixman/src/pixman-implementation.c |
|
570 --- a/gfx/cairo/libpixman/src/pixman-implementation.c |
|
571 +++ b/gfx/cairo/libpixman/src/pixman-implementation.c |
|
572 @@ -101,45 +101,51 @@ pixman_implementation_t * |
|
573 imp->fill = delegate_fill; |
|
574 imp->src_iter_init = delegate_src_iter_init; |
|
575 imp->dest_iter_init = delegate_dest_iter_init; |
|
576 |
|
577 imp->fast_paths = fast_paths; |
|
578 |
|
579 for (i = 0; i < PIXMAN_N_OPERATORS; ++i) |
|
580 { |
|
581 + imp->combine_16[i] = NULL; |
|
582 imp->combine_32[i] = NULL; |
|
583 imp->combine_64[i] = NULL; |
|
584 imp->combine_32_ca[i] = NULL; |
|
585 imp->combine_64_ca[i] = NULL; |
|
586 } |
|
587 |
|
588 return imp; |
|
589 } |
|
590 |
|
591 pixman_combine_32_func_t |
|
592 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, |
|
593 pixman_op_t op, |
|
594 pixman_bool_t component_alpha, |
|
595 - pixman_bool_t narrow) |
|
596 + pixman_bool_t narrow, |
|
597 + pixman_bool_t rgb16) |
|
598 { |
|
599 pixman_combine_32_func_t f; |
|
600 |
|
601 do |
|
602 { |
|
603 pixman_combine_32_func_t (*combiners[]) = |
|
604 { |
|
605 (pixman_combine_32_func_t *)imp->combine_64, |
|
606 (pixman_combine_32_func_t *)imp->combine_64_ca, |
|
607 imp->combine_32, |
|
608 imp->combine_32_ca, |
|
609 + (pixman_combine_32_func_t *)imp->combine_16, |
|
610 + NULL, |
|
611 }; |
|
612 - |
|
613 - f = combiners[component_alpha | (narrow << 1)][op]; |
|
614 - |
|
615 + if (rgb16) { |
|
616 + f = combiners[4][op]; |
|
617 + } else { |
|
618 + f = combiners[component_alpha + (narrow << 1)][op]; |
|
619 + } |
|
620 imp = imp->delegate; |
|
621 } |
|
622 while (!f); |
|
623 |
|
624 return f; |
|
625 } |
|
626 |
|
627 pixman_bool_t |
|
628 diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c |
|
629 --- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c |
|
630 +++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c |
|
631 @@ -217,42 +217,185 @@ linear_get_scanline_narrow (pixman_iter_ |
|
632 } |
|
633 } |
|
634 |
|
635 iter->y++; |
|
636 |
|
637 return iter->buffer; |
|
638 } |
|
639 |
|
640 +static uint16_t convert_8888_to_0565(uint32_t color) |
|
641 +{ |
|
642 + return CONVERT_8888_TO_0565(color); |
|
643 +} |
|
644 + |
|
645 +static uint32_t * |
|
646 +linear_get_scanline_16 (pixman_iter_t *iter, |
|
647 + const uint32_t *mask) |
|
648 +{ |
|
649 + pixman_image_t *image = iter->image; |
|
650 + int x = iter->x; |
|
651 + int y = iter->y; |
|
652 + int width = iter->width; |
|
653 + uint16_t * buffer = (uint16_t*)iter->buffer; |
|
654 + |
|
655 + pixman_vector_t v, unit; |
|
656 + pixman_fixed_32_32_t l; |
|
657 + pixman_fixed_48_16_t dx, dy; |
|
658 + gradient_t *gradient = (gradient_t *)image; |
|
659 + linear_gradient_t *linear = (linear_gradient_t *)image; |
|
660 + uint16_t *end = buffer + width; |
|
661 + pixman_gradient_walker_t walker; |
|
662 + |
|
663 + _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); |
|
664 + |
|
665 + /* reference point is the center of the pixel */ |
|
666 + v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
|
667 + v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
|
668 + v.vector[2] = pixman_fixed_1; |
|
669 + |
|
670 + if (image->common.transform) |
|
671 + { |
|
672 + if (!pixman_transform_point_3d (image->common.transform, &v)) |
|
673 + return iter->buffer; |
|
674 + |
|
675 + unit.vector[0] = image->common.transform->matrix[0][0]; |
|
676 + unit.vector[1] = image->common.transform->matrix[1][0]; |
|
677 + unit.vector[2] = image->common.transform->matrix[2][0]; |
|
678 + } |
|
679 + else |
|
680 + { |
|
681 + unit.vector[0] = pixman_fixed_1; |
|
682 + unit.vector[1] = 0; |
|
683 + unit.vector[2] = 0; |
|
684 + } |
|
685 + |
|
686 + dx = linear->p2.x - linear->p1.x; |
|
687 + dy = linear->p2.y - linear->p1.y; |
|
688 + |
|
689 + l = dx * dx + dy * dy; |
|
690 + |
|
691 + if (l == 0 || unit.vector[2] == 0) |
|
692 + { |
|
693 + /* affine transformation only */ |
|
694 + pixman_fixed_32_32_t t, next_inc; |
|
695 + double inc; |
|
696 + |
|
697 + if (l == 0 || v.vector[2] == 0) |
|
698 + { |
|
699 + t = 0; |
|
700 + inc = 0; |
|
701 + } |
|
702 + else |
|
703 + { |
|
704 + double invden, v2; |
|
705 + |
|
706 + invden = pixman_fixed_1 * (double) pixman_fixed_1 / |
|
707 + (l * (double) v.vector[2]); |
|
708 + v2 = v.vector[2] * (1. / pixman_fixed_1); |
|
709 + t = ((dx * v.vector[0] + dy * v.vector[1]) - |
|
710 + (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; |
|
711 + inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; |
|
712 + } |
|
713 + next_inc = 0; |
|
714 + |
|
715 + if (((pixman_fixed_32_32_t )(inc * width)) == 0) |
|
716 + { |
|
717 + register uint16_t color; |
|
718 + |
|
719 + color = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t)); |
|
720 + while (buffer < end) |
|
721 + *buffer++ = color; |
|
722 + } |
|
723 + else |
|
724 + { |
|
725 + int i; |
|
726 + |
|
727 + i = 0; |
|
728 + while (buffer < end) |
|
729 + { |
|
730 + if (!mask || *mask++) |
|
731 + { |
|
732 + *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, |
|
733 + t + next_inc)); |
|
734 + } |
|
735 + i++; |
|
736 + next_inc = inc * i; |
|
737 + buffer++; |
|
738 + } |
|
739 + } |
|
740 + } |
|
741 + else |
|
742 + { |
|
743 + /* projective transformation */ |
|
744 + double t; |
|
745 + |
|
746 + t = 0; |
|
747 + |
|
748 + while (buffer < end) |
|
749 + { |
|
750 + if (!mask || *mask++) |
|
751 + { |
|
752 + if (v.vector[2] != 0) |
|
753 + { |
|
754 + double invden, v2; |
|
755 + |
|
756 + invden = pixman_fixed_1 * (double) pixman_fixed_1 / |
|
757 + (l * (double) v.vector[2]); |
|
758 + v2 = v.vector[2] * (1. / pixman_fixed_1); |
|
759 + t = ((dx * v.vector[0] + dy * v.vector[1]) - |
|
760 + (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; |
|
761 + } |
|
762 + |
|
763 + *buffer = convert_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t)); |
|
764 + } |
|
765 + |
|
766 + ++buffer; |
|
767 + |
|
768 + v.vector[0] += unit.vector[0]; |
|
769 + v.vector[1] += unit.vector[1]; |
|
770 + v.vector[2] += unit.vector[2]; |
|
771 + } |
|
772 + } |
|
773 + |
|
774 + iter->y++; |
|
775 + |
|
776 + return iter->buffer; |
|
777 +} |
|
778 + |
|
779 static uint32_t * |
|
780 linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
|
781 { |
|
782 uint32_t *buffer = linear_get_scanline_narrow (iter, NULL); |
|
783 |
|
784 pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); |
|
785 |
|
786 return buffer; |
|
787 } |
|
788 |
|
789 void |
|
790 _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
|
791 { |
|
792 if (linear_gradient_is_horizontal ( |
|
793 iter->image, iter->x, iter->y, iter->width, iter->height)) |
|
794 { |
|
795 - if (iter->flags & ITER_NARROW) |
|
796 + if (iter->flags & ITER_16) |
|
797 + linear_get_scanline_16 (iter, NULL); |
|
798 + else if (iter->flags & ITER_NARROW) |
|
799 linear_get_scanline_narrow (iter, NULL); |
|
800 else |
|
801 linear_get_scanline_wide (iter, NULL); |
|
802 |
|
803 iter->get_scanline = _pixman_iter_get_scanline_noop; |
|
804 } |
|
805 else |
|
806 { |
|
807 - if (iter->flags & ITER_NARROW) |
|
808 + if (iter->flags & ITER_16) |
|
809 + iter->get_scanline = linear_get_scanline_16; |
|
810 + else if (iter->flags & ITER_NARROW) |
|
811 iter->get_scanline = linear_get_scanline_narrow; |
|
812 else |
|
813 iter->get_scanline = linear_get_scanline_wide; |
|
814 } |
|
815 } |
|
816 |
|
817 PIXMAN_EXPORT pixman_image_t * |
|
818 pixman_image_create_linear_gradient (pixman_point_fixed_t * p1, |
|
819 diff --git a/gfx/cairo/libpixman/src/pixman-private.h b/gfx/cairo/libpixman/src/pixman-private.h |
|
820 --- a/gfx/cairo/libpixman/src/pixman-private.h |
|
821 +++ b/gfx/cairo/libpixman/src/pixman-private.h |
|
822 @@ -152,24 +152,28 @@ struct bits_image |
|
823 int height; |
|
824 uint32_t * bits; |
|
825 uint32_t * free_me; |
|
826 int rowstride; /* in number of uint32_t's */ |
|
827 |
|
828 fetch_scanline_t get_scanline_32; |
|
829 fetch_scanline_t get_scanline_64; |
|
830 |
|
831 + fetch_scanline_t fetch_scanline_16; |
|
832 + |
|
833 fetch_scanline_t fetch_scanline_32; |
|
834 fetch_pixel_32_t fetch_pixel_32; |
|
835 store_scanline_t store_scanline_32; |
|
836 |
|
837 fetch_scanline_t fetch_scanline_64; |
|
838 fetch_pixel_64_t fetch_pixel_64; |
|
839 store_scanline_t store_scanline_64; |
|
840 |
|
841 + store_scanline_t store_scanline_16; |
|
842 + |
|
843 /* Used for indirect access to the bits */ |
|
844 pixman_read_memory_func_t read_func; |
|
845 pixman_write_memory_func_t write_func; |
|
846 }; |
|
847 |
|
848 union pixman_image |
|
849 { |
|
850 image_type_t type; |
|
851 @@ -202,17 +206,24 @@ typedef enum |
|
852 * destination. |
|
853 * |
|
854 * When he destination is xRGB, this is useful knowledge, because then |
|
855 * we can treat it as if it were ARGB, which means in some cases we can |
|
856 * avoid copying it to a temporary buffer. |
|
857 */ |
|
858 ITER_LOCALIZED_ALPHA = (1 << 1), |
|
859 ITER_IGNORE_ALPHA = (1 << 2), |
|
860 - ITER_IGNORE_RGB = (1 << 3) |
|
861 + ITER_IGNORE_RGB = (1 << 3), |
|
862 + |
|
863 + /* With the addition of ITER_16 we now have two flags that to represent |
|
864 + * 3 pipelines. This means that there can be an invalid state when |
|
865 + * both ITER_NARROW and ITER_16 are set. In this case |
|
866 + * ITER_16 overrides NARROW and we should use the 16 bit pipeline. |
|
867 + * Note: ITER_16 still has a 32 bit mask, which is a bit weird. */ |
|
868 + ITER_16 = (1 << 4) |
|
869 } iter_flags_t; |
|
870 |
|
871 struct pixman_iter_t |
|
872 { |
|
873 /* These are initialized by _pixman_implementation_{src,dest}_init */ |
|
874 pixman_image_t * image; |
|
875 uint32_t * buffer; |
|
876 int x, y; |
|
877 @@ -429,16 +440,17 @@ typedef pixman_bool_t (*pixman_fill_func |
|
878 int x, |
|
879 int y, |
|
880 int width, |
|
881 int height, |
|
882 uint32_t xor); |
|
883 typedef void (*pixman_iter_init_func_t) (pixman_implementation_t *imp, |
|
884 pixman_iter_t *iter); |
|
885 |
|
886 +void _pixman_setup_combiner_functions_16 (pixman_implementation_t *imp); |
|
887 void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp); |
|
888 void _pixman_setup_combiner_functions_64 (pixman_implementation_t *imp); |
|
889 |
|
890 typedef struct |
|
891 { |
|
892 pixman_op_t op; |
|
893 pixman_format_code_t src_format; |
|
894 uint32_t src_flags; |
|
895 @@ -459,32 +471,34 @@ struct pixman_implementation_t |
|
896 pixman_fill_func_t fill; |
|
897 pixman_iter_init_func_t src_iter_init; |
|
898 pixman_iter_init_func_t dest_iter_init; |
|
899 |
|
900 pixman_combine_32_func_t combine_32[PIXMAN_N_OPERATORS]; |
|
901 pixman_combine_32_func_t combine_32_ca[PIXMAN_N_OPERATORS]; |
|
902 pixman_combine_64_func_t combine_64[PIXMAN_N_OPERATORS]; |
|
903 pixman_combine_64_func_t combine_64_ca[PIXMAN_N_OPERATORS]; |
|
904 + pixman_combine_64_func_t combine_16[PIXMAN_N_OPERATORS]; |
|
905 }; |
|
906 |
|
907 uint32_t |
|
908 _pixman_image_get_solid (pixman_implementation_t *imp, |
|
909 pixman_image_t * image, |
|
910 pixman_format_code_t format); |
|
911 |
|
912 pixman_implementation_t * |
|
913 _pixman_implementation_create (pixman_implementation_t *delegate, |
|
914 const pixman_fast_path_t *fast_paths); |
|
915 |
|
916 pixman_combine_32_func_t |
|
917 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, |
|
918 pixman_op_t op, |
|
919 pixman_bool_t component_alpha, |
|
920 - pixman_bool_t wide); |
|
921 + pixman_bool_t wide, |
|
922 + pixman_bool_t rgb16); |
|
923 |
|
924 pixman_bool_t |
|
925 _pixman_implementation_blt (pixman_implementation_t *imp, |
|
926 uint32_t * src_bits, |
|
927 uint32_t * dst_bits, |
|
928 int src_stride, |
|
929 int dst_stride, |
|
930 int src_bpp, |
|
931 @@ -613,16 +627,17 @@ uint32_t * |
|
932 #define FAST_PATH_Y_UNIT_ZERO (1 << 18) |
|
933 #define FAST_PATH_BILINEAR_FILTER (1 << 19) |
|
934 #define FAST_PATH_ROTATE_90_TRANSFORM (1 << 20) |
|
935 #define FAST_PATH_ROTATE_180_TRANSFORM (1 << 21) |
|
936 #define FAST_PATH_ROTATE_270_TRANSFORM (1 << 22) |
|
937 #define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST (1 << 23) |
|
938 #define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR (1 << 24) |
|
939 #define FAST_PATH_BITS_IMAGE (1 << 25) |
|
940 +#define FAST_PATH_16_FORMAT (1 << 26) |
|
941 |
|
942 #define FAST_PATH_PAD_REPEAT \ |
|
943 (FAST_PATH_NO_NONE_REPEAT | \ |
|
944 FAST_PATH_NO_NORMAL_REPEAT | \ |
|
945 FAST_PATH_NO_REFLECT_REPEAT) |
|
946 |
|
947 #define FAST_PATH_NORMAL_REPEAT \ |
|
948 (FAST_PATH_NO_NONE_REPEAT | \ |
|
949 diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c |
|
950 --- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c |
|
951 +++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c |
|
952 @@ -395,35 +395,289 @@ radial_get_scanline_narrow (pixman_iter_ |
|
953 v.vector[2] += unit.vector[2]; |
|
954 } |
|
955 } |
|
956 |
|
957 iter->y++; |
|
958 return iter->buffer; |
|
959 } |
|
960 |
|
961 +static uint16_t convert_8888_to_0565(uint32_t color) |
|
962 +{ |
|
963 + return CONVERT_8888_TO_0565(color); |
|
964 +} |
|
965 + |
|
966 +static uint32_t * |
|
967 +radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) |
|
968 +{ |
|
969 + /* |
|
970 + * Implementation of radial gradients following the PDF specification. |
|
971 + * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference |
|
972 + * Manual (PDF 32000-1:2008 at the time of this writing). |
|
973 + * |
|
974 + * In the radial gradient problem we are given two circles (c₁,r₁) and |
|
975 + * (c₂,r₂) that define the gradient itself. |
|
976 + * |
|
977 + * Mathematically the gradient can be defined as the family of circles |
|
978 + * |
|
979 + * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂) |
|
980 + * |
|
981 + * excluding those circles whose radius would be < 0. When a point |
|
982 + * belongs to more than one circle, the one with a bigger t is the only |
|
983 + * one that contributes to its color. When a point does not belong |
|
984 + * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0). |
|
985 + * Further limitations on the range of values for t are imposed when |
|
986 + * the gradient is not repeated, namely t must belong to [0,1]. |
|
987 + * |
|
988 + * The graphical result is the same as drawing the valid (radius > 0) |
|
989 + * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient |
|
990 + * is not repeated) using SOURCE operator composition. |
|
991 + * |
|
992 + * It looks like a cone pointing towards the viewer if the ending circle |
|
993 + * is smaller than the starting one, a cone pointing inside the page if |
|
994 + * the starting circle is the smaller one and like a cylinder if they |
|
995 + * have the same radius. |
|
996 + * |
|
997 + * What we actually do is, given the point whose color we are interested |
|
998 + * in, compute the t values for that point, solving for t in: |
|
999 + * |
|
1000 + * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂ |
|
1001 + * |
|
1002 + * Let's rewrite it in a simpler way, by defining some auxiliary |
|
1003 + * variables: |
|
1004 + * |
|
1005 + * cd = c₂ - c₁ |
|
1006 + * pd = p - c₁ |
|
1007 + * dr = r₂ - r₁ |
|
1008 + * length(t·cd - pd) = r₁ + t·dr |
|
1009 + * |
|
1010 + * which actually means |
|
1011 + * |
|
1012 + * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr |
|
1013 + * |
|
1014 + * or |
|
1015 + * |
|
1016 + * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr. |
|
1017 + * |
|
1018 + * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes: |
|
1019 + * |
|
1020 + * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)² |
|
1021 + * |
|
1022 + * where we can actually expand the squares and solve for t: |
|
1023 + * |
|
1024 + * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² = |
|
1025 + * = r₁² + 2·r₁·t·dr + t²·dr² |
|
1026 + * |
|
1027 + * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t + |
|
1028 + * (pdx² + pdy² - r₁²) = 0 |
|
1029 + * |
|
1030 + * A = cdx² + cdy² - dr² |
|
1031 + * B = pdx·cdx + pdy·cdy + r₁·dr |
|
1032 + * C = pdx² + pdy² - r₁² |
|
1033 + * At² - 2Bt + C = 0 |
|
1034 + * |
|
1035 + * The solutions (unless the equation degenerates because of A = 0) are: |
|
1036 + * |
|
1037 + * t = (B ± ⎷(B² - A·C)) / A |
|
1038 + * |
|
1039 + * The solution we are going to prefer is the bigger one, unless the |
|
1040 + * radius associated to it is negative (or it falls outside the valid t |
|
1041 + * range). |
|
1042 + * |
|
1043 + * Additional observations (useful for optimizations): |
|
1044 + * A does not depend on p |
|
1045 + * |
|
1046 + * A < 0 <=> one of the two circles completely contains the other one |
|
1047 + * <=> for every p, the radiuses associated with the two t solutions |
|
1048 + * have opposite sign |
|
1049 + */ |
|
1050 + pixman_image_t *image = iter->image; |
|
1051 + int x = iter->x; |
|
1052 + int y = iter->y; |
|
1053 + int width = iter->width; |
|
1054 + uint16_t *buffer = iter->buffer; |
|
1055 + |
|
1056 + gradient_t *gradient = (gradient_t *)image; |
|
1057 + radial_gradient_t *radial = (radial_gradient_t *)image; |
|
1058 + uint16_t *end = buffer + width; |
|
1059 + pixman_gradient_walker_t walker; |
|
1060 + pixman_vector_t v, unit; |
|
1061 + |
|
1062 + /* reference point is the center of the pixel */ |
|
1063 + v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
|
1064 + v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
|
1065 + v.vector[2] = pixman_fixed_1; |
|
1066 + |
|
1067 + _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); |
|
1068 + |
|
1069 + if (image->common.transform) |
|
1070 + { |
|
1071 + if (!pixman_transform_point_3d (image->common.transform, &v)) |
|
1072 + return iter->buffer; |
|
1073 + |
|
1074 + unit.vector[0] = image->common.transform->matrix[0][0]; |
|
1075 + unit.vector[1] = image->common.transform->matrix[1][0]; |
|
1076 + unit.vector[2] = image->common.transform->matrix[2][0]; |
|
1077 + } |
|
1078 + else |
|
1079 + { |
|
1080 + unit.vector[0] = pixman_fixed_1; |
|
1081 + unit.vector[1] = 0; |
|
1082 + unit.vector[2] = 0; |
|
1083 + } |
|
1084 + |
|
1085 + if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1) |
|
1086 + { |
|
1087 + /* |
|
1088 + * Given: |
|
1089 + * |
|
1090 + * t = (B ± ⎷(B² - A·C)) / A |
|
1091 + * |
|
1092 + * where |
|
1093 + * |
|
1094 + * A = cdx² + cdy² - dr² |
|
1095 + * B = pdx·cdx + pdy·cdy + r₁·dr |
|
1096 + * C = pdx² + pdy² - r₁² |
|
1097 + * det = B² - A·C |
|
1098 + * |
|
1099 + * Since we have an affine transformation, we know that (pdx, pdy) |
|
1100 + * increase linearly with each pixel, |
|
1101 + * |
|
1102 + * pdx = pdx₀ + n·ux, |
|
1103 + * pdy = pdy₀ + n·uy, |
|
1104 + * |
|
1105 + * we can then express B, C and det through multiple differentiation. |
|
1106 + */ |
|
1107 + pixman_fixed_32_32_t b, db, c, dc, ddc; |
|
1108 + |
|
1109 + /* warning: this computation may overflow */ |
|
1110 + v.vector[0] -= radial->c1.x; |
|
1111 + v.vector[1] -= radial->c1.y; |
|
1112 + |
|
1113 + /* |
|
1114 + * B and C are computed and updated exactly. |
|
1115 + * If fdot was used instead of dot, in the worst case it would |
|
1116 + * lose 11 bits of precision in each of the multiplication and |
|
1117 + * summing up would zero out all the bit that were preserved, |
|
1118 + * thus making the result 0 instead of the correct one. |
|
1119 + * This would mean a worst case of unbound relative error or |
|
1120 + * about 2^10 absolute error |
|
1121 + */ |
|
1122 + b = dot (v.vector[0], v.vector[1], radial->c1.radius, |
|
1123 + radial->delta.x, radial->delta.y, radial->delta.radius); |
|
1124 + db = dot (unit.vector[0], unit.vector[1], 0, |
|
1125 + radial->delta.x, radial->delta.y, 0); |
|
1126 + |
|
1127 + c = dot (v.vector[0], v.vector[1], |
|
1128 + -((pixman_fixed_48_16_t) radial->c1.radius), |
|
1129 + v.vector[0], v.vector[1], radial->c1.radius); |
|
1130 + dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0], |
|
1131 + 2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1], |
|
1132 + 0, |
|
1133 + unit.vector[0], unit.vector[1], 0); |
|
1134 + ddc = 2 * dot (unit.vector[0], unit.vector[1], 0, |
|
1135 + unit.vector[0], unit.vector[1], 0); |
|
1136 + |
|
1137 + while (buffer < end) |
|
1138 + { |
|
1139 + if (!mask || *mask++) |
|
1140 + { |
|
1141 + *buffer = convert_8888_to_0565( |
|
1142 + radial_compute_color (radial->a, b, c, |
|
1143 + radial->inva, |
|
1144 + radial->delta.radius, |
|
1145 + radial->mindr, |
|
1146 + &walker, |
|
1147 + image->common.repeat)); |
|
1148 + } |
|
1149 + |
|
1150 + b += db; |
|
1151 + c += dc; |
|
1152 + dc += ddc; |
|
1153 + ++buffer; |
|
1154 + } |
|
1155 + } |
|
1156 + else |
|
1157 + { |
|
1158 + /* projective */ |
|
1159 + /* Warning: |
|
1160 + * error propagation guarantees are much looser than in the affine case |
|
1161 + */ |
|
1162 + while (buffer < end) |
|
1163 + { |
|
1164 + if (!mask || *mask++) |
|
1165 + { |
|
1166 + if (v.vector[2] != 0) |
|
1167 + { |
|
1168 + double pdx, pdy, invv2, b, c; |
|
1169 + |
|
1170 + invv2 = 1. * pixman_fixed_1 / v.vector[2]; |
|
1171 + |
|
1172 + pdx = v.vector[0] * invv2 - radial->c1.x; |
|
1173 + /* / pixman_fixed_1 */ |
|
1174 + |
|
1175 + pdy = v.vector[1] * invv2 - radial->c1.y; |
|
1176 + /* / pixman_fixed_1 */ |
|
1177 + |
|
1178 + b = fdot (pdx, pdy, radial->c1.radius, |
|
1179 + radial->delta.x, radial->delta.y, |
|
1180 + radial->delta.radius); |
|
1181 + /* / pixman_fixed_1 / pixman_fixed_1 */ |
|
1182 + |
|
1183 + c = fdot (pdx, pdy, -radial->c1.radius, |
|
1184 + pdx, pdy, radial->c1.radius); |
|
1185 + /* / pixman_fixed_1 / pixman_fixed_1 */ |
|
1186 + |
|
1187 + *buffer = convert_8888_to_0565 ( |
|
1188 + radial_compute_color (radial->a, b, c, |
|
1189 + radial->inva, |
|
1190 + radial->delta.radius, |
|
1191 + radial->mindr, |
|
1192 + &walker, |
|
1193 + image->common.repeat)); |
|
1194 + } |
|
1195 + else |
|
1196 + { |
|
1197 + *buffer = 0; |
|
1198 + } |
|
1199 + } |
|
1200 + |
|
1201 + ++buffer; |
|
1202 + |
|
1203 + v.vector[0] += unit.vector[0]; |
|
1204 + v.vector[1] += unit.vector[1]; |
|
1205 + v.vector[2] += unit.vector[2]; |
|
1206 + } |
|
1207 + } |
|
1208 + |
|
1209 + iter->y++; |
|
1210 + return iter->buffer; |
|
1211 +} |
|
1212 static uint32_t * |
|
1213 radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
|
1214 { |
|
1215 uint32_t *buffer = radial_get_scanline_narrow (iter, NULL); |
|
1216 |
|
1217 pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); |
|
1218 |
|
1219 return buffer; |
|
1220 } |
|
1221 |
|
1222 void |
|
1223 _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
|
1224 { |
|
1225 - if (iter->flags & ITER_NARROW) |
|
1226 + if (iter->flags & ITER_16) |
|
1227 + iter->get_scanline = radial_get_scanline_16; |
|
1228 + else if (iter->flags & ITER_NARROW) |
|
1229 iter->get_scanline = radial_get_scanline_narrow; |
|
1230 else |
|
1231 iter->get_scanline = radial_get_scanline_wide; |
|
1232 } |
|
1233 |
|
1234 + |
|
1235 PIXMAN_EXPORT pixman_image_t * |
|
1236 pixman_image_create_radial_gradient (pixman_point_fixed_t * inner, |
|
1237 pixman_point_fixed_t * outer, |
|
1238 pixman_fixed_t inner_radius, |
|
1239 pixman_fixed_t outer_radius, |
|
1240 const pixman_gradient_stop_t *stops, |
|
1241 int n_stops) |
|
1242 { |