/src/cairo/subprojects/pixman-0.43.4/pixman/pixman-bits-image.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. |
3 | | * 2005 Lars Knoll & Zack Rusin, Trolltech |
4 | | * 2008 Aaron Plattner, NVIDIA Corporation |
5 | | * Copyright © 2000 SuSE, Inc. |
6 | | * Copyright © 2007, 2009 Red Hat, Inc. |
7 | | * Copyright © 2008 André Tupinambá <andrelrt@gmail.com> |
8 | | * |
9 | | * Permission to use, copy, modify, distribute, and sell this software and its |
10 | | * documentation for any purpose is hereby granted without fee, provided that |
11 | | * the above copyright notice appear in all copies and that both that |
12 | | * copyright notice and this permission notice appear in supporting |
13 | | * documentation, and that the name of Keith Packard not be used in |
14 | | * advertising or publicity pertaining to distribution of the software without |
15 | | * specific, written prior permission. Keith Packard makes no |
16 | | * representations about the suitability of this software for any purpose. It |
17 | | * is provided "as is" without express or implied warranty. |
18 | | * |
19 | | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
20 | | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
22 | | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
23 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
24 | | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
25 | | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
26 | | * SOFTWARE. |
27 | | */ |
28 | | |
29 | | #ifdef HAVE_CONFIG_H |
30 | | #include <pixman-config.h> |
31 | | #endif |
32 | | #include <stdio.h> |
33 | | #include <stdlib.h> |
34 | | #include <string.h> |
35 | | #include "pixman-private.h" |
36 | | #include "pixman-combine32.h" |
37 | | #include "pixman-inlines.h" |
38 | | #include "dither/blue-noise-64x64.h" |
39 | | |
40 | | /* Fetch functions */ |
41 | | |
42 | | static force_inline void |
43 | | fetch_pixel_no_alpha_32 (bits_image_t *image, |
44 | | int x, int y, pixman_bool_t check_bounds, |
45 | | void *out) |
46 | 0 | { |
47 | 0 | uint32_t *ret = out; |
48 | |
|
49 | 0 | if (check_bounds && |
50 | 0 | (x < 0 || x >= image->width || y < 0 || y >= image->height)) |
51 | 0 | *ret = 0; |
52 | 0 | else |
53 | 0 | *ret = image->fetch_pixel_32 (image, x, y); |
54 | 0 | } |
55 | | |
56 | | static force_inline void |
57 | | fetch_pixel_no_alpha_float (bits_image_t *image, |
58 | | int x, int y, pixman_bool_t check_bounds, |
59 | | void *out) |
60 | 0 | { |
61 | 0 | argb_t *ret = out; |
62 | |
|
63 | 0 | if (check_bounds && |
64 | 0 | (x < 0 || x >= image->width || y < 0 || y >= image->height)) |
65 | 0 | ret->a = ret->r = ret->g = ret->b = 0.f; |
66 | 0 | else |
67 | 0 | *ret = image->fetch_pixel_float (image, x, y); |
68 | 0 | } |
69 | | |
70 | | typedef void (* get_pixel_t) (bits_image_t *image, |
71 | | int x, int y, pixman_bool_t check_bounds, void *out); |
72 | | |
73 | | static force_inline void |
74 | | bits_image_fetch_pixel_nearest (bits_image_t *image, |
75 | | pixman_fixed_t x, |
76 | | pixman_fixed_t y, |
77 | | get_pixel_t get_pixel, |
78 | | void *out) |
79 | 0 | { |
80 | 0 | int x0 = pixman_fixed_to_int (x - pixman_fixed_e); |
81 | 0 | int y0 = pixman_fixed_to_int (y - pixman_fixed_e); |
82 | |
|
83 | 0 | if (image->common.repeat != PIXMAN_REPEAT_NONE) |
84 | 0 | { |
85 | 0 | repeat (image->common.repeat, &x0, image->width); |
86 | 0 | repeat (image->common.repeat, &y0, image->height); |
87 | |
|
88 | 0 | get_pixel (image, x0, y0, FALSE, out); |
89 | 0 | } |
90 | 0 | else |
91 | 0 | { |
92 | 0 | get_pixel (image, x0, y0, TRUE, out); |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | | static force_inline void |
97 | | bits_image_fetch_pixel_bilinear_32 (bits_image_t *image, |
98 | | pixman_fixed_t x, |
99 | | pixman_fixed_t y, |
100 | | get_pixel_t get_pixel, |
101 | | void *out) |
102 | 0 | { |
103 | 0 | pixman_repeat_t repeat_mode = image->common.repeat; |
104 | 0 | int width = image->width; |
105 | 0 | int height = image->height; |
106 | 0 | int x1, y1, x2, y2; |
107 | 0 | uint32_t tl, tr, bl, br; |
108 | 0 | int32_t distx, disty; |
109 | 0 | uint32_t *ret = out; |
110 | |
|
111 | 0 | x1 = x - pixman_fixed_1 / 2; |
112 | 0 | y1 = y - pixman_fixed_1 / 2; |
113 | |
|
114 | 0 | distx = pixman_fixed_to_bilinear_weight (x1); |
115 | 0 | disty = pixman_fixed_to_bilinear_weight (y1); |
116 | |
|
117 | 0 | x1 = pixman_fixed_to_int (x1); |
118 | 0 | y1 = pixman_fixed_to_int (y1); |
119 | 0 | x2 = x1 + 1; |
120 | 0 | y2 = y1 + 1; |
121 | |
|
122 | 0 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
123 | 0 | { |
124 | 0 | repeat (repeat_mode, &x1, width); |
125 | 0 | repeat (repeat_mode, &y1, height); |
126 | 0 | repeat (repeat_mode, &x2, width); |
127 | 0 | repeat (repeat_mode, &y2, height); |
128 | |
|
129 | 0 | get_pixel (image, x1, y1, FALSE, &tl); |
130 | 0 | get_pixel (image, x2, y1, FALSE, &tr); |
131 | 0 | get_pixel (image, x1, y2, FALSE, &bl); |
132 | 0 | get_pixel (image, x2, y2, FALSE, &br); |
133 | 0 | } |
134 | 0 | else |
135 | 0 | { |
136 | 0 | get_pixel (image, x1, y1, TRUE, &tl); |
137 | 0 | get_pixel (image, x2, y1, TRUE, &tr); |
138 | 0 | get_pixel (image, x1, y2, TRUE, &bl); |
139 | 0 | get_pixel (image, x2, y2, TRUE, &br); |
140 | 0 | } |
141 | |
|
142 | 0 | *ret = bilinear_interpolation (tl, tr, bl, br, distx, disty); |
143 | 0 | } |
144 | | |
145 | | static force_inline void |
146 | | bits_image_fetch_pixel_bilinear_float (bits_image_t *image, |
147 | | pixman_fixed_t x, |
148 | | pixman_fixed_t y, |
149 | | get_pixel_t get_pixel, |
150 | | void *out) |
151 | 0 | { |
152 | 0 | pixman_repeat_t repeat_mode = image->common.repeat; |
153 | 0 | int width = image->width; |
154 | 0 | int height = image->height; |
155 | 0 | int x1, y1, x2, y2; |
156 | 0 | argb_t tl, tr, bl, br; |
157 | 0 | float distx, disty; |
158 | 0 | argb_t *ret = out; |
159 | |
|
160 | 0 | x1 = x - pixman_fixed_1 / 2; |
161 | 0 | y1 = y - pixman_fixed_1 / 2; |
162 | |
|
163 | 0 | distx = ((float)pixman_fixed_fraction(x1)) / 65536.f; |
164 | 0 | disty = ((float)pixman_fixed_fraction(y1)) / 65536.f; |
165 | |
|
166 | 0 | x1 = pixman_fixed_to_int (x1); |
167 | 0 | y1 = pixman_fixed_to_int (y1); |
168 | 0 | x2 = x1 + 1; |
169 | 0 | y2 = y1 + 1; |
170 | |
|
171 | 0 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
172 | 0 | { |
173 | 0 | repeat (repeat_mode, &x1, width); |
174 | 0 | repeat (repeat_mode, &y1, height); |
175 | 0 | repeat (repeat_mode, &x2, width); |
176 | 0 | repeat (repeat_mode, &y2, height); |
177 | |
|
178 | 0 | get_pixel (image, x1, y1, FALSE, &tl); |
179 | 0 | get_pixel (image, x2, y1, FALSE, &tr); |
180 | 0 | get_pixel (image, x1, y2, FALSE, &bl); |
181 | 0 | get_pixel (image, x2, y2, FALSE, &br); |
182 | 0 | } |
183 | 0 | else |
184 | 0 | { |
185 | 0 | get_pixel (image, x1, y1, TRUE, &tl); |
186 | 0 | get_pixel (image, x2, y1, TRUE, &tr); |
187 | 0 | get_pixel (image, x1, y2, TRUE, &bl); |
188 | 0 | get_pixel (image, x2, y2, TRUE, &br); |
189 | 0 | } |
190 | |
|
191 | 0 | *ret = bilinear_interpolation_float (tl, tr, bl, br, distx, disty); |
192 | 0 | } |
193 | | |
194 | | static force_inline void accum_32(unsigned int *satot, unsigned int *srtot, |
195 | | unsigned int *sgtot, unsigned int *sbtot, |
196 | | const void *p, pixman_fixed_t f) |
197 | 0 | { |
198 | 0 | uint32_t pixel = *(uint32_t *)p; |
199 | |
|
200 | 0 | *srtot += (int)RED_8 (pixel) * f; |
201 | 0 | *sgtot += (int)GREEN_8 (pixel) * f; |
202 | 0 | *sbtot += (int)BLUE_8 (pixel) * f; |
203 | 0 | *satot += (int)ALPHA_8 (pixel) * f; |
204 | 0 | } |
205 | | |
206 | | static force_inline void reduce_32(unsigned int satot, unsigned int srtot, |
207 | | unsigned int sgtot, unsigned int sbtot, |
208 | | void *p) |
209 | 0 | { |
210 | 0 | uint32_t *ret = p; |
211 | |
|
212 | 0 | satot = (int32_t)(satot + 0x8000) / 65536; |
213 | 0 | srtot = (int32_t)(srtot + 0x8000) / 65536; |
214 | 0 | sgtot = (int32_t)(sgtot + 0x8000) / 65536; |
215 | 0 | sbtot = (int32_t)(sbtot + 0x8000) / 65536; |
216 | |
|
217 | 0 | satot = CLIP ((int32_t)satot, 0, 0xff); |
218 | 0 | srtot = CLIP ((int32_t)srtot, 0, 0xff); |
219 | 0 | sgtot = CLIP ((int32_t)sgtot, 0, 0xff); |
220 | 0 | sbtot = CLIP ((int32_t)sbtot, 0, 0xff); |
221 | |
|
222 | 0 | *ret = ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); |
223 | 0 | } |
224 | | |
225 | | static force_inline void accum_float(unsigned int *satot, unsigned int *srtot, |
226 | | unsigned int *sgtot, unsigned int *sbtot, |
227 | | const void *p, pixman_fixed_t f) |
228 | 0 | { |
229 | 0 | const argb_t *pixel = p; |
230 | |
|
231 | 0 | *satot += pixel->a * f; |
232 | 0 | *srtot += pixel->r * f; |
233 | 0 | *sgtot += pixel->g * f; |
234 | 0 | *sbtot += pixel->b * f; |
235 | 0 | } |
236 | | |
237 | | static force_inline void reduce_float(unsigned int satot, unsigned int srtot, |
238 | | unsigned int sgtot, unsigned int sbtot, |
239 | | void *p) |
240 | 0 | { |
241 | 0 | argb_t *ret = p; |
242 | |
|
243 | 0 | ret->a = CLIP ((int32_t)satot / 65536.f, 0.f, 1.f); |
244 | 0 | ret->r = CLIP ((int32_t)srtot / 65536.f, 0.f, 1.f); |
245 | 0 | ret->g = CLIP ((int32_t)sgtot / 65536.f, 0.f, 1.f); |
246 | 0 | ret->b = CLIP ((int32_t)sbtot / 65536.f, 0.f, 1.f); |
247 | 0 | } |
248 | | |
249 | | typedef void (* accumulate_pixel_t) (unsigned int *satot, unsigned int *srtot, |
250 | | unsigned int *sgtot, unsigned int *sbtot, |
251 | | const void *pixel, pixman_fixed_t f); |
252 | | |
253 | | typedef void (* reduce_pixel_t) (unsigned int satot, unsigned int srtot, |
254 | | unsigned int sgtot, unsigned int sbtot, |
255 | | void *out); |
256 | | |
257 | | static force_inline void |
258 | | bits_image_fetch_pixel_convolution (bits_image_t *image, |
259 | | pixman_fixed_t x, |
260 | | pixman_fixed_t y, |
261 | | get_pixel_t get_pixel, |
262 | | void *out, |
263 | | accumulate_pixel_t accum, |
264 | | reduce_pixel_t reduce) |
265 | 0 | { |
266 | 0 | pixman_fixed_t *params = image->common.filter_params; |
267 | 0 | int x_off = (params[0] - pixman_fixed_1) >> 1; |
268 | 0 | int y_off = (params[1] - pixman_fixed_1) >> 1; |
269 | 0 | int32_t cwidth = pixman_fixed_to_int (params[0]); |
270 | 0 | int32_t cheight = pixman_fixed_to_int (params[1]); |
271 | 0 | int32_t i, j, x1, x2, y1, y2; |
272 | 0 | pixman_repeat_t repeat_mode = image->common.repeat; |
273 | 0 | int width = image->width; |
274 | 0 | int height = image->height; |
275 | 0 | unsigned int srtot, sgtot, sbtot, satot; |
276 | |
|
277 | 0 | params += 2; |
278 | |
|
279 | 0 | x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); |
280 | 0 | y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); |
281 | 0 | x2 = x1 + cwidth; |
282 | 0 | y2 = y1 + cheight; |
283 | |
|
284 | 0 | srtot = sgtot = sbtot = satot = 0; |
285 | |
|
286 | 0 | for (i = y1; i < y2; ++i) |
287 | 0 | { |
288 | 0 | for (j = x1; j < x2; ++j) |
289 | 0 | { |
290 | 0 | int rx = j; |
291 | 0 | int ry = i; |
292 | |
|
293 | 0 | pixman_fixed_t f = *params; |
294 | |
|
295 | 0 | if (f) |
296 | 0 | { |
297 | | /* Must be big enough to hold a argb_t */ |
298 | 0 | argb_t pixel; |
299 | |
|
300 | 0 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
301 | 0 | { |
302 | 0 | repeat (repeat_mode, &rx, width); |
303 | 0 | repeat (repeat_mode, &ry, height); |
304 | |
|
305 | 0 | get_pixel (image, rx, ry, FALSE, &pixel); |
306 | 0 | } |
307 | 0 | else |
308 | 0 | { |
309 | 0 | get_pixel (image, rx, ry, TRUE, &pixel); |
310 | 0 | } |
311 | |
|
312 | 0 | accum (&satot, &srtot, &sgtot, &sbtot, &pixel, f); |
313 | 0 | } |
314 | |
|
315 | 0 | params++; |
316 | 0 | } |
317 | 0 | } |
318 | |
|
319 | 0 | reduce (satot, srtot, sgtot, sbtot, out); |
320 | 0 | } |
321 | | |
322 | | static void |
323 | | bits_image_fetch_pixel_separable_convolution (bits_image_t *image, |
324 | | pixman_fixed_t x, |
325 | | pixman_fixed_t y, |
326 | | get_pixel_t get_pixel, |
327 | | void *out, |
328 | | accumulate_pixel_t accum, |
329 | | reduce_pixel_t reduce) |
330 | 0 | { |
331 | 0 | pixman_fixed_t *params = image->common.filter_params; |
332 | 0 | pixman_repeat_t repeat_mode = image->common.repeat; |
333 | 0 | int width = image->width; |
334 | 0 | int height = image->height; |
335 | 0 | int cwidth = pixman_fixed_to_int (params[0]); |
336 | 0 | int cheight = pixman_fixed_to_int (params[1]); |
337 | 0 | int x_phase_bits = pixman_fixed_to_int (params[2]); |
338 | 0 | int y_phase_bits = pixman_fixed_to_int (params[3]); |
339 | 0 | int x_phase_shift = 16 - x_phase_bits; |
340 | 0 | int y_phase_shift = 16 - y_phase_bits; |
341 | 0 | int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; |
342 | 0 | int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; |
343 | 0 | pixman_fixed_t *y_params; |
344 | 0 | unsigned int srtot, sgtot, sbtot, satot; |
345 | 0 | int32_t x1, x2, y1, y2; |
346 | 0 | int32_t px, py; |
347 | 0 | int i, j; |
348 | | |
349 | | /* Round x and y to the middle of the closest phase before continuing. This |
350 | | * ensures that the convolution matrix is aligned right, since it was |
351 | | * positioned relative to a particular phase (and not relative to whatever |
352 | | * exact fraction we happen to get here). |
353 | | */ |
354 | 0 | x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); |
355 | 0 | y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); |
356 | |
|
357 | 0 | px = (x & 0xffff) >> x_phase_shift; |
358 | 0 | py = (y & 0xffff) >> y_phase_shift; |
359 | |
|
360 | 0 | y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; |
361 | |
|
362 | 0 | x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); |
363 | 0 | y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); |
364 | 0 | x2 = x1 + cwidth; |
365 | 0 | y2 = y1 + cheight; |
366 | |
|
367 | 0 | srtot = sgtot = sbtot = satot = 0; |
368 | |
|
369 | 0 | for (i = y1; i < y2; ++i) |
370 | 0 | { |
371 | 0 | pixman_fixed_48_16_t fy = *y_params++; |
372 | 0 | pixman_fixed_t *x_params = params + 4 + px * cwidth; |
373 | |
|
374 | 0 | if (fy) |
375 | 0 | { |
376 | 0 | for (j = x1; j < x2; ++j) |
377 | 0 | { |
378 | 0 | pixman_fixed_t fx = *x_params++; |
379 | 0 | int rx = j; |
380 | 0 | int ry = i; |
381 | |
|
382 | 0 | if (fx) |
383 | 0 | { |
384 | | /* Must be big enough to hold a argb_t */ |
385 | 0 | argb_t pixel; |
386 | 0 | pixman_fixed_t f; |
387 | |
|
388 | 0 | if (repeat_mode != PIXMAN_REPEAT_NONE) |
389 | 0 | { |
390 | 0 | repeat (repeat_mode, &rx, width); |
391 | 0 | repeat (repeat_mode, &ry, height); |
392 | |
|
393 | 0 | get_pixel (image, rx, ry, FALSE, &pixel); |
394 | 0 | } |
395 | 0 | else |
396 | 0 | { |
397 | 0 | get_pixel (image, rx, ry, TRUE, &pixel); |
398 | 0 | } |
399 | |
|
400 | 0 | f = (fy * fx + 0x8000) >> 16; |
401 | |
|
402 | 0 | accum(&satot, &srtot, &sgtot, &sbtot, &pixel, f); |
403 | 0 | } |
404 | 0 | } |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | |
|
409 | 0 | reduce(satot, srtot, sgtot, sbtot, out); |
410 | 0 | } |
411 | | |
412 | | static force_inline void |
413 | | bits_image_fetch_pixel_filtered (bits_image_t *image, |
414 | | pixman_bool_t wide, |
415 | | pixman_fixed_t x, |
416 | | pixman_fixed_t y, |
417 | | get_pixel_t get_pixel, |
418 | | void *out) |
419 | 0 | { |
420 | 0 | switch (image->common.filter) |
421 | 0 | { |
422 | 0 | case PIXMAN_FILTER_NEAREST: |
423 | 0 | case PIXMAN_FILTER_FAST: |
424 | 0 | bits_image_fetch_pixel_nearest (image, x, y, get_pixel, out); |
425 | 0 | break; |
426 | | |
427 | 0 | case PIXMAN_FILTER_BILINEAR: |
428 | 0 | case PIXMAN_FILTER_GOOD: |
429 | 0 | case PIXMAN_FILTER_BEST: |
430 | 0 | if (wide) |
431 | 0 | bits_image_fetch_pixel_bilinear_float (image, x, y, get_pixel, out); |
432 | 0 | else |
433 | 0 | bits_image_fetch_pixel_bilinear_32 (image, x, y, get_pixel, out); |
434 | 0 | break; |
435 | | |
436 | 0 | case PIXMAN_FILTER_CONVOLUTION: |
437 | 0 | if (wide) |
438 | 0 | { |
439 | 0 | bits_image_fetch_pixel_convolution (image, x, y, |
440 | 0 | get_pixel, out, |
441 | 0 | accum_float, |
442 | 0 | reduce_float); |
443 | 0 | } |
444 | 0 | else |
445 | 0 | { |
446 | 0 | bits_image_fetch_pixel_convolution (image, x, y, |
447 | 0 | get_pixel, out, |
448 | 0 | accum_32, reduce_32); |
449 | 0 | } |
450 | 0 | break; |
451 | | |
452 | 0 | case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: |
453 | 0 | if (wide) |
454 | 0 | { |
455 | 0 | bits_image_fetch_pixel_separable_convolution (image, x, y, |
456 | 0 | get_pixel, out, |
457 | 0 | accum_float, |
458 | 0 | reduce_float); |
459 | 0 | } |
460 | 0 | else |
461 | 0 | { |
462 | 0 | bits_image_fetch_pixel_separable_convolution (image, x, y, |
463 | 0 | get_pixel, out, |
464 | 0 | accum_32, reduce_32); |
465 | 0 | } |
466 | 0 | break; |
467 | | |
468 | 0 | default: |
469 | 0 | assert (0); |
470 | 0 | break; |
471 | 0 | } |
472 | 0 | } |
473 | | |
474 | | static uint32_t * |
475 | | __bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, |
476 | | pixman_bool_t wide, |
477 | | const uint32_t * mask) |
478 | 0 | { |
479 | 0 | pixman_image_t *image = iter->image; |
480 | 0 | int offset = iter->x; |
481 | 0 | int line = iter->y++; |
482 | 0 | int width = iter->width; |
483 | 0 | uint32_t * buffer = iter->buffer; |
484 | |
|
485 | 0 | const uint32_t wide_zero[4] = {0}; |
486 | 0 | pixman_fixed_t x, y; |
487 | 0 | pixman_fixed_t ux, uy; |
488 | 0 | pixman_vector_t v; |
489 | 0 | int i; |
490 | 0 | get_pixel_t get_pixel = |
491 | 0 | wide ? fetch_pixel_no_alpha_float : fetch_pixel_no_alpha_32; |
492 | | |
493 | | /* reference point is the center of the pixel */ |
494 | 0 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
495 | 0 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
496 | 0 | v.vector[2] = pixman_fixed_1; |
497 | |
|
498 | 0 | if (image->common.transform) |
499 | 0 | { |
500 | 0 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
501 | 0 | return iter->buffer; |
502 | | |
503 | 0 | ux = image->common.transform->matrix[0][0]; |
504 | 0 | uy = image->common.transform->matrix[1][0]; |
505 | 0 | } |
506 | 0 | else |
507 | 0 | { |
508 | 0 | ux = pixman_fixed_1; |
509 | 0 | uy = 0; |
510 | 0 | } |
511 | | |
512 | 0 | x = v.vector[0]; |
513 | 0 | y = v.vector[1]; |
514 | |
|
515 | 0 | for (i = 0; i < width; ++i) |
516 | 0 | { |
517 | 0 | if (!mask || (!wide && mask[i]) || |
518 | 0 | (wide && memcmp(&mask[4 * i], wide_zero, 16) != 0)) |
519 | 0 | { |
520 | 0 | bits_image_fetch_pixel_filtered ( |
521 | 0 | &image->bits, wide, x, y, get_pixel, buffer); |
522 | 0 | } |
523 | |
|
524 | 0 | x += ux; |
525 | 0 | y += uy; |
526 | 0 | buffer += wide ? 4 : 1; |
527 | 0 | } |
528 | |
|
529 | 0 | return iter->buffer; |
530 | 0 | } |
531 | | |
532 | | static uint32_t * |
533 | | bits_image_fetch_affine_no_alpha_32 (pixman_iter_t *iter, |
534 | | const uint32_t *mask) |
535 | 0 | { |
536 | 0 | return __bits_image_fetch_affine_no_alpha(iter, FALSE, mask); |
537 | 0 | } |
538 | | |
539 | | static uint32_t * |
540 | | bits_image_fetch_affine_no_alpha_float (pixman_iter_t *iter, |
541 | | const uint32_t *mask) |
542 | 0 | { |
543 | 0 | return __bits_image_fetch_affine_no_alpha(iter, TRUE, mask); |
544 | 0 | } |
545 | | |
546 | | /* General fetcher */ |
547 | | static force_inline void |
548 | | fetch_pixel_general_32 (bits_image_t *image, |
549 | | int x, int y, pixman_bool_t check_bounds, |
550 | | void *out) |
551 | 0 | { |
552 | 0 | uint32_t pixel, *ret = out; |
553 | |
|
554 | 0 | if (check_bounds && |
555 | 0 | (x < 0 || x >= image->width || y < 0 || y >= image->height)) |
556 | 0 | { |
557 | 0 | *ret = 0; |
558 | 0 | return; |
559 | 0 | } |
560 | | |
561 | 0 | pixel = image->fetch_pixel_32 (image, x, y); |
562 | |
|
563 | 0 | if (image->common.alpha_map) |
564 | 0 | { |
565 | 0 | uint32_t pixel_a; |
566 | |
|
567 | 0 | x -= image->common.alpha_origin_x; |
568 | 0 | y -= image->common.alpha_origin_y; |
569 | |
|
570 | 0 | if (x < 0 || x >= image->common.alpha_map->width || |
571 | 0 | y < 0 || y >= image->common.alpha_map->height) |
572 | 0 | { |
573 | 0 | pixel_a = 0; |
574 | 0 | } |
575 | 0 | else |
576 | 0 | { |
577 | 0 | pixel_a = image->common.alpha_map->fetch_pixel_32 ( |
578 | 0 | image->common.alpha_map, x, y); |
579 | |
|
580 | 0 | pixel_a = ALPHA_8 (pixel_a); |
581 | 0 | } |
582 | |
|
583 | 0 | pixel &= 0x00ffffff; |
584 | 0 | pixel |= (pixel_a << 24); |
585 | 0 | } |
586 | |
|
587 | 0 | *ret = pixel; |
588 | 0 | } |
589 | | |
590 | | static force_inline void |
591 | | fetch_pixel_general_float (bits_image_t *image, |
592 | | int x, int y, pixman_bool_t check_bounds, |
593 | | void *out) |
594 | 0 | { |
595 | 0 | argb_t *ret = out; |
596 | |
|
597 | 0 | if (check_bounds && |
598 | 0 | (x < 0 || x >= image->width || y < 0 || y >= image->height)) |
599 | 0 | { |
600 | 0 | ret->a = ret->r = ret->g = ret->b = 0; |
601 | 0 | return; |
602 | 0 | } |
603 | | |
604 | 0 | *ret = image->fetch_pixel_float (image, x, y); |
605 | |
|
606 | 0 | if (image->common.alpha_map) |
607 | 0 | { |
608 | 0 | x -= image->common.alpha_origin_x; |
609 | 0 | y -= image->common.alpha_origin_y; |
610 | |
|
611 | 0 | if (x < 0 || x >= image->common.alpha_map->width || |
612 | 0 | y < 0 || y >= image->common.alpha_map->height) |
613 | 0 | { |
614 | 0 | ret->a = 0.f; |
615 | 0 | } |
616 | 0 | else |
617 | 0 | { |
618 | 0 | argb_t alpha; |
619 | |
|
620 | 0 | alpha = image->common.alpha_map->fetch_pixel_float ( |
621 | 0 | image->common.alpha_map, x, y); |
622 | |
|
623 | 0 | ret->a = alpha.a; |
624 | 0 | } |
625 | 0 | } |
626 | 0 | } |
627 | | |
628 | | static uint32_t * |
629 | | __bits_image_fetch_general (pixman_iter_t *iter, |
630 | | pixman_bool_t wide, |
631 | | const uint32_t *mask) |
632 | 0 | { |
633 | 0 | pixman_image_t *image = iter->image; |
634 | 0 | int offset = iter->x; |
635 | 0 | int line = iter->y++; |
636 | 0 | int width = iter->width; |
637 | 0 | uint32_t * buffer = iter->buffer; |
638 | 0 | get_pixel_t get_pixel = |
639 | 0 | wide ? fetch_pixel_general_float : fetch_pixel_general_32; |
640 | |
|
641 | 0 | const uint32_t wide_zero[4] = {0}; |
642 | 0 | pixman_fixed_t x, y, w; |
643 | 0 | pixman_fixed_t ux, uy, uw; |
644 | 0 | pixman_vector_t v; |
645 | 0 | int i; |
646 | | |
647 | | /* reference point is the center of the pixel */ |
648 | 0 | v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; |
649 | 0 | v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; |
650 | 0 | v.vector[2] = pixman_fixed_1; |
651 | |
|
652 | 0 | if (image->common.transform) |
653 | 0 | { |
654 | 0 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
655 | 0 | return buffer; |
656 | | |
657 | 0 | ux = image->common.transform->matrix[0][0]; |
658 | 0 | uy = image->common.transform->matrix[1][0]; |
659 | 0 | uw = image->common.transform->matrix[2][0]; |
660 | 0 | } |
661 | 0 | else |
662 | 0 | { |
663 | 0 | ux = pixman_fixed_1; |
664 | 0 | uy = 0; |
665 | 0 | uw = 0; |
666 | 0 | } |
667 | | |
668 | 0 | x = v.vector[0]; |
669 | 0 | y = v.vector[1]; |
670 | 0 | w = v.vector[2]; |
671 | |
|
672 | 0 | for (i = 0; i < width; ++i) |
673 | 0 | { |
674 | 0 | pixman_fixed_t x0, y0; |
675 | |
|
676 | 0 | if (!mask || (!wide && mask[i]) || |
677 | 0 | (wide && memcmp(&mask[4 * i], wide_zero, 16) != 0)) |
678 | 0 | { |
679 | 0 | if (w != 0) |
680 | 0 | { |
681 | 0 | x0 = ((uint64_t)x << 16) / w; |
682 | 0 | y0 = ((uint64_t)y << 16) / w; |
683 | 0 | } |
684 | 0 | else |
685 | 0 | { |
686 | 0 | x0 = 0; |
687 | 0 | y0 = 0; |
688 | 0 | } |
689 | |
|
690 | 0 | bits_image_fetch_pixel_filtered ( |
691 | 0 | &image->bits, wide, x0, y0, get_pixel, buffer); |
692 | 0 | } |
693 | |
|
694 | 0 | x += ux; |
695 | 0 | y += uy; |
696 | 0 | w += uw; |
697 | 0 | buffer += wide ? 4 : 1; |
698 | 0 | } |
699 | |
|
700 | 0 | return iter->buffer; |
701 | 0 | } |
702 | | |
703 | | static uint32_t * |
704 | | bits_image_fetch_general_32 (pixman_iter_t *iter, |
705 | | const uint32_t *mask) |
706 | 0 | { |
707 | 0 | return __bits_image_fetch_general(iter, FALSE, mask); |
708 | 0 | } |
709 | | |
710 | | static uint32_t * |
711 | | bits_image_fetch_general_float (pixman_iter_t *iter, |
712 | | const uint32_t *mask) |
713 | 0 | { |
714 | 0 | return __bits_image_fetch_general(iter, TRUE, mask); |
715 | 0 | } |
716 | | |
717 | | static void |
718 | | replicate_pixel_32 (bits_image_t * bits, |
719 | | int x, |
720 | | int y, |
721 | | int width, |
722 | | uint32_t * buffer) |
723 | 0 | { |
724 | 0 | uint32_t color; |
725 | 0 | uint32_t *end; |
726 | |
|
727 | 0 | color = bits->fetch_pixel_32 (bits, x, y); |
728 | |
|
729 | 0 | end = buffer + width; |
730 | 0 | while (buffer < end) |
731 | 0 | *(buffer++) = color; |
732 | 0 | } |
733 | | |
734 | | static void |
735 | | replicate_pixel_float (bits_image_t * bits, |
736 | | int x, |
737 | | int y, |
738 | | int width, |
739 | | uint32_t * b) |
740 | 0 | { |
741 | 0 | argb_t color; |
742 | 0 | argb_t *buffer = (argb_t *)b; |
743 | 0 | argb_t *end; |
744 | |
|
745 | 0 | color = bits->fetch_pixel_float (bits, x, y); |
746 | |
|
747 | 0 | end = buffer + width; |
748 | 0 | while (buffer < end) |
749 | 0 | *(buffer++) = color; |
750 | 0 | } |
751 | | |
752 | | static void |
753 | | bits_image_fetch_untransformed_repeat_none (bits_image_t *image, |
754 | | pixman_bool_t wide, |
755 | | int x, |
756 | | int y, |
757 | | int width, |
758 | | uint32_t * buffer) |
759 | 0 | { |
760 | 0 | uint32_t w; |
761 | |
|
762 | 0 | if (y < 0 || y >= image->height) |
763 | 0 | { |
764 | 0 | memset (buffer, 0, width * (wide? sizeof (argb_t) : 4)); |
765 | 0 | return; |
766 | 0 | } |
767 | | |
768 | 0 | if (x < 0) |
769 | 0 | { |
770 | 0 | w = MIN (width, -x); |
771 | |
|
772 | 0 | memset (buffer, 0, w * (wide ? sizeof (argb_t) : 4)); |
773 | |
|
774 | 0 | width -= w; |
775 | 0 | buffer += w * (wide? 4 : 1); |
776 | 0 | x += w; |
777 | 0 | } |
778 | |
|
779 | 0 | if (x < image->width) |
780 | 0 | { |
781 | 0 | w = MIN (width, image->width - x); |
782 | |
|
783 | 0 | if (wide) |
784 | 0 | image->fetch_scanline_float (image, x, y, w, buffer, NULL); |
785 | 0 | else |
786 | 0 | image->fetch_scanline_32 (image, x, y, w, buffer, NULL); |
787 | |
|
788 | 0 | width -= w; |
789 | 0 | buffer += w * (wide? 4 : 1); |
790 | 0 | x += w; |
791 | 0 | } |
792 | |
|
793 | 0 | memset (buffer, 0, width * (wide ? sizeof (argb_t) : 4)); |
794 | 0 | } |
795 | | |
796 | | static void |
797 | | bits_image_fetch_untransformed_repeat_normal (bits_image_t *image, |
798 | | pixman_bool_t wide, |
799 | | int x, |
800 | | int y, |
801 | | int width, |
802 | | uint32_t * buffer) |
803 | 0 | { |
804 | 0 | uint32_t w; |
805 | |
|
806 | 0 | while (y < 0) |
807 | 0 | y += image->height; |
808 | |
|
809 | 0 | while (y >= image->height) |
810 | 0 | y -= image->height; |
811 | |
|
812 | 0 | if (image->width == 1) |
813 | 0 | { |
814 | 0 | if (wide) |
815 | 0 | replicate_pixel_float (image, 0, y, width, buffer); |
816 | 0 | else |
817 | 0 | replicate_pixel_32 (image, 0, y, width, buffer); |
818 | |
|
819 | 0 | return; |
820 | 0 | } |
821 | | |
822 | 0 | while (width) |
823 | 0 | { |
824 | 0 | while (x < 0) |
825 | 0 | x += image->width; |
826 | 0 | while (x >= image->width) |
827 | 0 | x -= image->width; |
828 | |
|
829 | 0 | w = MIN (width, image->width - x); |
830 | |
|
831 | 0 | if (wide) |
832 | 0 | image->fetch_scanline_float (image, x, y, w, buffer, NULL); |
833 | 0 | else |
834 | 0 | image->fetch_scanline_32 (image, x, y, w, buffer, NULL); |
835 | |
|
836 | 0 | buffer += w * (wide? 4 : 1); |
837 | 0 | x += w; |
838 | 0 | width -= w; |
839 | 0 | } |
840 | 0 | } |
841 | | |
842 | | static uint32_t * |
843 | | bits_image_fetch_untransformed_32 (pixman_iter_t * iter, |
844 | | const uint32_t *mask) |
845 | 0 | { |
846 | 0 | pixman_image_t *image = iter->image; |
847 | 0 | int x = iter->x; |
848 | 0 | int y = iter->y; |
849 | 0 | int width = iter->width; |
850 | 0 | uint32_t * buffer = iter->buffer; |
851 | |
|
852 | 0 | if (image->common.repeat == PIXMAN_REPEAT_NONE) |
853 | 0 | { |
854 | 0 | bits_image_fetch_untransformed_repeat_none ( |
855 | 0 | &image->bits, FALSE, x, y, width, buffer); |
856 | 0 | } |
857 | 0 | else |
858 | 0 | { |
859 | 0 | bits_image_fetch_untransformed_repeat_normal ( |
860 | 0 | &image->bits, FALSE, x, y, width, buffer); |
861 | 0 | } |
862 | |
|
863 | 0 | iter->y++; |
864 | 0 | return buffer; |
865 | 0 | } |
866 | | |
867 | | static uint32_t * |
868 | | bits_image_fetch_untransformed_float (pixman_iter_t * iter, |
869 | | const uint32_t *mask) |
870 | 0 | { |
871 | 0 | pixman_image_t *image = iter->image; |
872 | 0 | int x = iter->x; |
873 | 0 | int y = iter->y; |
874 | 0 | int width = iter->width; |
875 | 0 | uint32_t * buffer = iter->buffer; |
876 | |
|
877 | 0 | if (image->common.repeat == PIXMAN_REPEAT_NONE) |
878 | 0 | { |
879 | 0 | bits_image_fetch_untransformed_repeat_none ( |
880 | 0 | &image->bits, TRUE, x, y, width, buffer); |
881 | 0 | } |
882 | 0 | else |
883 | 0 | { |
884 | 0 | bits_image_fetch_untransformed_repeat_normal ( |
885 | 0 | &image->bits, TRUE, x, y, width, buffer); |
886 | 0 | } |
887 | |
|
888 | 0 | iter->y++; |
889 | 0 | return buffer; |
890 | 0 | } |
891 | | |
892 | | typedef struct |
893 | | { |
894 | | pixman_format_code_t format; |
895 | | uint32_t flags; |
896 | | pixman_iter_get_scanline_t get_scanline_32; |
897 | | pixman_iter_get_scanline_t get_scanline_float; |
898 | | } fetcher_info_t; |
899 | | |
900 | | static const fetcher_info_t fetcher_info[] = |
901 | | { |
902 | | { PIXMAN_any, |
903 | | (FAST_PATH_NO_ALPHA_MAP | |
904 | | FAST_PATH_ID_TRANSFORM | |
905 | | FAST_PATH_NO_CONVOLUTION_FILTER | |
906 | | FAST_PATH_NO_PAD_REPEAT | |
907 | | FAST_PATH_NO_REFLECT_REPEAT), |
908 | | bits_image_fetch_untransformed_32, |
909 | | bits_image_fetch_untransformed_float |
910 | | }, |
911 | | |
912 | | /* Affine, no alpha */ |
913 | | { PIXMAN_any, |
914 | | (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM), |
915 | | bits_image_fetch_affine_no_alpha_32, |
916 | | bits_image_fetch_affine_no_alpha_float, |
917 | | }, |
918 | | |
919 | | /* General */ |
920 | | { PIXMAN_any, |
921 | | 0, |
922 | | bits_image_fetch_general_32, |
923 | | bits_image_fetch_general_float, |
924 | | }, |
925 | | |
926 | | { PIXMAN_null }, |
927 | | }; |
928 | | |
929 | | static void |
930 | | bits_image_property_changed (pixman_image_t *image) |
931 | 37.0k | { |
932 | 37.0k | _pixman_bits_image_setup_accessors (&image->bits); |
933 | 37.0k | } |
934 | | |
935 | | void |
936 | | _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
937 | 0 | { |
938 | 0 | pixman_format_code_t format = image->common.extended_format_code; |
939 | 0 | uint32_t flags = image->common.flags; |
940 | 0 | const fetcher_info_t *info; |
941 | |
|
942 | 0 | for (info = fetcher_info; info->format != PIXMAN_null; ++info) |
943 | 0 | { |
944 | 0 | if ((info->format == format || info->format == PIXMAN_any) && |
945 | 0 | (info->flags & flags) == info->flags) |
946 | 0 | { |
947 | 0 | if (iter->iter_flags & ITER_NARROW) |
948 | 0 | { |
949 | 0 | iter->get_scanline = info->get_scanline_32; |
950 | 0 | } |
951 | 0 | else |
952 | 0 | { |
953 | 0 | iter->get_scanline = info->get_scanline_float; |
954 | 0 | } |
955 | 0 | return; |
956 | 0 | } |
957 | 0 | } |
958 | | |
959 | | /* Just in case we somehow didn't find a scanline function */ |
960 | 0 | iter->get_scanline = _pixman_iter_get_scanline_noop; |
961 | 0 | } |
962 | | |
963 | | static uint32_t * |
964 | | dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) |
965 | 0 | { |
966 | 0 | pixman_image_t *image = iter->image; |
967 | 0 | int x = iter->x; |
968 | 0 | int y = iter->y; |
969 | 0 | int width = iter->width; |
970 | 0 | uint32_t * buffer = iter->buffer; |
971 | |
|
972 | 0 | image->bits.fetch_scanline_32 (&image->bits, x, y, width, buffer, mask); |
973 | 0 | if (image->common.alpha_map) |
974 | 0 | { |
975 | 0 | uint32_t *alpha; |
976 | |
|
977 | 0 | if ((alpha = malloc (width * sizeof (uint32_t)))) |
978 | 0 | { |
979 | 0 | int i; |
980 | |
|
981 | 0 | x -= image->common.alpha_origin_x; |
982 | 0 | y -= image->common.alpha_origin_y; |
983 | |
|
984 | 0 | image->common.alpha_map->fetch_scanline_32 ( |
985 | 0 | image->common.alpha_map, x, y, width, alpha, mask); |
986 | |
|
987 | 0 | for (i = 0; i < width; ++i) |
988 | 0 | { |
989 | 0 | buffer[i] &= ~0xff000000; |
990 | 0 | buffer[i] |= (alpha[i] & 0xff000000); |
991 | 0 | } |
992 | |
|
993 | 0 | free (alpha); |
994 | 0 | } |
995 | 0 | } |
996 | |
|
997 | 0 | return iter->buffer; |
998 | 0 | } |
999 | | |
1000 | | static uint32_t * |
1001 | | dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
1002 | 0 | { |
1003 | 0 | bits_image_t * image = &iter->image->bits; |
1004 | 0 | int x = iter->x; |
1005 | 0 | int y = iter->y; |
1006 | 0 | int width = iter->width; |
1007 | 0 | argb_t * buffer = (argb_t *)iter->buffer; |
1008 | |
|
1009 | 0 | image->fetch_scanline_float ( |
1010 | 0 | image, x, y, width, (uint32_t *)buffer, mask); |
1011 | 0 | if (image->common.alpha_map) |
1012 | 0 | { |
1013 | 0 | argb_t *alpha; |
1014 | |
|
1015 | 0 | if ((alpha = malloc (width * sizeof (argb_t)))) |
1016 | 0 | { |
1017 | 0 | int i; |
1018 | |
|
1019 | 0 | x -= image->common.alpha_origin_x; |
1020 | 0 | y -= image->common.alpha_origin_y; |
1021 | |
|
1022 | 0 | image->common.alpha_map->fetch_scanline_float ( |
1023 | 0 | image->common.alpha_map, x, y, width, (uint32_t *)alpha, mask); |
1024 | |
|
1025 | 0 | for (i = 0; i < width; ++i) |
1026 | 0 | buffer[i].a = alpha[i].a; |
1027 | |
|
1028 | 0 | free (alpha); |
1029 | 0 | } |
1030 | 0 | } |
1031 | |
|
1032 | 0 | return iter->buffer; |
1033 | 0 | } |
1034 | | |
1035 | | static void |
1036 | | dest_write_back_narrow (pixman_iter_t *iter) |
1037 | 0 | { |
1038 | 0 | bits_image_t * image = &iter->image->bits; |
1039 | 0 | int x = iter->x; |
1040 | 0 | int y = iter->y; |
1041 | 0 | int width = iter->width; |
1042 | 0 | const uint32_t *buffer = iter->buffer; |
1043 | |
|
1044 | 0 | image->store_scanline_32 (image, x, y, width, buffer); |
1045 | |
|
1046 | 0 | if (image->common.alpha_map) |
1047 | 0 | { |
1048 | 0 | x -= image->common.alpha_origin_x; |
1049 | 0 | y -= image->common.alpha_origin_y; |
1050 | |
|
1051 | 0 | image->common.alpha_map->store_scanline_32 ( |
1052 | 0 | image->common.alpha_map, x, y, width, buffer); |
1053 | 0 | } |
1054 | |
|
1055 | 0 | iter->y++; |
1056 | 0 | } |
1057 | | |
1058 | | static float |
1059 | | dither_factor_blue_noise_64 (int x, int y) |
1060 | 0 | { |
1061 | 0 | float m = dither_blue_noise_64x64[((y & 0x3f) << 6) | (x & 0x3f)]; |
1062 | 0 | return m * (1. / 4096.f) + (1. / 8192.f); |
1063 | 0 | } |
1064 | | |
1065 | | static float |
1066 | | dither_factor_bayer_8 (int x, int y) |
1067 | 0 | { |
1068 | 0 | uint32_t m; |
1069 | |
|
1070 | 0 | y ^= x; |
1071 | | |
1072 | | /* Compute reverse(interleave(xor(x mod n, y mod n), x mod n)) |
1073 | | * Here n = 8 and `mod n` is the bottom 3 bits. |
1074 | | */ |
1075 | 0 | m = ((y & 0x1) << 5) | ((x & 0x1) << 4) | |
1076 | 0 | ((y & 0x2) << 2) | ((x & 0x2) << 1) | |
1077 | 0 | ((y & 0x4) >> 1) | ((x & 0x4) >> 2); |
1078 | | |
1079 | | /* m is in range [0, 63]. We scale it to [0, 63.0f/64.0f], then |
1080 | | * shift it to to [1.0f/128.0f, 127.0f/128.0f] so that 0 < d < 1. |
1081 | | * This ensures exact values are not changed by dithering. |
1082 | | */ |
1083 | 0 | return (float)(m) * (1 / 64.0f) + (1.0f / 128.0f); |
1084 | 0 | } |
1085 | | |
1086 | | typedef float (* dither_factor_t)(int x, int y); |
1087 | | |
1088 | | static force_inline float |
1089 | | dither_apply_channel (float f, float d, float s) |
1090 | 0 | { |
1091 | | /* float_to_unorm splits the [0, 1] segment in (1 << n_bits) |
1092 | | * subsections of equal length; however unorm_to_float does not |
1093 | | * map to the center of those sections. In fact, pixel value u is |
1094 | | * mapped to: |
1095 | | * |
1096 | | * u u u 1 |
1097 | | * -------------- = ---------- + -------------- * ---------- |
1098 | | * 2^n_bits - 1 2^n_bits 2^n_bits - 1 2^n_bits |
1099 | | * |
1100 | | * Hence if f = u / (2^n_bits - 1) is exactly representable on a |
1101 | | * n_bits palette, all the numbers between |
1102 | | * |
1103 | | * u |
1104 | | * ---------- = f - f * 2^n_bits = f + (0 - f) * 2^n_bits |
1105 | | * 2^n_bits |
1106 | | * |
1107 | | * and |
1108 | | * |
1109 | | * u + 1 |
1110 | | * ---------- = f - (f - 1) * 2^n_bits = f + (1 - f) * 2^n_bits |
1111 | | * 2^n_bits |
1112 | | * |
1113 | | * are also mapped back to u. |
1114 | | * |
1115 | | * Hence the following calculation ensures that we add as much |
1116 | | * noise as possible without perturbing values which are exactly |
1117 | | * representable in the target colorspace. Note that this corresponds to |
1118 | | * mixing the original color with noise with a ratio of `1 / 2^n_bits`. |
1119 | | */ |
1120 | 0 | return f + (d - f) * s; |
1121 | 0 | } |
1122 | | |
1123 | | static force_inline float |
1124 | | dither_compute_scale (int n_bits) |
1125 | 0 | { |
1126 | | // No dithering for wide formats |
1127 | 0 | if (n_bits == 0 || n_bits >= 32) |
1128 | 0 | return 0.f; |
1129 | | |
1130 | 0 | return 1.f / (float)(1 << n_bits); |
1131 | 0 | } |
1132 | | |
1133 | | static const uint32_t * |
1134 | | dither_apply_ordered (pixman_iter_t *iter, dither_factor_t factor) |
1135 | 0 | { |
1136 | 0 | bits_image_t *image = &iter->image->bits; |
1137 | 0 | int x = iter->x + image->dither_offset_x; |
1138 | 0 | int y = iter->y + image->dither_offset_y; |
1139 | 0 | int width = iter->width; |
1140 | 0 | argb_t *buffer = (argb_t *)iter->buffer; |
1141 | |
|
1142 | 0 | pixman_format_code_t format = image->format; |
1143 | 0 | int a_size = PIXMAN_FORMAT_A (format); |
1144 | 0 | int r_size = PIXMAN_FORMAT_R (format); |
1145 | 0 | int g_size = PIXMAN_FORMAT_G (format); |
1146 | 0 | int b_size = PIXMAN_FORMAT_B (format); |
1147 | |
|
1148 | 0 | float a_scale = dither_compute_scale (a_size); |
1149 | 0 | float r_scale = dither_compute_scale (r_size); |
1150 | 0 | float g_scale = dither_compute_scale (g_size); |
1151 | 0 | float b_scale = dither_compute_scale (b_size); |
1152 | |
|
1153 | 0 | int i; |
1154 | 0 | float d; |
1155 | |
|
1156 | 0 | for (i = 0; i < width; ++i) |
1157 | 0 | { |
1158 | 0 | d = factor (x + i, y); |
1159 | |
|
1160 | 0 | buffer->a = dither_apply_channel (buffer->a, d, a_scale); |
1161 | 0 | buffer->r = dither_apply_channel (buffer->r, d, r_scale); |
1162 | 0 | buffer->g = dither_apply_channel (buffer->g, d, g_scale); |
1163 | 0 | buffer->b = dither_apply_channel (buffer->b, d, b_scale); |
1164 | |
|
1165 | 0 | buffer++; |
1166 | 0 | } |
1167 | |
|
1168 | 0 | return iter->buffer; |
1169 | 0 | } |
1170 | | |
1171 | | static void |
1172 | | dest_write_back_wide (pixman_iter_t *iter) |
1173 | 0 | { |
1174 | 0 | bits_image_t * image = &iter->image->bits; |
1175 | 0 | int x = iter->x; |
1176 | 0 | int y = iter->y; |
1177 | 0 | int width = iter->width; |
1178 | 0 | const uint32_t *buffer = iter->buffer; |
1179 | |
|
1180 | 0 | switch (image->dither) |
1181 | 0 | { |
1182 | 0 | case PIXMAN_DITHER_NONE: |
1183 | 0 | break; |
1184 | | |
1185 | 0 | case PIXMAN_DITHER_GOOD: |
1186 | 0 | case PIXMAN_DITHER_BEST: |
1187 | 0 | case PIXMAN_DITHER_ORDERED_BLUE_NOISE_64: |
1188 | 0 | buffer = dither_apply_ordered (iter, dither_factor_blue_noise_64); |
1189 | 0 | break; |
1190 | | |
1191 | 0 | case PIXMAN_DITHER_FAST: |
1192 | 0 | case PIXMAN_DITHER_ORDERED_BAYER_8: |
1193 | 0 | buffer = dither_apply_ordered (iter, dither_factor_bayer_8); |
1194 | 0 | break; |
1195 | 0 | } |
1196 | | |
1197 | 0 | image->store_scanline_float (image, x, y, width, buffer); |
1198 | |
|
1199 | 0 | if (image->common.alpha_map) |
1200 | 0 | { |
1201 | 0 | x -= image->common.alpha_origin_x; |
1202 | 0 | y -= image->common.alpha_origin_y; |
1203 | |
|
1204 | 0 | image->common.alpha_map->store_scanline_float ( |
1205 | 0 | image->common.alpha_map, x, y, width, buffer); |
1206 | 0 | } |
1207 | |
|
1208 | 0 | iter->y++; |
1209 | 0 | } |
1210 | | |
1211 | | void |
1212 | | _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
1213 | 0 | { |
1214 | 0 | if (iter->iter_flags & ITER_NARROW) |
1215 | 0 | { |
1216 | 0 | if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == |
1217 | 0 | (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) |
1218 | 0 | { |
1219 | 0 | iter->get_scanline = _pixman_iter_get_scanline_noop; |
1220 | 0 | } |
1221 | 0 | else |
1222 | 0 | { |
1223 | 0 | iter->get_scanline = dest_get_scanline_narrow; |
1224 | 0 | } |
1225 | | |
1226 | 0 | iter->write_back = dest_write_back_narrow; |
1227 | 0 | } |
1228 | 0 | else |
1229 | 0 | { |
1230 | 0 | iter->get_scanline = dest_get_scanline_wide; |
1231 | 0 | iter->write_back = dest_write_back_wide; |
1232 | 0 | } |
1233 | 0 | } |
1234 | | |
1235 | | static uint32_t * |
1236 | | create_bits (pixman_format_code_t format, |
1237 | | int width, |
1238 | | int height, |
1239 | | int * rowstride_bytes, |
1240 | | pixman_bool_t clear) |
1241 | 73.6k | { |
1242 | 73.6k | int stride; |
1243 | 73.6k | size_t buf_size; |
1244 | 73.6k | int bpp; |
1245 | | |
1246 | | /* what follows is a long-winded way, avoiding any possibility of integer |
1247 | | * overflows, of saying: |
1248 | | * stride = ((width * bpp + 0x1f) >> 5) * sizeof (uint32_t); |
1249 | | */ |
1250 | | |
1251 | 73.6k | bpp = PIXMAN_FORMAT_BPP (format); |
1252 | 73.6k | if (_pixman_multiply_overflows_int (width, bpp)) |
1253 | 0 | return NULL; |
1254 | | |
1255 | 73.6k | stride = width * bpp; |
1256 | 73.6k | if (_pixman_addition_overflows_int (stride, 0x1f)) |
1257 | 0 | return NULL; |
1258 | | |
1259 | 73.6k | stride += 0x1f; |
1260 | 73.6k | stride >>= 5; |
1261 | | |
1262 | 73.6k | stride *= sizeof (uint32_t); |
1263 | | |
1264 | 73.6k | if (_pixman_multiply_overflows_size (height, stride)) |
1265 | 0 | return NULL; |
1266 | | |
1267 | 73.6k | buf_size = (size_t)height * stride; |
1268 | | |
1269 | 73.6k | if (rowstride_bytes) |
1270 | 73.6k | *rowstride_bytes = stride; |
1271 | | |
1272 | 73.6k | if (clear) |
1273 | 73.6k | return calloc (1, buf_size); |
1274 | 0 | else |
1275 | 0 | return malloc (buf_size); |
1276 | 73.6k | } |
1277 | | |
1278 | | pixman_bool_t |
1279 | | _pixman_bits_image_init (pixman_image_t * image, |
1280 | | pixman_format_code_t format, |
1281 | | int width, |
1282 | | int height, |
1283 | | uint32_t * bits, |
1284 | | int rowstride, |
1285 | | pixman_bool_t clear) |
1286 | 93.2k | { |
1287 | 93.2k | uint32_t *free_me = NULL; |
1288 | | |
1289 | 93.2k | if (PIXMAN_FORMAT_BPP (format) == 128) |
1290 | 26 | return_val_if_fail(!(rowstride % 4), FALSE); |
1291 | | |
1292 | 93.2k | if (!bits && width && height) |
1293 | 73.6k | { |
1294 | 73.6k | int rowstride_bytes; |
1295 | | |
1296 | 73.6k | free_me = bits = create_bits (format, width, height, &rowstride_bytes, clear); |
1297 | | |
1298 | 73.6k | if (!bits) |
1299 | 0 | return FALSE; |
1300 | | |
1301 | 73.6k | rowstride = rowstride_bytes / (int) sizeof (uint32_t); |
1302 | 73.6k | } |
1303 | | |
1304 | 93.2k | _pixman_image_init (image); |
1305 | | |
1306 | 93.2k | image->type = BITS; |
1307 | 93.2k | image->bits.format = format; |
1308 | 93.2k | image->bits.width = width; |
1309 | 93.2k | image->bits.height = height; |
1310 | 93.2k | image->bits.bits = bits; |
1311 | 93.2k | image->bits.free_me = free_me; |
1312 | 93.2k | image->bits.dither = PIXMAN_DITHER_NONE; |
1313 | 93.2k | image->bits.dither_offset_x = 0; |
1314 | 93.2k | image->bits.dither_offset_y = 0; |
1315 | 93.2k | image->bits.read_func = NULL; |
1316 | 93.2k | image->bits.write_func = NULL; |
1317 | 93.2k | image->bits.rowstride = rowstride; |
1318 | 93.2k | image->bits.indexed = NULL; |
1319 | | |
1320 | 93.2k | image->common.property_changed = bits_image_property_changed; |
1321 | | |
1322 | 93.2k | _pixman_image_reset_clip_region (image); |
1323 | | |
1324 | 93.2k | return TRUE; |
1325 | 93.2k | } |
1326 | | |
1327 | | static pixman_image_t * |
1328 | | create_bits_image_internal (pixman_format_code_t format, |
1329 | | int width, |
1330 | | int height, |
1331 | | uint32_t * bits, |
1332 | | int rowstride_bytes, |
1333 | | pixman_bool_t clear) |
1334 | 93.2k | { |
1335 | 93.2k | pixman_image_t *image; |
1336 | | |
1337 | | /* must be a whole number of uint32_t's |
1338 | | */ |
1339 | 93.2k | return_val_if_fail ( |
1340 | 93.2k | bits == NULL || (rowstride_bytes % sizeof (uint32_t)) == 0, NULL); |
1341 | | |
1342 | 93.2k | return_val_if_fail (PIXMAN_FORMAT_BPP (format) >= PIXMAN_FORMAT_DEPTH (format), NULL); |
1343 | | |
1344 | 93.2k | image = _pixman_image_allocate (); |
1345 | | |
1346 | 93.2k | if (!image) |
1347 | 0 | return NULL; |
1348 | | |
1349 | 93.2k | if (!_pixman_bits_image_init (image, format, width, height, bits, |
1350 | 93.2k | rowstride_bytes / (int) sizeof (uint32_t), |
1351 | 93.2k | clear)) |
1352 | 2 | { |
1353 | 2 | free (image); |
1354 | 2 | return NULL; |
1355 | 2 | } |
1356 | | |
1357 | 93.2k | return image; |
1358 | 93.2k | } |
1359 | | |
1360 | | /* If bits is NULL, a buffer will be allocated and initialized to 0 */ |
1361 | | PIXMAN_EXPORT pixman_image_t * |
1362 | | pixman_image_create_bits (pixman_format_code_t format, |
1363 | | int width, |
1364 | | int height, |
1365 | | uint32_t * bits, |
1366 | | int rowstride_bytes) |
1367 | 93.2k | { |
1368 | 93.2k | return create_bits_image_internal ( |
1369 | 93.2k | format, width, height, bits, rowstride_bytes, TRUE); |
1370 | 93.2k | } |
1371 | | |
1372 | | |
1373 | | /* If bits is NULL, a buffer will be allocated and _not_ initialized */ |
1374 | | PIXMAN_EXPORT pixman_image_t * |
1375 | | pixman_image_create_bits_no_clear (pixman_format_code_t format, |
1376 | | int width, |
1377 | | int height, |
1378 | | uint32_t * bits, |
1379 | | int rowstride_bytes) |
1380 | 0 | { |
1381 | 0 | return create_bits_image_internal ( |
1382 | 0 | format, width, height, bits, rowstride_bytes, FALSE); |
1383 | 0 | } |