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