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 <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 :
38 : /*
39 : * By default, just evaluate the image at 32bpp and expand. Individual image
40 : * types can plug in a better scanline getter if they want to. For example
41 : * we could produce smoother gradients by evaluating them at higher color
42 : * depth, but that's a project for the future.
43 : */
44 : static void
45 0 : _pixman_image_get_scanline_generic_64 (pixman_image_t * image,
46 : int x,
47 : int y,
48 : int width,
49 : uint32_t * buffer,
50 : const uint32_t * mask)
51 : {
52 0 : uint32_t *mask8 = NULL;
53 :
54 : /* Contract the mask image, if one exists, so that the 32-bit fetch
55 : * function can use it.
56 : */
57 0 : if (mask)
58 : {
59 0 : mask8 = pixman_malloc_ab (width, sizeof(uint32_t));
60 0 : if (!mask8)
61 0 : return;
62 :
63 0 : pixman_contract (mask8, (uint64_t *)mask, width);
64 : }
65 :
66 : /* Fetch the source image into the first half of buffer. */
67 0 : image->bits.get_scanline_32 (image, x, y, width, (uint32_t*)buffer, mask8);
68 :
69 : /* Expand from 32bpp to 64bpp in place. */
70 0 : pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, width);
71 :
72 0 : free (mask8);
73 : }
74 :
75 : /* Fetch functions */
76 :
77 : static force_inline uint32_t
78 0 : fetch_pixel_no_alpha (bits_image_t *image,
79 : int x, int y, pixman_bool_t check_bounds)
80 : {
81 0 : if (check_bounds &&
82 0 : (x < 0 || x >= image->width || y < 0 || y >= image->height))
83 : {
84 0 : return 0;
85 : }
86 :
87 0 : return image->fetch_pixel_32 (image, x, y);
88 : }
89 :
90 : typedef uint32_t (* get_pixel_t) (bits_image_t *image,
91 : int x, int y, pixman_bool_t check_bounds);
92 :
93 : static force_inline void
94 : repeat (pixman_repeat_t repeat, int size, int *coord)
95 : {
96 0 : switch (repeat)
97 : {
98 : case PIXMAN_REPEAT_NORMAL:
99 0 : *coord = MOD (*coord, size);
100 : break;
101 :
102 : case PIXMAN_REPEAT_PAD:
103 0 : *coord = CLIP (*coord, 0, size - 1);
104 : break;
105 :
106 : case PIXMAN_REPEAT_REFLECT:
107 0 : *coord = MOD (*coord, size * 2);
108 :
109 0 : if (*coord >= size)
110 0 : *coord = size * 2 - *coord - 1;
111 : break;
112 :
113 : case PIXMAN_REPEAT_NONE:
114 : break;
115 :
116 : default:
117 : break;
118 : }
119 : }
120 :
121 : static force_inline uint32_t
122 : bits_image_fetch_pixel_nearest (bits_image_t *image,
123 : pixman_fixed_t x,
124 : pixman_fixed_t y,
125 : get_pixel_t get_pixel)
126 : {
127 0 : int x0 = pixman_fixed_to_int (x - pixman_fixed_e);
128 0 : int y0 = pixman_fixed_to_int (y - pixman_fixed_e);
129 :
130 0 : if (image->common.repeat != PIXMAN_REPEAT_NONE)
131 : {
132 0 : repeat (image->common.repeat, image->width, &x0);
133 0 : repeat (image->common.repeat, image->height, &y0);
134 :
135 0 : return get_pixel (image, x0, y0, FALSE);
136 : }
137 : else
138 : {
139 0 : return get_pixel (image, x0, y0, TRUE);
140 : }
141 : }
142 :
143 : #if SIZEOF_LONG > 4
144 :
145 : static force_inline uint32_t
146 : bilinear_interpolation (uint32_t tl, uint32_t tr,
147 : uint32_t bl, uint32_t br,
148 : int distx, int disty)
149 : {
150 : uint64_t distxy, distxiy, distixy, distixiy;
151 : uint64_t tl64, tr64, bl64, br64;
152 : uint64_t f, r;
153 :
154 : distxy = distx * disty;
155 : distxiy = distx * (256 - disty);
156 : distixy = (256 - distx) * disty;
157 : distixiy = (256 - distx) * (256 - disty);
158 :
159 : /* Alpha and Blue */
160 : tl64 = tl & 0xff0000ff;
161 : tr64 = tr & 0xff0000ff;
162 : bl64 = bl & 0xff0000ff;
163 : br64 = br & 0xff0000ff;
164 :
165 : f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
166 : r = f & 0x0000ff0000ff0000ull;
167 :
168 : /* Red and Green */
169 : tl64 = tl;
170 : tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
171 :
172 : tr64 = tr;
173 : tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
174 :
175 : bl64 = bl;
176 : bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
177 :
178 : br64 = br;
179 : br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
180 :
181 : f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
182 : r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
183 :
184 : return (uint32_t)(r >> 16);
185 : }
186 :
187 : #else
188 :
189 : static force_inline uint32_t
190 : bilinear_interpolation (uint32_t tl, uint32_t tr,
191 : uint32_t bl, uint32_t br,
192 : int distx, int disty)
193 : {
194 : int distxy, distxiy, distixy, distixiy;
195 : uint32_t f, r;
196 :
197 0 : distxy = distx * disty;
198 0 : distxiy = (distx << 8) - distxy; /* distx * (256 - disty) */
199 0 : distixy = (disty << 8) - distxy; /* disty * (256 - distx) */
200 0 : distixiy =
201 0 : 256 * 256 - (disty << 8) -
202 0 : (distx << 8) + distxy; /* (256 - distx) * (256 - disty) */
203 :
204 : /* Blue */
205 0 : r = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
206 0 : + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
207 :
208 : /* Green */
209 0 : f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
210 0 : + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
211 0 : r |= f & 0xff000000;
212 :
213 0 : tl >>= 16;
214 0 : tr >>= 16;
215 0 : bl >>= 16;
216 0 : br >>= 16;
217 0 : r >>= 16;
218 :
219 : /* Red */
220 0 : f = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
221 0 : + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
222 0 : r |= f & 0x00ff0000;
223 :
224 : /* Alpha */
225 0 : f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
226 0 : + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
227 0 : r |= f & 0xff000000;
228 :
229 0 : return r;
230 : }
231 :
232 : #endif
233 :
234 : static force_inline uint32_t
235 : bits_image_fetch_pixel_bilinear (bits_image_t *image,
236 : pixman_fixed_t x,
237 : pixman_fixed_t y,
238 : get_pixel_t get_pixel)
239 : {
240 0 : pixman_repeat_t repeat_mode = image->common.repeat;
241 0 : int width = image->width;
242 0 : int height = image->height;
243 : int x1, y1, x2, y2;
244 : uint32_t tl, tr, bl, br;
245 : int32_t distx, disty;
246 :
247 0 : x1 = x - pixman_fixed_1 / 2;
248 0 : y1 = y - pixman_fixed_1 / 2;
249 :
250 0 : distx = (x1 >> 8) & 0xff;
251 0 : disty = (y1 >> 8) & 0xff;
252 :
253 0 : x1 = pixman_fixed_to_int (x1);
254 0 : y1 = pixman_fixed_to_int (y1);
255 0 : x2 = x1 + 1;
256 0 : y2 = y1 + 1;
257 :
258 0 : if (repeat_mode != PIXMAN_REPEAT_NONE)
259 : {
260 : repeat (repeat_mode, width, &x1);
261 : repeat (repeat_mode, height, &y1);
262 : repeat (repeat_mode, width, &x2);
263 : repeat (repeat_mode, height, &y2);
264 :
265 0 : tl = get_pixel (image, x1, y1, FALSE);
266 0 : bl = get_pixel (image, x1, y2, FALSE);
267 0 : tr = get_pixel (image, x2, y1, FALSE);
268 0 : br = get_pixel (image, x2, y2, FALSE);
269 : }
270 : else
271 : {
272 0 : tl = get_pixel (image, x1, y1, TRUE);
273 0 : tr = get_pixel (image, x2, y1, TRUE);
274 0 : bl = get_pixel (image, x1, y2, TRUE);
275 0 : br = get_pixel (image, x2, y2, TRUE);
276 : }
277 :
278 : return bilinear_interpolation (tl, tr, bl, br, distx, disty);
279 : }
280 :
281 : static void
282 0 : bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
283 : int offset,
284 : int line,
285 : int width,
286 : uint32_t * buffer,
287 : const uint32_t * mask)
288 : {
289 0 : bits_image_t *bits = &ima->bits;
290 : pixman_fixed_t x_top, x_bottom, x;
291 : pixman_fixed_t ux_top, ux_bottom, ux;
292 : pixman_vector_t v;
293 : uint32_t top_mask, bottom_mask;
294 : uint32_t *top_row;
295 : uint32_t *bottom_row;
296 : uint32_t *end;
297 0 : uint32_t zero[2] = { 0, 0 };
298 0 : uint32_t one = 1;
299 : int y, y1, y2;
300 : int disty;
301 : int mask_inc;
302 : int w;
303 :
304 : /* reference point is the center of the pixel */
305 0 : v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
306 0 : v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
307 0 : v.vector[2] = pixman_fixed_1;
308 :
309 0 : if (!pixman_transform_point_3d (bits->common.transform, &v))
310 0 : return;
311 :
312 0 : ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0];
313 0 : x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2;
314 :
315 0 : y = v.vector[1] - pixman_fixed_1/2;
316 0 : disty = (y >> 8) & 0xff;
317 :
318 : /* Load the pointers to the first and second lines from the source
319 : * image that bilinear code must read.
320 : *
321 : * The main trick in this code is about the check if any line are
322 : * outside of the image;
323 : *
324 : * When I realize that a line (any one) is outside, I change
325 : * the pointer to a dummy area with zeros. Once I change this, I
326 : * must be sure the pointer will not change, so I set the
327 : * variables to each pointer increments inside the loop.
328 : */
329 0 : y1 = pixman_fixed_to_int (y);
330 0 : y2 = y1 + 1;
331 :
332 0 : if (y1 < 0 || y1 >= bits->height)
333 : {
334 0 : top_row = zero;
335 0 : x_top = 0;
336 0 : ux_top = 0;
337 : }
338 : else
339 : {
340 0 : top_row = bits->bits + y1 * bits->rowstride;
341 0 : x_top = x;
342 0 : ux_top = ux;
343 : }
344 :
345 0 : if (y2 < 0 || y2 >= bits->height)
346 : {
347 0 : bottom_row = zero;
348 0 : x_bottom = 0;
349 0 : ux_bottom = 0;
350 : }
351 : else
352 : {
353 0 : bottom_row = bits->bits + y2 * bits->rowstride;
354 0 : x_bottom = x;
355 0 : ux_bottom = ux;
356 : }
357 :
358 : /* Instead of checking whether the operation uses the mast in
359 : * each loop iteration, verify this only once and prepare the
360 : * variables to make the code smaller inside the loop.
361 : */
362 0 : if (!mask)
363 : {
364 0 : mask_inc = 0;
365 0 : mask = &one;
366 : }
367 : else
368 : {
369 : /* If have a mask, prepare the variables to check it */
370 0 : mask_inc = 1;
371 : }
372 :
373 : /* If both are zero, then the whole thing is zero */
374 0 : if (top_row == zero && bottom_row == zero)
375 : {
376 0 : memset (buffer, 0, width * sizeof (uint32_t));
377 0 : return;
378 : }
379 0 : else if (bits->format == PIXMAN_x8r8g8b8)
380 : {
381 0 : if (top_row == zero)
382 : {
383 0 : top_mask = 0;
384 0 : bottom_mask = 0xff000000;
385 : }
386 0 : else if (bottom_row == zero)
387 : {
388 0 : top_mask = 0xff000000;
389 0 : bottom_mask = 0;
390 : }
391 : else
392 : {
393 0 : top_mask = 0xff000000;
394 0 : bottom_mask = 0xff000000;
395 : }
396 : }
397 : else
398 : {
399 0 : top_mask = 0;
400 0 : bottom_mask = 0;
401 : }
402 :
403 0 : end = buffer + width;
404 :
405 : /* Zero fill to the left of the image */
406 0 : while (buffer < end && x < pixman_fixed_minus_1)
407 : {
408 0 : *buffer++ = 0;
409 0 : x += ux;
410 0 : x_top += ux_top;
411 0 : x_bottom += ux_bottom;
412 0 : mask += mask_inc;
413 : }
414 :
415 : /* Left edge
416 : */
417 0 : while (buffer < end && x < 0)
418 : {
419 : uint32_t tr, br;
420 : int32_t distx;
421 :
422 0 : tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask;
423 0 : br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask;
424 :
425 0 : distx = (x >> 8) & 0xff;
426 :
427 0 : *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty);
428 :
429 0 : x += ux;
430 0 : x_top += ux_top;
431 0 : x_bottom += ux_bottom;
432 0 : mask += mask_inc;
433 : }
434 :
435 : /* Main part */
436 0 : w = pixman_int_to_fixed (bits->width - 1);
437 :
438 0 : while (buffer < end && x < w)
439 : {
440 0 : if (*mask)
441 : {
442 : uint32_t tl, tr, bl, br;
443 : int32_t distx;
444 :
445 0 : tl = top_row [pixman_fixed_to_int (x_top)] | top_mask;
446 0 : tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask;
447 0 : bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask;
448 0 : br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask;
449 :
450 0 : distx = (x >> 8) & 0xff;
451 :
452 0 : *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty);
453 : }
454 :
455 0 : buffer++;
456 0 : x += ux;
457 0 : x_top += ux_top;
458 0 : x_bottom += ux_bottom;
459 0 : mask += mask_inc;
460 : }
461 :
462 : /* Right Edge */
463 0 : w = pixman_int_to_fixed (bits->width);
464 0 : while (buffer < end && x < w)
465 : {
466 0 : if (*mask)
467 : {
468 : uint32_t tl, bl;
469 : int32_t distx;
470 :
471 0 : tl = top_row [pixman_fixed_to_int (x_top)] | top_mask;
472 0 : bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask;
473 :
474 0 : distx = (x >> 8) & 0xff;
475 :
476 0 : *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty);
477 : }
478 :
479 0 : buffer++;
480 0 : x += ux;
481 0 : x_top += ux_top;
482 0 : x_bottom += ux_bottom;
483 0 : mask += mask_inc;
484 : }
485 :
486 : /* Zero fill to the left of the image */
487 0 : while (buffer < end)
488 0 : *buffer++ = 0;
489 : }
490 :
491 : static force_inline uint32_t
492 : bits_image_fetch_pixel_convolution (bits_image_t *image,
493 : pixman_fixed_t x,
494 : pixman_fixed_t y,
495 : get_pixel_t get_pixel)
496 : {
497 0 : pixman_fixed_t *params = image->common.filter_params;
498 0 : int x_off = (params[0] - pixman_fixed_1) >> 1;
499 0 : int y_off = (params[1] - pixman_fixed_1) >> 1;
500 0 : int32_t cwidth = pixman_fixed_to_int (params[0]);
501 0 : int32_t cheight = pixman_fixed_to_int (params[1]);
502 : int32_t srtot, sgtot, sbtot, satot;
503 : int32_t i, j, x1, x2, y1, y2;
504 0 : pixman_repeat_t repeat_mode = image->common.repeat;
505 0 : int width = image->width;
506 0 : int height = image->height;
507 :
508 0 : params += 2;
509 :
510 0 : x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
511 0 : y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
512 0 : x2 = x1 + cwidth;
513 0 : y2 = y1 + cheight;
514 :
515 0 : srtot = sgtot = sbtot = satot = 0;
516 :
517 0 : for (i = y1; i < y2; ++i)
518 : {
519 0 : for (j = x1; j < x2; ++j)
520 : {
521 0 : int rx = j;
522 0 : int ry = i;
523 :
524 0 : pixman_fixed_t f = *params;
525 :
526 0 : if (f)
527 : {
528 : uint32_t pixel;
529 :
530 0 : if (repeat_mode != PIXMAN_REPEAT_NONE)
531 : {
532 : repeat (repeat_mode, width, &rx);
533 : repeat (repeat_mode, height, &ry);
534 :
535 0 : pixel = get_pixel (image, rx, ry, FALSE);
536 : }
537 : else
538 : {
539 0 : pixel = get_pixel (image, rx, ry, TRUE);
540 : }
541 :
542 0 : srtot += RED_8 (pixel) * f;
543 0 : sgtot += GREEN_8 (pixel) * f;
544 0 : sbtot += BLUE_8 (pixel) * f;
545 0 : satot += ALPHA_8 (pixel) * f;
546 : }
547 :
548 0 : params++;
549 : }
550 : }
551 :
552 0 : satot >>= 16;
553 0 : srtot >>= 16;
554 0 : sgtot >>= 16;
555 0 : sbtot >>= 16;
556 :
557 0 : satot = CLIP (satot, 0, 0xff);
558 0 : srtot = CLIP (srtot, 0, 0xff);
559 0 : sgtot = CLIP (sgtot, 0, 0xff);
560 0 : sbtot = CLIP (sbtot, 0, 0xff);
561 :
562 0 : return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot));
563 : }
564 :
565 : static force_inline uint32_t
566 : bits_image_fetch_pixel_filtered (bits_image_t *image,
567 : pixman_fixed_t x,
568 : pixman_fixed_t y,
569 : get_pixel_t get_pixel)
570 : {
571 0 : switch (image->common.filter)
572 : {
573 : case PIXMAN_FILTER_NEAREST:
574 : case PIXMAN_FILTER_FAST:
575 : return bits_image_fetch_pixel_nearest (image, x, y, get_pixel);
576 : break;
577 :
578 : case PIXMAN_FILTER_BILINEAR:
579 : case PIXMAN_FILTER_GOOD:
580 : case PIXMAN_FILTER_BEST:
581 : return bits_image_fetch_pixel_bilinear (image, x, y, get_pixel);
582 : break;
583 :
584 : case PIXMAN_FILTER_CONVOLUTION:
585 : return bits_image_fetch_pixel_convolution (image, x, y, get_pixel);
586 : break;
587 :
588 : default:
589 : break;
590 : }
591 :
592 0 : return 0;
593 : }
594 :
595 : static void
596 0 : bits_image_fetch_affine_no_alpha (pixman_image_t * image,
597 : int offset,
598 : int line,
599 : int width,
600 : uint32_t * buffer,
601 : const uint32_t * mask)
602 : {
603 : pixman_fixed_t x, y;
604 : pixman_fixed_t ux, uy;
605 : pixman_vector_t v;
606 : int i;
607 :
608 : /* reference point is the center of the pixel */
609 0 : v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
610 0 : v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
611 0 : v.vector[2] = pixman_fixed_1;
612 :
613 0 : if (image->common.transform)
614 : {
615 0 : if (!pixman_transform_point_3d (image->common.transform, &v))
616 0 : return;
617 :
618 0 : ux = image->common.transform->matrix[0][0];
619 0 : uy = image->common.transform->matrix[1][0];
620 : }
621 : else
622 : {
623 0 : ux = pixman_fixed_1;
624 0 : uy = 0;
625 : }
626 :
627 0 : x = v.vector[0];
628 0 : y = v.vector[1];
629 :
630 0 : for (i = 0; i < width; ++i)
631 : {
632 0 : if (!mask || mask[i])
633 : {
634 0 : buffer[i] = bits_image_fetch_pixel_filtered (
635 : &image->bits, x, y, fetch_pixel_no_alpha);
636 : }
637 :
638 0 : x += ux;
639 0 : y += uy;
640 : }
641 : }
642 :
643 : /* General fetcher */
644 : static force_inline uint32_t
645 0 : fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds)
646 : {
647 : uint32_t pixel;
648 :
649 0 : if (check_bounds &&
650 0 : (x < 0 || x >= image->width || y < 0 || y >= image->height))
651 : {
652 0 : return 0;
653 : }
654 :
655 0 : pixel = image->fetch_pixel_32 (image, x, y);
656 :
657 0 : if (image->common.alpha_map)
658 : {
659 : uint32_t pixel_a;
660 :
661 0 : x -= image->common.alpha_origin_x;
662 0 : y -= image->common.alpha_origin_y;
663 :
664 0 : if (x < 0 || x >= image->common.alpha_map->width ||
665 0 : y < 0 || y >= image->common.alpha_map->height)
666 : {
667 0 : pixel_a = 0;
668 : }
669 : else
670 : {
671 0 : pixel_a = image->common.alpha_map->fetch_pixel_32 (
672 : image->common.alpha_map, x, y);
673 :
674 0 : pixel_a = ALPHA_8 (pixel_a);
675 : }
676 :
677 0 : pixel &= 0x00ffffff;
678 0 : pixel |= (pixel_a << 24);
679 : }
680 :
681 0 : return pixel;
682 : }
683 :
684 : static void
685 0 : bits_image_fetch_general (pixman_image_t * image,
686 : int offset,
687 : int line,
688 : int width,
689 : uint32_t * buffer,
690 : const uint32_t * mask)
691 : {
692 : pixman_fixed_t x, y, w;
693 : pixman_fixed_t ux, uy, uw;
694 : pixman_vector_t v;
695 : int i;
696 :
697 : /* reference point is the center of the pixel */
698 0 : v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
699 0 : v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
700 0 : v.vector[2] = pixman_fixed_1;
701 :
702 0 : if (image->common.transform)
703 : {
704 0 : if (!pixman_transform_point_3d (image->common.transform, &v))
705 0 : return;
706 :
707 0 : ux = image->common.transform->matrix[0][0];
708 0 : uy = image->common.transform->matrix[1][0];
709 0 : uw = image->common.transform->matrix[2][0];
710 : }
711 : else
712 : {
713 0 : ux = pixman_fixed_1;
714 0 : uy = 0;
715 0 : uw = 0;
716 : }
717 :
718 0 : x = v.vector[0];
719 0 : y = v.vector[1];
720 0 : w = v.vector[2];
721 :
722 0 : for (i = 0; i < width; ++i)
723 : {
724 : pixman_fixed_t x0, y0;
725 :
726 0 : if (!mask || mask[i])
727 : {
728 0 : if (w != 0)
729 : {
730 0 : x0 = ((pixman_fixed_48_16_t)x << 16) / w;
731 0 : y0 = ((pixman_fixed_48_16_t)y << 16) / w;
732 : }
733 : else
734 : {
735 0 : x0 = 0;
736 0 : y0 = 0;
737 : }
738 :
739 0 : buffer[i] = bits_image_fetch_pixel_filtered (
740 : &image->bits, x0, y0, fetch_pixel_general);
741 : }
742 :
743 0 : x += ux;
744 0 : y += uy;
745 0 : w += uw;
746 : }
747 : }
748 :
749 : static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
750 :
751 : typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x);
752 :
753 : static force_inline void
754 : bits_image_fetch_bilinear_affine (pixman_image_t * image,
755 : int offset,
756 : int line,
757 : int width,
758 : uint32_t * buffer,
759 : const uint32_t * mask,
760 :
761 : convert_pixel_t convert_pixel,
762 : pixman_format_code_t format,
763 : pixman_repeat_t repeat_mode)
764 : {
765 : pixman_fixed_t x, y;
766 : pixman_fixed_t ux, uy;
767 : pixman_vector_t v;
768 0 : bits_image_t *bits = &image->bits;
769 : int i;
770 :
771 : /* reference point is the center of the pixel */
772 0 : v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
773 0 : v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
774 0 : v.vector[2] = pixman_fixed_1;
775 :
776 0 : if (!pixman_transform_point_3d (image->common.transform, &v))
777 : return;
778 :
779 0 : ux = image->common.transform->matrix[0][0];
780 0 : uy = image->common.transform->matrix[1][0];
781 :
782 0 : x = v.vector[0];
783 0 : y = v.vector[1];
784 :
785 0 : for (i = 0; i < width; ++i)
786 : {
787 : int x1, y1, x2, y2;
788 : uint32_t tl, tr, bl, br;
789 : int32_t distx, disty;
790 0 : int width = image->bits.width;
791 0 : int height = image->bits.height;
792 : const uint8_t *row1;
793 : const uint8_t *row2;
794 :
795 0 : if (mask && !mask[i])
796 : goto next;
797 :
798 0 : x1 = x - pixman_fixed_1 / 2;
799 0 : y1 = y - pixman_fixed_1 / 2;
800 :
801 0 : distx = (x1 >> 8) & 0xff;
802 0 : disty = (y1 >> 8) & 0xff;
803 :
804 0 : y1 = pixman_fixed_to_int (y1);
805 0 : y2 = y1 + 1;
806 0 : x1 = pixman_fixed_to_int (x1);
807 0 : x2 = x1 + 1;
808 :
809 0 : if (repeat_mode != PIXMAN_REPEAT_NONE)
810 : {
811 : uint32_t mask;
812 :
813 0 : mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
814 :
815 : repeat (repeat_mode, width, &x1);
816 : repeat (repeat_mode, height, &y1);
817 : repeat (repeat_mode, width, &x2);
818 : repeat (repeat_mode, height, &y2);
819 :
820 0 : row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
821 0 : row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
822 :
823 0 : tl = convert_pixel (row1, x1) | mask;
824 0 : tr = convert_pixel (row1, x2) | mask;
825 0 : bl = convert_pixel (row2, x1) | mask;
826 0 : br = convert_pixel (row2, x2) | mask;
827 : }
828 : else
829 : {
830 : uint32_t mask1, mask2;
831 : int bpp;
832 :
833 : /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value,
834 : * which means if you use it in expressions, those
835 : * expressions become unsigned themselves. Since
836 : * the variables below can be negative in some cases,
837 : * that will lead to crashes on 64 bit architectures.
838 : *
839 : * So this line makes sure bpp is signed
840 : */
841 0 : bpp = PIXMAN_FORMAT_BPP (format);
842 :
843 0 : if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0)
844 : {
845 0 : buffer[i] = 0;
846 : goto next;
847 : }
848 :
849 0 : if (y2 == 0)
850 : {
851 0 : row1 = zero;
852 0 : mask1 = 0;
853 : }
854 : else
855 : {
856 0 : row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
857 0 : row1 += bpp / 8 * x1;
858 :
859 0 : mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
860 : }
861 :
862 0 : if (y1 == height - 1)
863 : {
864 0 : row2 = zero;
865 0 : mask2 = 0;
866 : }
867 : else
868 : {
869 0 : row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
870 0 : row2 += bpp / 8 * x1;
871 :
872 0 : mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
873 : }
874 :
875 0 : if (x2 == 0)
876 : {
877 0 : tl = 0;
878 0 : bl = 0;
879 : }
880 : else
881 : {
882 0 : tl = convert_pixel (row1, 0) | mask1;
883 0 : bl = convert_pixel (row2, 0) | mask2;
884 : }
885 :
886 0 : if (x1 == width - 1)
887 : {
888 0 : tr = 0;
889 0 : br = 0;
890 : }
891 : else
892 : {
893 0 : tr = convert_pixel (row1, 1) | mask1;
894 0 : br = convert_pixel (row2, 1) | mask2;
895 : }
896 : }
897 :
898 0 : buffer[i] = bilinear_interpolation (
899 : tl, tr, bl, br, distx, disty);
900 :
901 : next:
902 0 : x += ux;
903 0 : y += uy;
904 : }
905 : }
906 :
907 : static force_inline void
908 : bits_image_fetch_nearest_affine (pixman_image_t * image,
909 : int offset,
910 : int line,
911 : int width,
912 : uint32_t * buffer,
913 : const uint32_t * mask,
914 :
915 : convert_pixel_t convert_pixel,
916 : pixman_format_code_t format,
917 : pixman_repeat_t repeat_mode)
918 : {
919 : pixman_fixed_t x, y;
920 : pixman_fixed_t ux, uy;
921 : pixman_vector_t v;
922 0 : bits_image_t *bits = &image->bits;
923 : int i;
924 :
925 : /* reference point is the center of the pixel */
926 0 : v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
927 0 : v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
928 0 : v.vector[2] = pixman_fixed_1;
929 :
930 0 : if (!pixman_transform_point_3d (image->common.transform, &v))
931 : return;
932 :
933 0 : ux = image->common.transform->matrix[0][0];
934 0 : uy = image->common.transform->matrix[1][0];
935 :
936 0 : x = v.vector[0];
937 0 : y = v.vector[1];
938 :
939 0 : for (i = 0; i < width; ++i)
940 : {
941 : int width, height, x0, y0;
942 : const uint8_t *row;
943 :
944 0 : if (mask && !mask[i])
945 : goto next;
946 :
947 0 : width = image->bits.width;
948 0 : height = image->bits.height;
949 0 : x0 = pixman_fixed_to_int (x - pixman_fixed_e);
950 0 : y0 = pixman_fixed_to_int (y - pixman_fixed_e);
951 :
952 0 : if (repeat_mode == PIXMAN_REPEAT_NONE &&
953 0 : (y0 < 0 || y0 >= height || x0 < 0 || x0 >= width))
954 : {
955 0 : buffer[i] = 0;
956 : }
957 : else
958 : {
959 0 : uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
960 :
961 0 : if (repeat_mode != PIXMAN_REPEAT_NONE)
962 : {
963 : repeat (repeat_mode, width, &x0);
964 : repeat (repeat_mode, height, &y0);
965 : }
966 :
967 0 : row = (uint8_t *)bits->bits + bits->rowstride * 4 * y0;
968 :
969 0 : buffer[i] = convert_pixel (row, x0) | mask;
970 : }
971 :
972 : next:
973 0 : x += ux;
974 0 : y += uy;
975 : }
976 : }
977 :
978 : static force_inline uint32_t
979 0 : convert_a8r8g8b8 (const uint8_t *row, int x)
980 : {
981 0 : return *(((uint32_t *)row) + x);
982 : }
983 :
984 : static force_inline uint32_t
985 0 : convert_x8r8g8b8 (const uint8_t *row, int x)
986 : {
987 0 : return *(((uint32_t *)row) + x);
988 : }
989 :
990 : static force_inline uint32_t
991 0 : convert_a8 (const uint8_t *row, int x)
992 : {
993 0 : return *(row + x) << 24;
994 : }
995 :
996 : static force_inline uint32_t
997 0 : convert_r5g6b5 (const uint8_t *row, int x)
998 : {
999 0 : return CONVERT_0565_TO_0888 (*((uint16_t *)row + x));
1000 : }
1001 :
1002 : #define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \
1003 : static void \
1004 : bits_image_fetch_bilinear_affine_ ## name (pixman_image_t *image, \
1005 : int offset, \
1006 : int line, \
1007 : int width, \
1008 : uint32_t * buffer, \
1009 : const uint32_t * mask) \
1010 : { \
1011 : bits_image_fetch_bilinear_affine (image, offset, line, \
1012 : width, buffer, mask, \
1013 : convert_ ## format, \
1014 : PIXMAN_ ## format, \
1015 : repeat_mode); \
1016 : }
1017 :
1018 : #define MAKE_NEAREST_FETCHER(name, format, repeat_mode) \
1019 : static void \
1020 : bits_image_fetch_nearest_affine_ ## name (pixman_image_t *image, \
1021 : int offset, \
1022 : int line, \
1023 : int width, \
1024 : uint32_t * buffer, \
1025 : const uint32_t * mask) \
1026 : { \
1027 : bits_image_fetch_nearest_affine (image, offset, line, \
1028 : width, buffer, mask, \
1029 : convert_ ## format, \
1030 : PIXMAN_ ## format, \
1031 : repeat_mode); \
1032 : }
1033 :
1034 : #define MAKE_FETCHERS(name, format, repeat_mode) \
1035 : MAKE_NEAREST_FETCHER (name, format, repeat_mode) \
1036 : MAKE_BILINEAR_FETCHER (name, format, repeat_mode)
1037 :
1038 0 : MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD)
1039 0 : MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE)
1040 0 : MAKE_FETCHERS (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT)
1041 0 : MAKE_FETCHERS (normal_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NORMAL)
1042 0 : MAKE_FETCHERS (pad_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_PAD)
1043 0 : MAKE_FETCHERS (none_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NONE)
1044 0 : MAKE_FETCHERS (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT)
1045 0 : MAKE_FETCHERS (normal_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NORMAL)
1046 0 : MAKE_FETCHERS (pad_a8, a8, PIXMAN_REPEAT_PAD)
1047 0 : MAKE_FETCHERS (none_a8, a8, PIXMAN_REPEAT_NONE)
1048 0 : MAKE_FETCHERS (reflect_a8, a8, PIXMAN_REPEAT_REFLECT)
1049 0 : MAKE_FETCHERS (normal_a8, a8, PIXMAN_REPEAT_NORMAL)
1050 0 : MAKE_FETCHERS (pad_r5g6b5, r5g6b5, PIXMAN_REPEAT_PAD)
1051 0 : MAKE_FETCHERS (none_r5g6b5, r5g6b5, PIXMAN_REPEAT_NONE)
1052 0 : MAKE_FETCHERS (reflect_r5g6b5, r5g6b5, PIXMAN_REPEAT_REFLECT)
1053 0 : MAKE_FETCHERS (normal_r5g6b5, r5g6b5, PIXMAN_REPEAT_NORMAL)
1054 :
1055 : static void
1056 0 : bits_image_fetch_solid_32 (pixman_image_t * image,
1057 : int x,
1058 : int y,
1059 : int width,
1060 : uint32_t * buffer,
1061 : const uint32_t * mask)
1062 : {
1063 : uint32_t color;
1064 : uint32_t *end;
1065 :
1066 0 : color = image->bits.fetch_pixel_32 (&image->bits, 0, 0);
1067 :
1068 0 : end = buffer + width;
1069 0 : while (buffer < end)
1070 0 : *(buffer++) = color;
1071 0 : }
1072 :
1073 : static void
1074 0 : bits_image_fetch_solid_64 (pixman_image_t * image,
1075 : int x,
1076 : int y,
1077 : int width,
1078 : uint32_t * b,
1079 : const uint32_t * unused)
1080 : {
1081 : uint64_t color;
1082 0 : uint64_t *buffer = (uint64_t *)b;
1083 : uint64_t *end;
1084 :
1085 0 : color = image->bits.fetch_pixel_64 (&image->bits, 0, 0);
1086 :
1087 0 : end = buffer + width;
1088 0 : while (buffer < end)
1089 0 : *(buffer++) = color;
1090 0 : }
1091 :
1092 : static void
1093 0 : bits_image_fetch_untransformed_repeat_none (bits_image_t *image,
1094 : pixman_bool_t wide,
1095 : int x,
1096 : int y,
1097 : int width,
1098 : uint32_t * buffer)
1099 : {
1100 : uint32_t w;
1101 :
1102 0 : if (y < 0 || y >= image->height)
1103 : {
1104 0 : memset (buffer, 0, width * (wide? 8 : 4));
1105 0 : return;
1106 : }
1107 :
1108 0 : if (x < 0)
1109 : {
1110 0 : w = MIN (width, -x);
1111 :
1112 0 : memset (buffer, 0, w * (wide ? 8 : 4));
1113 :
1114 0 : width -= w;
1115 0 : buffer += w * (wide? 2 : 1);
1116 0 : x += w;
1117 : }
1118 :
1119 0 : if (x < image->width)
1120 : {
1121 0 : w = MIN (width, image->width - x);
1122 :
1123 0 : if (wide)
1124 0 : image->fetch_scanline_64 ((pixman_image_t *)image, x, y, w, buffer, NULL);
1125 : else
1126 0 : image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL);
1127 :
1128 0 : width -= w;
1129 0 : buffer += w * (wide? 2 : 1);
1130 0 : x += w;
1131 : }
1132 :
1133 0 : memset (buffer, 0, width * (wide ? 8 : 4));
1134 : }
1135 :
1136 : static void
1137 0 : bits_image_fetch_untransformed_repeat_normal (bits_image_t *image,
1138 : pixman_bool_t wide,
1139 : int x,
1140 : int y,
1141 : int width,
1142 : uint32_t * buffer)
1143 : {
1144 : uint32_t w;
1145 :
1146 0 : while (y < 0)
1147 0 : y += image->height;
1148 :
1149 0 : while (y >= image->height)
1150 0 : y -= image->height;
1151 :
1152 0 : while (width)
1153 : {
1154 0 : while (x < 0)
1155 0 : x += image->width;
1156 0 : while (x >= image->width)
1157 0 : x -= image->width;
1158 :
1159 0 : w = MIN (width, image->width - x);
1160 :
1161 0 : if (wide)
1162 0 : image->fetch_scanline_64 ((pixman_image_t *)image, x, y, w, buffer, NULL);
1163 : else
1164 0 : image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL);
1165 :
1166 0 : buffer += w * (wide? 2 : 1);
1167 0 : x += w;
1168 0 : width -= w;
1169 : }
1170 0 : }
1171 :
1172 : static void
1173 0 : bits_image_fetch_untransformed_32 (pixman_image_t * image,
1174 : int x,
1175 : int y,
1176 : int width,
1177 : uint32_t * buffer,
1178 : const uint32_t * mask)
1179 : {
1180 0 : if (image->common.repeat == PIXMAN_REPEAT_NONE)
1181 : {
1182 0 : bits_image_fetch_untransformed_repeat_none (
1183 : &image->bits, FALSE, x, y, width, buffer);
1184 : }
1185 : else
1186 : {
1187 0 : bits_image_fetch_untransformed_repeat_normal (
1188 : &image->bits, FALSE, x, y, width, buffer);
1189 : }
1190 0 : }
1191 :
1192 : static void
1193 0 : bits_image_fetch_untransformed_64 (pixman_image_t * image,
1194 : int x,
1195 : int y,
1196 : int width,
1197 : uint32_t * buffer,
1198 : const uint32_t * unused)
1199 : {
1200 0 : if (image->common.repeat == PIXMAN_REPEAT_NONE)
1201 : {
1202 0 : bits_image_fetch_untransformed_repeat_none (
1203 : &image->bits, TRUE, x, y, width, buffer);
1204 : }
1205 : else
1206 : {
1207 0 : bits_image_fetch_untransformed_repeat_normal (
1208 : &image->bits, TRUE, x, y, width, buffer);
1209 : }
1210 0 : }
1211 :
1212 : typedef struct
1213 : {
1214 : pixman_format_code_t format;
1215 : uint32_t flags;
1216 : fetch_scanline_t fetch_32;
1217 : fetch_scanline_t fetch_64;
1218 : } fetcher_info_t;
1219 :
1220 : static const fetcher_info_t fetcher_info[] =
1221 : {
1222 : { PIXMAN_solid,
1223 : FAST_PATH_NO_ALPHA_MAP,
1224 : bits_image_fetch_solid_32,
1225 : bits_image_fetch_solid_64
1226 : },
1227 :
1228 : { PIXMAN_any,
1229 : (FAST_PATH_NO_ALPHA_MAP |
1230 : FAST_PATH_ID_TRANSFORM |
1231 : FAST_PATH_NO_CONVOLUTION_FILTER |
1232 : FAST_PATH_NO_PAD_REPEAT |
1233 : FAST_PATH_NO_REFLECT_REPEAT),
1234 : bits_image_fetch_untransformed_32,
1235 : bits_image_fetch_untransformed_64
1236 : },
1237 :
1238 : #define FAST_BILINEAR_FLAGS \
1239 : (FAST_PATH_NO_ALPHA_MAP | \
1240 : FAST_PATH_NO_ACCESSORS | \
1241 : FAST_PATH_HAS_TRANSFORM | \
1242 : FAST_PATH_AFFINE_TRANSFORM | \
1243 : FAST_PATH_X_UNIT_POSITIVE | \
1244 : FAST_PATH_Y_UNIT_ZERO | \
1245 : FAST_PATH_NONE_REPEAT | \
1246 : FAST_PATH_BILINEAR_FILTER)
1247 :
1248 : { PIXMAN_a8r8g8b8,
1249 : FAST_BILINEAR_FLAGS,
1250 : bits_image_fetch_bilinear_no_repeat_8888,
1251 : _pixman_image_get_scanline_generic_64
1252 : },
1253 :
1254 : { PIXMAN_x8r8g8b8,
1255 : FAST_BILINEAR_FLAGS,
1256 : bits_image_fetch_bilinear_no_repeat_8888,
1257 : _pixman_image_get_scanline_generic_64
1258 : },
1259 :
1260 : #define GENERAL_BILINEAR_FLAGS \
1261 : (FAST_PATH_NO_ALPHA_MAP | \
1262 : FAST_PATH_NO_ACCESSORS | \
1263 : FAST_PATH_HAS_TRANSFORM | \
1264 : FAST_PATH_AFFINE_TRANSFORM | \
1265 : FAST_PATH_BILINEAR_FILTER)
1266 :
1267 : #define GENERAL_NEAREST_FLAGS \
1268 : (FAST_PATH_NO_ALPHA_MAP | \
1269 : FAST_PATH_NO_ACCESSORS | \
1270 : FAST_PATH_HAS_TRANSFORM | \
1271 : FAST_PATH_AFFINE_TRANSFORM | \
1272 : FAST_PATH_NEAREST_FILTER)
1273 :
1274 : #define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \
1275 : { PIXMAN_ ## format, \
1276 : GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \
1277 : bits_image_fetch_bilinear_affine_ ## name, \
1278 : _pixman_image_get_scanline_generic_64 \
1279 : },
1280 :
1281 : #define NEAREST_AFFINE_FAST_PATH(name, format, repeat) \
1282 : { PIXMAN_ ## format, \
1283 : GENERAL_NEAREST_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \
1284 : bits_image_fetch_nearest_affine_ ## name, \
1285 : _pixman_image_get_scanline_generic_64 \
1286 : },
1287 :
1288 : #define AFFINE_FAST_PATHS(name, format, repeat) \
1289 : BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \
1290 : NEAREST_AFFINE_FAST_PATH(name, format, repeat)
1291 :
1292 : AFFINE_FAST_PATHS (pad_a8r8g8b8, a8r8g8b8, PAD)
1293 : AFFINE_FAST_PATHS (none_a8r8g8b8, a8r8g8b8, NONE)
1294 : AFFINE_FAST_PATHS (reflect_a8r8g8b8, a8r8g8b8, REFLECT)
1295 : AFFINE_FAST_PATHS (normal_a8r8g8b8, a8r8g8b8, NORMAL)
1296 : AFFINE_FAST_PATHS (pad_x8r8g8b8, x8r8g8b8, PAD)
1297 : AFFINE_FAST_PATHS (none_x8r8g8b8, x8r8g8b8, NONE)
1298 : AFFINE_FAST_PATHS (reflect_x8r8g8b8, x8r8g8b8, REFLECT)
1299 : AFFINE_FAST_PATHS (normal_x8r8g8b8, x8r8g8b8, NORMAL)
1300 : AFFINE_FAST_PATHS (pad_a8, a8, PAD)
1301 : AFFINE_FAST_PATHS (none_a8, a8, NONE)
1302 : AFFINE_FAST_PATHS (reflect_a8, a8, REFLECT)
1303 : AFFINE_FAST_PATHS (normal_a8, a8, NORMAL)
1304 : AFFINE_FAST_PATHS (pad_r5g6b5, r5g6b5, PAD)
1305 : AFFINE_FAST_PATHS (none_r5g6b5, r5g6b5, NONE)
1306 : AFFINE_FAST_PATHS (reflect_r5g6b5, r5g6b5, REFLECT)
1307 : AFFINE_FAST_PATHS (normal_r5g6b5, r5g6b5, NORMAL)
1308 :
1309 : /* Affine, no alpha */
1310 : { PIXMAN_any,
1311 : (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM),
1312 : bits_image_fetch_affine_no_alpha,
1313 : _pixman_image_get_scanline_generic_64
1314 : },
1315 :
1316 : /* General */
1317 : { PIXMAN_any, 0, bits_image_fetch_general, _pixman_image_get_scanline_generic_64 },
1318 :
1319 : { PIXMAN_null },
1320 : };
1321 :
1322 : static void
1323 72 : bits_image_property_changed (pixman_image_t *image)
1324 : {
1325 72 : uint32_t flags = image->common.flags;
1326 72 : pixman_format_code_t format = image->common.extended_format_code;
1327 : const fetcher_info_t *info;
1328 :
1329 72 : _pixman_bits_image_setup_accessors (&image->bits);
1330 :
1331 72 : info = fetcher_info;
1332 226 : while (info->format != PIXMAN_null)
1333 : {
1334 236 : if ((info->format == format || info->format == PIXMAN_any) &&
1335 82 : (info->flags & flags) == info->flags)
1336 : {
1337 72 : image->bits.get_scanline_32 = info->fetch_32;
1338 72 : image->bits.get_scanline_64 = info->fetch_64;
1339 72 : break;
1340 : }
1341 :
1342 82 : info++;
1343 : }
1344 72 : }
1345 :
1346 : static uint32_t *
1347 0 : src_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
1348 : {
1349 0 : iter->image->bits.get_scanline_32 (
1350 0 : iter->image, iter->x, iter->y++, iter->width, iter->buffer, mask);
1351 :
1352 0 : return iter->buffer;
1353 : }
1354 :
1355 : static uint32_t *
1356 0 : src_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
1357 : {
1358 0 : iter->image->bits.get_scanline_64 (
1359 0 : iter->image, iter->x, iter->y++, iter->width, iter->buffer, mask);
1360 :
1361 0 : return iter->buffer;
1362 : }
1363 :
1364 : void
1365 0 : _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
1366 : {
1367 0 : if (iter->flags & ITER_NARROW)
1368 0 : iter->get_scanline = src_get_scanline_narrow;
1369 : else
1370 0 : iter->get_scanline = src_get_scanline_wide;
1371 0 : }
1372 :
1373 : static uint32_t *
1374 0 : dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
1375 : {
1376 0 : pixman_image_t *image = iter->image;
1377 0 : int x = iter->x;
1378 0 : int y = iter->y;
1379 0 : int width = iter->width;
1380 0 : uint32_t * buffer = iter->buffer;
1381 :
1382 0 : image->bits.fetch_scanline_32 (image, x, y, width, buffer, mask);
1383 0 : if (image->common.alpha_map)
1384 : {
1385 0 : x -= image->common.alpha_origin_x;
1386 0 : y -= image->common.alpha_origin_y;
1387 :
1388 0 : image->common.alpha_map->fetch_scanline_32 (
1389 0 : (pixman_image_t *)image->common.alpha_map,
1390 : x, y, width, buffer, mask);
1391 : }
1392 :
1393 0 : return iter->buffer;
1394 : }
1395 :
1396 : static uint32_t *
1397 0 : dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
1398 : {
1399 0 : bits_image_t * image = &iter->image->bits;
1400 0 : int x = iter->x;
1401 0 : int y = iter->y;
1402 0 : int width = iter->width;
1403 0 : uint32_t * buffer = iter->buffer;
1404 :
1405 0 : image->fetch_scanline_64 (
1406 : (pixman_image_t *)image, x, y, width, buffer, mask);
1407 0 : if (image->common.alpha_map)
1408 : {
1409 0 : x -= image->common.alpha_origin_x;
1410 0 : y -= image->common.alpha_origin_y;
1411 :
1412 0 : image->common.alpha_map->fetch_scanline_64 (
1413 0 : (pixman_image_t *)image->common.alpha_map, x, y, width, buffer, mask);
1414 : }
1415 :
1416 0 : return iter->buffer;
1417 : }
1418 :
1419 : static void
1420 0 : dest_write_back_narrow (pixman_iter_t *iter)
1421 : {
1422 0 : bits_image_t * image = &iter->image->bits;
1423 0 : int x = iter->x;
1424 0 : int y = iter->y;
1425 0 : int width = iter->width;
1426 0 : const uint32_t *buffer = iter->buffer;
1427 :
1428 0 : image->store_scanline_32 (image, x, y, width, buffer);
1429 :
1430 0 : if (image->common.alpha_map)
1431 : {
1432 0 : x -= image->common.alpha_origin_x;
1433 0 : y -= image->common.alpha_origin_y;
1434 :
1435 0 : image->common.alpha_map->store_scanline_32 (
1436 : image->common.alpha_map, x, y, width, buffer);
1437 : }
1438 :
1439 0 : iter->y++;
1440 0 : }
1441 :
1442 : static void
1443 0 : dest_write_back_wide (pixman_iter_t *iter)
1444 : {
1445 0 : bits_image_t * image = &iter->image->bits;
1446 0 : int x = iter->x;
1447 0 : int y = iter->y;
1448 0 : int width = iter->width;
1449 0 : const uint32_t *buffer = iter->buffer;
1450 :
1451 0 : image->store_scanline_64 (image, x, y, width, buffer);
1452 :
1453 0 : if (image->common.alpha_map)
1454 : {
1455 0 : x -= image->common.alpha_origin_x;
1456 0 : y -= image->common.alpha_origin_y;
1457 :
1458 0 : image->common.alpha_map->store_scanline_64 (
1459 : image->common.alpha_map, x, y, width, buffer);
1460 : }
1461 :
1462 0 : iter->y++;
1463 0 : }
1464 :
1465 : static void
1466 0 : dest_write_back_direct (pixman_iter_t *iter)
1467 : {
1468 0 : iter->buffer += iter->image->bits.rowstride;
1469 0 : }
1470 :
1471 : void
1472 0 : _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter)
1473 : {
1474 0 : if (iter->flags & ITER_NARROW)
1475 : {
1476 0 : if (((image->common.flags &
1477 : (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_NO_ACCESSORS)) ==
1478 0 : (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_NO_ACCESSORS)) &&
1479 0 : (image->bits.format == PIXMAN_a8r8g8b8 ||
1480 0 : (image->bits.format == PIXMAN_x8r8g8b8 &&
1481 0 : (iter->flags & ITER_LOCALIZED_ALPHA))))
1482 : {
1483 0 : iter->buffer = image->bits.bits + iter->y * image->bits.rowstride + iter->x;
1484 :
1485 0 : iter->get_scanline = _pixman_iter_get_scanline_noop;
1486 0 : iter->write_back = dest_write_back_direct;
1487 : }
1488 : else
1489 : {
1490 0 : if ((iter->flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
1491 : (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
1492 : {
1493 0 : iter->get_scanline = _pixman_iter_get_scanline_noop;
1494 : }
1495 : else
1496 : {
1497 0 : iter->get_scanline = dest_get_scanline_narrow;
1498 : }
1499 :
1500 0 : iter->write_back = dest_write_back_narrow;
1501 : }
1502 : }
1503 : else
1504 : {
1505 0 : iter->get_scanline = dest_get_scanline_wide;
1506 0 : iter->write_back = dest_write_back_wide;
1507 : }
1508 0 : }
1509 :
1510 : static uint32_t *
1511 0 : create_bits (pixman_format_code_t format,
1512 : int width,
1513 : int height,
1514 : int * rowstride_bytes)
1515 : {
1516 : int stride;
1517 : int buf_size;
1518 : int bpp;
1519 :
1520 : /* what follows is a long-winded way, avoiding any possibility of integer
1521 : * overflows, of saying:
1522 : * stride = ((width * bpp + 0x1f) >> 5) * sizeof (uint32_t);
1523 : */
1524 :
1525 0 : bpp = PIXMAN_FORMAT_BPP (format);
1526 0 : if (pixman_multiply_overflows_int (width, bpp))
1527 0 : return NULL;
1528 :
1529 0 : stride = width * bpp;
1530 0 : if (pixman_addition_overflows_int (stride, 0x1f))
1531 0 : return NULL;
1532 :
1533 0 : stride += 0x1f;
1534 0 : stride >>= 5;
1535 :
1536 0 : stride *= sizeof (uint32_t);
1537 :
1538 0 : if (pixman_multiply_overflows_int (height, stride))
1539 0 : return NULL;
1540 :
1541 0 : buf_size = height * stride;
1542 :
1543 0 : if (rowstride_bytes)
1544 0 : *rowstride_bytes = stride;
1545 :
1546 0 : return calloc (buf_size, 1);
1547 : }
1548 :
1549 : PIXMAN_EXPORT pixman_image_t *
1550 75 : pixman_image_create_bits (pixman_format_code_t format,
1551 : int width,
1552 : int height,
1553 : uint32_t * bits,
1554 : int rowstride_bytes)
1555 : {
1556 : pixman_image_t *image;
1557 75 : uint32_t *free_me = NULL;
1558 :
1559 : /* must be a whole number of uint32_t's
1560 : */
1561 75 : return_val_if_fail (
1562 : bits == NULL || (rowstride_bytes % sizeof (uint32_t)) == 0, NULL);
1563 :
1564 75 : return_val_if_fail (PIXMAN_FORMAT_BPP (format) >= PIXMAN_FORMAT_DEPTH (format), NULL);
1565 :
1566 75 : if (!bits && width && height)
1567 : {
1568 0 : free_me = bits = create_bits (format, width, height, &rowstride_bytes);
1569 0 : if (!bits)
1570 0 : return NULL;
1571 : }
1572 :
1573 75 : image = _pixman_image_allocate ();
1574 :
1575 75 : if (!image)
1576 : {
1577 0 : if (free_me)
1578 0 : free (free_me);
1579 :
1580 0 : return NULL;
1581 : }
1582 :
1583 75 : image->type = BITS;
1584 75 : image->bits.format = format;
1585 75 : image->bits.width = width;
1586 75 : image->bits.height = height;
1587 75 : image->bits.bits = bits;
1588 75 : image->bits.free_me = free_me;
1589 75 : image->bits.read_func = NULL;
1590 75 : image->bits.write_func = NULL;
1591 :
1592 : /* The rowstride is stored in number of uint32_t */
1593 75 : image->bits.rowstride = rowstride_bytes / (int) sizeof (uint32_t);
1594 :
1595 75 : image->bits.indexed = NULL;
1596 :
1597 75 : image->common.property_changed = bits_image_property_changed;
1598 :
1599 75 : _pixman_image_reset_clip_region (image);
1600 :
1601 75 : return image;
1602 : }
|