/work/workdir/UnpackedTarball/cairo/src/cairo-image-source.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2003 University of Southern California |
5 | | * Copyright © 2009,2010,2011 Intel Corporation |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it either under the terms of the GNU Lesser General Public |
9 | | * License version 2.1 as published by the Free Software Foundation |
10 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
11 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
12 | | * notice, a recipient may use your version of this file under either |
13 | | * the MPL or the LGPL. |
14 | | * |
15 | | * You should have received a copy of the LGPL along with this library |
16 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
17 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
18 | | * You should have received a copy of the MPL along with this library |
19 | | * in the file COPYING-MPL-1.1 |
20 | | * |
21 | | * The contents of this file are subject to the Mozilla Public License |
22 | | * Version 1.1 (the "License"); you may not use this file except in |
23 | | * compliance with the License. You may obtain a copy of the License at |
24 | | * http://www.mozilla.org/MPL/ |
25 | | * |
26 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
27 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
28 | | * the specific language governing rights and limitations. |
29 | | * |
30 | | * The Original Code is the cairo graphics library. |
31 | | * |
32 | | * The Initial Developer of the Original Code is University of Southern |
33 | | * California. |
34 | | * |
35 | | * Contributor(s): |
36 | | * Carl D. Worth <cworth@cworth.org> |
37 | | * Chris Wilson <chris@chris-wilson.co.uk> |
38 | | */ |
39 | | |
40 | | /* The purpose of this file/surface is to simply translate a pattern |
41 | | * to a pixman_image_t and thence to feed it back to the general |
42 | | * compositor interface. |
43 | | */ |
44 | | |
45 | | #include "cairoint.h" |
46 | | |
47 | | #include "cairo-image-surface-private.h" |
48 | | |
49 | | #include "cairo-compositor-private.h" |
50 | | #include "cairo-error-private.h" |
51 | | #include "cairo-pattern-inline.h" |
52 | | #include "cairo-paginated-private.h" |
53 | | #include "cairo-recording-surface-private.h" |
54 | | #include "cairo-surface-observer-private.h" |
55 | | #include "cairo-surface-snapshot-inline.h" |
56 | | #include "cairo-surface-subsurface-private.h" |
57 | | |
58 | 3.06k | #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ |
59 | | |
60 | | #if CAIRO_NO_MUTEX |
61 | | #define PIXMAN_HAS_ATOMIC_OPS 1 |
62 | | #endif |
63 | | |
64 | | #if PIXMAN_HAS_ATOMIC_OPS |
65 | | static pixman_image_t *__pixman_transparent_image; |
66 | | static pixman_image_t *__pixman_black_image; |
67 | | static pixman_image_t *__pixman_white_image; |
68 | | |
69 | | static pixman_image_t * |
70 | | _pixman_transparent_image (void) |
71 | | { |
72 | | pixman_image_t *image; |
73 | | |
74 | | TRACE ((stderr, "%s\n", __FUNCTION__)); |
75 | | |
76 | | image = __pixman_transparent_image; |
77 | | if (unlikely (image == NULL)) { |
78 | | pixman_color_t color; |
79 | | |
80 | | color.red = 0x00; |
81 | | color.green = 0x00; |
82 | | color.blue = 0x00; |
83 | | color.alpha = 0x00; |
84 | | |
85 | | image = pixman_image_create_solid_fill (&color); |
86 | | if (unlikely (image == NULL)) |
87 | | return NULL; |
88 | | |
89 | | if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image, |
90 | | NULL, image)) |
91 | | { |
92 | | pixman_image_ref (image); |
93 | | } |
94 | | } else { |
95 | | pixman_image_ref (image); |
96 | | } |
97 | | |
98 | | return image; |
99 | | } |
100 | | |
101 | | static pixman_image_t * |
102 | | _pixman_black_image (void) |
103 | | { |
104 | | pixman_image_t *image; |
105 | | |
106 | | TRACE ((stderr, "%s\n", __FUNCTION__)); |
107 | | |
108 | | image = __pixman_black_image; |
109 | | if (unlikely (image == NULL)) { |
110 | | pixman_color_t color; |
111 | | |
112 | | color.red = 0x00; |
113 | | color.green = 0x00; |
114 | | color.blue = 0x00; |
115 | | color.alpha = 0xffff; |
116 | | |
117 | | image = pixman_image_create_solid_fill (&color); |
118 | | if (unlikely (image == NULL)) |
119 | | return NULL; |
120 | | |
121 | | if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image, |
122 | | NULL, image)) |
123 | | { |
124 | | pixman_image_ref (image); |
125 | | } |
126 | | } else { |
127 | | pixman_image_ref (image); |
128 | | } |
129 | | |
130 | | return image; |
131 | | } |
132 | | |
133 | | static pixman_image_t * |
134 | | _pixman_white_image (void) |
135 | | { |
136 | | pixman_image_t *image; |
137 | | |
138 | | TRACE ((stderr, "%s\n", __FUNCTION__)); |
139 | | |
140 | | image = __pixman_white_image; |
141 | | if (unlikely (image == NULL)) { |
142 | | pixman_color_t color; |
143 | | |
144 | | color.red = 0xffff; |
145 | | color.green = 0xffff; |
146 | | color.blue = 0xffff; |
147 | | color.alpha = 0xffff; |
148 | | |
149 | | image = pixman_image_create_solid_fill (&color); |
150 | | if (unlikely (image == NULL)) |
151 | | return NULL; |
152 | | |
153 | | if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image, |
154 | | NULL, image)) |
155 | | { |
156 | | pixman_image_ref (image); |
157 | | } |
158 | | } else { |
159 | | pixman_image_ref (image); |
160 | | } |
161 | | |
162 | | return image; |
163 | | } |
164 | | |
165 | | static uint32_t |
166 | | hars_petruska_f54_1_random (void) |
167 | | { |
168 | | #define rol(x,k) ((x << k) | (x >> (32-k))) |
169 | | static uint32_t x; |
170 | | return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; |
171 | | #undef rol |
172 | | } |
173 | | |
174 | | static struct { |
175 | | cairo_color_t color; |
176 | | pixman_image_t *image; |
177 | | } cache[16]; |
178 | | static int n_cached; |
179 | | |
180 | | #else /* !PIXMAN_HAS_ATOMIC_OPS */ |
181 | | static pixman_image_t * |
182 | | _pixman_transparent_image (void) |
183 | 332 | { |
184 | 332 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
185 | 332 | return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT); |
186 | 332 | } |
187 | | |
188 | | static pixman_image_t * |
189 | | _pixman_black_image (void) |
190 | 94 | { |
191 | 94 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
192 | 94 | return _pixman_image_for_color (CAIRO_COLOR_BLACK); |
193 | 94 | } |
194 | | |
195 | | static pixman_image_t * |
196 | | _pixman_white_image (void) |
197 | 4 | { |
198 | 4 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
199 | 4 | return _pixman_image_for_color (CAIRO_COLOR_WHITE); |
200 | 4 | } |
201 | | #endif /* !PIXMAN_HAS_ATOMIC_OPS */ |
202 | | |
203 | | |
204 | | pixman_image_t * |
205 | | _pixman_image_for_color (const cairo_color_t *cairo_color) |
206 | 18.7k | { |
207 | 18.7k | pixman_color_t color; |
208 | 18.7k | pixman_image_t *image; |
209 | | |
210 | | #if PIXMAN_HAS_ATOMIC_OPS |
211 | | int i; |
212 | | |
213 | | if (CAIRO_COLOR_IS_CLEAR (cairo_color)) |
214 | | return _pixman_transparent_image (); |
215 | | |
216 | | if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) { |
217 | | if (cairo_color->red_short <= 0x00ff && |
218 | | cairo_color->green_short <= 0x00ff && |
219 | | cairo_color->blue_short <= 0x00ff) |
220 | | { |
221 | | return _pixman_black_image (); |
222 | | } |
223 | | |
224 | | if (cairo_color->red_short >= 0xff00 && |
225 | | cairo_color->green_short >= 0xff00 && |
226 | | cairo_color->blue_short >= 0xff00) |
227 | | { |
228 | | return _pixman_white_image (); |
229 | | } |
230 | | } |
231 | | |
232 | | CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex); |
233 | | for (i = 0; i < n_cached; i++) { |
234 | | if (_cairo_color_equal (&cache[i].color, cairo_color)) { |
235 | | image = pixman_image_ref (cache[i].image); |
236 | | goto UNLOCK; |
237 | | } |
238 | | } |
239 | | #endif |
240 | | |
241 | 18.7k | color.red = cairo_color->red_short; |
242 | 18.7k | color.green = cairo_color->green_short; |
243 | 18.7k | color.blue = cairo_color->blue_short; |
244 | 18.7k | color.alpha = cairo_color->alpha_short; |
245 | | |
246 | 18.7k | image = pixman_image_create_solid_fill (&color); |
247 | | #if PIXMAN_HAS_ATOMIC_OPS |
248 | | if (image == NULL) |
249 | | goto UNLOCK; |
250 | | |
251 | | if (n_cached < ARRAY_LENGTH (cache)) { |
252 | | i = n_cached++; |
253 | | } else { |
254 | | i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache); |
255 | | pixman_image_unref (cache[i].image); |
256 | | } |
257 | | cache[i].image = pixman_image_ref (image); |
258 | | cache[i].color = *cairo_color; |
259 | | |
260 | | UNLOCK: |
261 | | CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex); |
262 | | #endif |
263 | 18.7k | return image; |
264 | 18.7k | } |
265 | | |
266 | | |
267 | | void |
268 | | _cairo_image_reset_static_data (void) |
269 | 0 | { |
270 | | #if PIXMAN_HAS_ATOMIC_OPS |
271 | | while (n_cached) |
272 | | pixman_image_unref (cache[--n_cached].image); |
273 | | |
274 | | if (__pixman_transparent_image) { |
275 | | pixman_image_unref (__pixman_transparent_image); |
276 | | __pixman_transparent_image = NULL; |
277 | | } |
278 | | |
279 | | if (__pixman_black_image) { |
280 | | pixman_image_unref (__pixman_black_image); |
281 | | __pixman_black_image = NULL; |
282 | | } |
283 | | |
284 | | if (__pixman_white_image) { |
285 | | pixman_image_unref (__pixman_white_image); |
286 | | __pixman_white_image = NULL; |
287 | | } |
288 | | #endif |
289 | 0 | } |
290 | | |
291 | | static pixman_image_t * |
292 | | _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern, |
293 | | const cairo_rectangle_int_t *extents, |
294 | | int *ix, int *iy) |
295 | 3.06k | { |
296 | 3.06k | pixman_image_t *pixman_image; |
297 | 3.06k | pixman_gradient_stop_t pixman_stops_static[2]; |
298 | 3.06k | pixman_gradient_stop_t *pixman_stops = pixman_stops_static; |
299 | 3.06k | pixman_transform_t pixman_transform; |
300 | 3.06k | cairo_matrix_t matrix; |
301 | 3.06k | cairo_circle_double_t extremes[2]; |
302 | 3.06k | pixman_point_fixed_t p1, p2; |
303 | 3.06k | unsigned int i; |
304 | 3.06k | cairo_int_status_t status; |
305 | | |
306 | 3.06k | TRACE ((stderr, "%s\n", __FUNCTION__)); |
307 | | |
308 | 3.06k | if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { |
309 | 0 | pixman_stops = _cairo_malloc_ab (pattern->n_stops, |
310 | 0 | sizeof(pixman_gradient_stop_t)); |
311 | 0 | if (unlikely (pixman_stops == NULL)) |
312 | 0 | return NULL; |
313 | 0 | } |
314 | | |
315 | 9.18k | for (i = 0; i < pattern->n_stops; i++) { |
316 | 6.12k | pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset); |
317 | 6.12k | pixman_stops[i].color.red = pattern->stops[i].color.red_short; |
318 | 6.12k | pixman_stops[i].color.green = pattern->stops[i].color.green_short; |
319 | 6.12k | pixman_stops[i].color.blue = pattern->stops[i].color.blue_short; |
320 | 6.12k | pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short; |
321 | 6.12k | } |
322 | | |
323 | 3.06k | _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes); |
324 | | |
325 | 3.06k | p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x); |
326 | 3.06k | p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y); |
327 | 3.06k | p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x); |
328 | 3.06k | p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y); |
329 | | |
330 | 3.06k | if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
331 | 573 | pixman_image = pixman_image_create_linear_gradient (&p1, &p2, |
332 | 573 | pixman_stops, |
333 | 573 | pattern->n_stops); |
334 | 2.48k | } else { |
335 | 2.48k | pixman_fixed_t r1, r2; |
336 | | |
337 | 2.48k | r1 = _cairo_fixed_16_16_from_double (extremes[0].radius); |
338 | 2.48k | r2 = _cairo_fixed_16_16_from_double (extremes[1].radius); |
339 | | |
340 | 2.48k | pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2, |
341 | 2.48k | pixman_stops, |
342 | 2.48k | pattern->n_stops); |
343 | 2.48k | } |
344 | | |
345 | 3.06k | if (pixman_stops != pixman_stops_static) |
346 | 0 | free (pixman_stops); |
347 | | |
348 | 3.06k | if (unlikely (pixman_image == NULL)) |
349 | 0 | return NULL; |
350 | | |
351 | 3.06k | *ix = *iy = 0; |
352 | 3.06k | status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter, |
353 | 3.06k | extents->x + extents->width/2., |
354 | 3.06k | extents->y + extents->height/2., |
355 | 3.06k | &pixman_transform, ix, iy); |
356 | 3.06k | if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { |
357 | 2.25k | if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) || |
358 | 2.25k | ! pixman_image_set_transform (pixman_image, &pixman_transform)) |
359 | 0 | { |
360 | 0 | pixman_image_unref (pixman_image); |
361 | 0 | return NULL; |
362 | 0 | } |
363 | 2.25k | } |
364 | | |
365 | 3.06k | { |
366 | 3.06k | pixman_repeat_t pixman_repeat; |
367 | | |
368 | 3.06k | switch (pattern->base.extend) { |
369 | 0 | default: |
370 | 0 | case CAIRO_EXTEND_NONE: |
371 | 0 | pixman_repeat = PIXMAN_REPEAT_NONE; |
372 | 0 | break; |
373 | 0 | case CAIRO_EXTEND_REPEAT: |
374 | 0 | pixman_repeat = PIXMAN_REPEAT_NORMAL; |
375 | 0 | break; |
376 | 0 | case CAIRO_EXTEND_REFLECT: |
377 | 0 | pixman_repeat = PIXMAN_REPEAT_REFLECT; |
378 | 0 | break; |
379 | 3.06k | case CAIRO_EXTEND_PAD: |
380 | 3.06k | pixman_repeat = PIXMAN_REPEAT_PAD; |
381 | 3.06k | break; |
382 | 3.06k | } |
383 | | |
384 | 3.06k | pixman_image_set_repeat (pixman_image, pixman_repeat); |
385 | 3.06k | } |
386 | | |
387 | 0 | return pixman_image; |
388 | 3.06k | } |
389 | | |
390 | | static pixman_image_t * |
391 | | _pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern, |
392 | | const cairo_rectangle_int_t *extents, |
393 | | int *tx, int *ty) |
394 | 0 | { |
395 | 0 | pixman_image_t *image; |
396 | 0 | int width, height; |
397 | |
|
398 | 0 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
399 | |
|
400 | 0 | *tx = -extents->x; |
401 | 0 | *ty = -extents->y; |
402 | 0 | width = extents->width; |
403 | 0 | height = extents->height; |
404 | |
|
405 | 0 | image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0); |
406 | 0 | if (unlikely (image == NULL)) |
407 | 0 | return NULL; |
408 | | |
409 | 0 | _cairo_mesh_pattern_rasterize (pattern, |
410 | 0 | pixman_image_get_data (image), |
411 | 0 | width, height, |
412 | 0 | pixman_image_get_stride (image), |
413 | 0 | *tx, *ty); |
414 | 0 | return image; |
415 | 0 | } |
416 | | |
417 | | struct acquire_source_cleanup { |
418 | | cairo_surface_t *surface; |
419 | | cairo_image_surface_t *image; |
420 | | void *image_extra; |
421 | | }; |
422 | | |
423 | | static void |
424 | | _acquire_source_cleanup (pixman_image_t *pixman_image, |
425 | | void *closure) |
426 | 0 | { |
427 | 0 | struct acquire_source_cleanup *data = closure; |
428 | |
|
429 | 0 | _cairo_surface_release_source_image (data->surface, |
430 | 0 | data->image, |
431 | 0 | data->image_extra); |
432 | 0 | free (data); |
433 | 0 | } |
434 | | |
435 | | static void |
436 | | _defer_free_cleanup (pixman_image_t *pixman_image, |
437 | | void *closure) |
438 | 0 | { |
439 | 0 | cairo_surface_destroy (closure); |
440 | 0 | } |
441 | | |
442 | | static uint16_t |
443 | | expand_channel (uint16_t v, uint32_t bits) |
444 | 0 | { |
445 | 0 | int offset = 16 - bits; |
446 | 0 | while (offset > 0) { |
447 | 0 | v |= v >> bits; |
448 | 0 | offset -= bits; |
449 | 0 | bits += bits; |
450 | 0 | } |
451 | 0 | return v; |
452 | 0 | } |
453 | | |
454 | | static pixman_image_t * |
455 | | _pixel_to_solid (cairo_image_surface_t *image, int x, int y) |
456 | 430 | { |
457 | 430 | uint32_t pixel; |
458 | 430 | float *rgba; |
459 | 430 | pixman_color_t color; |
460 | | |
461 | 430 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
462 | | |
463 | 430 | switch (image->format) { |
464 | 0 | default: |
465 | 0 | case CAIRO_FORMAT_INVALID: |
466 | 0 | ASSERT_NOT_REACHED; |
467 | 0 | return NULL; |
468 | | |
469 | 0 | case CAIRO_FORMAT_A1: |
470 | 0 | pixel = *(uint8_t *) (image->data + y * image->stride + x/8); |
471 | 0 | return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image (); |
472 | | |
473 | 4 | case CAIRO_FORMAT_A8: |
474 | 4 | color.alpha = *(uint8_t *) (image->data + y * image->stride + x); |
475 | 4 | color.alpha |= color.alpha << 8; |
476 | 4 | if (color.alpha == 0) |
477 | 4 | return _pixman_transparent_image (); |
478 | 0 | if (color.alpha == 0xffff) |
479 | 0 | return _pixman_black_image (); |
480 | | |
481 | 0 | color.red = color.green = color.blue = 0; |
482 | 0 | return pixman_image_create_solid_fill (&color); |
483 | | |
484 | 0 | case CAIRO_FORMAT_RGB16_565: |
485 | 0 | pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x); |
486 | 0 | if (pixel == 0) |
487 | 0 | return _pixman_black_image (); |
488 | 0 | if (pixel == 0xffff) |
489 | 0 | return _pixman_white_image (); |
490 | | |
491 | 0 | color.alpha = 0xffff; |
492 | 0 | color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5); |
493 | 0 | color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6); |
494 | 0 | color.blue = expand_channel ((pixel & 0x1f) << 11, 5); |
495 | 0 | return pixman_image_create_solid_fill (&color); |
496 | | |
497 | 0 | case CAIRO_FORMAT_RGB30: |
498 | 0 | pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); |
499 | 0 | pixel &= 0x3fffffff; /* ignore alpha bits */ |
500 | 0 | if (pixel == 0) |
501 | 0 | return _pixman_black_image (); |
502 | 0 | if (pixel == 0x3fffffff) |
503 | 0 | return _pixman_white_image (); |
504 | | |
505 | | /* convert 10bpc to 16bpc */ |
506 | 0 | color.alpha = 0xffff; |
507 | 0 | color.red = expand_channel((pixel >> 20) & 0x3fff, 10); |
508 | 0 | color.green = expand_channel((pixel >> 10) & 0x3fff, 10); |
509 | 0 | color.blue = expand_channel(pixel & 0x3fff, 10); |
510 | 0 | return pixman_image_create_solid_fill (&color); |
511 | | |
512 | 0 | case CAIRO_FORMAT_RGB24_888: |
513 | 0 | pixel = (uint32_t)(image->data + y * image->stride + 3 * x)[0] | ((uint32_t)(image->data + y * image->stride + 3 * x)[1] << 8) | ((uint32_t)(image->data + y * image->stride + 3 * x)[2] << 16); |
514 | 0 | if (pixel == 0) |
515 | 0 | return _pixman_black_image (); |
516 | 0 | if (pixel == 0x00ffffff) |
517 | 0 | return _pixman_white_image (); |
518 | | |
519 | 0 | color.alpha = 0xffff; |
520 | 0 | color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00); |
521 | 0 | color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00); |
522 | 0 | color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00); |
523 | 0 | return pixman_image_create_solid_fill (&color); |
524 | | |
525 | 426 | case CAIRO_FORMAT_ARGB32: |
526 | 426 | case CAIRO_FORMAT_RGB24: |
527 | 426 | pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); |
528 | 426 | color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff; |
529 | 426 | if (color.alpha == 0) |
530 | 328 | return _pixman_transparent_image (); |
531 | 98 | if (pixel == 0xffffffff) |
532 | 4 | return _pixman_white_image (); |
533 | 94 | if (color.alpha == 0xffff && (pixel & 0xffffff) == 0) |
534 | 94 | return _pixman_black_image (); |
535 | | |
536 | 0 | color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00); |
537 | 0 | color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00); |
538 | 0 | color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00); |
539 | 0 | return pixman_image_create_solid_fill (&color); |
540 | | |
541 | 0 | case CAIRO_FORMAT_RGB96F: |
542 | 0 | case CAIRO_FORMAT_RGBA128F: |
543 | 0 | if (image->format == CAIRO_FORMAT_RGBA128F) |
544 | 0 | { |
545 | 0 | rgba = (float *)&image->data[y * image->stride + 16 * x]; |
546 | 0 | color.alpha = 65535.f * rgba[3]; |
547 | |
|
548 | 0 | if (color.alpha == 0) |
549 | 0 | return _pixman_transparent_image (); |
550 | 0 | } |
551 | 0 | else |
552 | 0 | { |
553 | 0 | rgba = (float *)&image->data[y * image->stride + 12 * x]; |
554 | 0 | color.alpha = 0xffff; |
555 | 0 | } |
556 | | |
557 | 0 | if (color.alpha == 0xffff && rgba[0] == 0.f && rgba[1] == 0.f && rgba[2] == 0.f) |
558 | 0 | return _pixman_black_image (); |
559 | 0 | if (color.alpha == 0xffff && rgba[0] == 1.f && rgba[1] == 1.f && rgba[2] == 1.f) |
560 | 0 | return _pixman_white_image (); |
561 | | |
562 | 0 | color.red = rgba[0] * 65535.f; |
563 | 0 | color.green = rgba[1] * 65535.f; |
564 | 0 | color.blue = rgba[2] * 65535.f; |
565 | 0 | return pixman_image_create_solid_fill (&color); |
566 | 430 | } |
567 | 430 | } |
568 | | |
569 | | /* ========================================================================== */ |
570 | | |
571 | | /* Index into filter table */ |
572 | | typedef enum |
573 | | { |
574 | | KERNEL_IMPULSE, |
575 | | KERNEL_BOX, |
576 | | KERNEL_LINEAR, |
577 | | KERNEL_MITCHELL, |
578 | | KERNEL_NOTCH, |
579 | | KERNEL_CATMULL_ROM, |
580 | | KERNEL_LANCZOS3, |
581 | | KERNEL_LANCZOS3_STRETCHED, |
582 | | KERNEL_TENT |
583 | | } kernel_t; |
584 | | |
585 | | /* Produce contribution of a filter of size r for pixel centered on x. |
586 | | For a typical low-pass function this evaluates the function at x/r. |
587 | | If the frequency is higher than 1/2, such as when r is less than 1, |
588 | | this may need to integrate several samples, see cubic for examples. |
589 | | */ |
590 | | typedef double (* kernel_func_t) (double x, double r); |
591 | | |
592 | | /* Return maximum number of pixels that will be non-zero. Except for |
593 | | impluse this is the maximum of 2 and the width of the non-zero part |
594 | | of the filter rounded up to the next integer. |
595 | | */ |
596 | | typedef int (* kernel_width_func_t) (double r); |
597 | | |
598 | | /* Table of filters */ |
599 | | typedef struct |
600 | | { |
601 | | kernel_t kernel; |
602 | | kernel_func_t func; |
603 | | kernel_width_func_t width; |
604 | | } filter_info_t; |
605 | | |
606 | | /* PIXMAN_KERNEL_IMPULSE: Returns pixel nearest the center. This |
607 | | matches PIXMAN_FILTER_NEAREST. This is useful if you wish to |
608 | | combine the result of nearest in one direction with another filter |
609 | | in the other. |
610 | | */ |
611 | | |
612 | | static double |
613 | | impulse_kernel (double x, double r) |
614 | 0 | { |
615 | 0 | return 1; |
616 | 0 | } |
617 | | |
618 | | static int |
619 | | impulse_width (double r) |
620 | 0 | { |
621 | 0 | return 1; |
622 | 0 | } |
623 | | |
624 | | /* PIXMAN_KERNEL_BOX: Intersection of a box of width r with square |
625 | | pixels. This is the smallest possible filter such that the output |
626 | | image contains an equal contribution from all the input |
627 | | pixels. Lots of software uses this. The function is a trapazoid of |
628 | | width r+1, not a box. |
629 | | |
630 | | When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and |
631 | | PIXMAN_KERNEL_TENT all produce the same filter, allowing |
632 | | them to be exchanged at this point. |
633 | | */ |
634 | | |
635 | | static double |
636 | | box_kernel (double x, double r) |
637 | 80.1k | { |
638 | 80.1k | return MAX (0.0, MIN (MIN (r, 1.0), |
639 | 80.1k | MIN ((r + 1) / 2 - x, (r + 1) / 2 + x))); |
640 | 80.1k | } |
641 | | |
642 | | static int |
643 | | box_width (double r) |
644 | 188 | { |
645 | 188 | return r < 1.0 ? 2 : ceil(r + 1); |
646 | 188 | } |
647 | | |
648 | | /* PIXMAN_KERNEL_LINEAR: Weighted sum of the two pixels nearest the |
649 | | center, or a triangle of width 2. This matches |
650 | | PIXMAN_FILTER_BILINEAR. This is useful if you wish to combine the |
651 | | result of bilinear in one direction with another filter in the |
652 | | other. This is not a good filter if r > 1. You may actually want |
653 | | PIXMAN_FILTER_TENT. |
654 | | |
655 | | When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and |
656 | | PIXMAN_KERNEL_TENT all produce the same filter, allowing |
657 | | them to be exchanged at this point. |
658 | | */ |
659 | | |
660 | | static double |
661 | | linear_kernel (double x, double r) |
662 | 0 | { |
663 | 0 | return MAX (1.0 - fabs(x), 0.0); |
664 | 0 | } |
665 | | |
666 | | static int |
667 | | linear_width (double r) |
668 | 0 | { |
669 | 0 | return 2; |
670 | 0 | } |
671 | | |
672 | | /* Cubic functions described in the Mitchell-Netravali paper. |
673 | | http://mentallandscape.com/Papers_siggraph88.pdf. This describes |
674 | | all possible cubic functions that can be used for sampling. |
675 | | */ |
676 | | |
677 | | static double |
678 | | general_cubic (double x, double r, double B, double C) |
679 | 0 | { |
680 | 0 | double ax; |
681 | 0 | if (r < 1.0) |
682 | 0 | return |
683 | 0 | general_cubic(x * 2 - .5, r * 2, B, C) + |
684 | 0 | general_cubic(x * 2 + .5, r * 2, B, C); |
685 | | |
686 | 0 | ax = fabs (x / r); |
687 | |
|
688 | 0 | if (ax < 1) |
689 | 0 | { |
690 | 0 | return (((12 - 9 * B - 6 * C) * ax + |
691 | 0 | (-18 + 12 * B + 6 * C)) * ax * ax + |
692 | 0 | (6 - 2 * B)) / 6; |
693 | 0 | } |
694 | 0 | else if (ax < 2) |
695 | 0 | { |
696 | 0 | return ((((-B - 6 * C) * ax + |
697 | 0 | (6 * B + 30 * C)) * ax + |
698 | 0 | (-12 * B - 48 * C)) * ax + |
699 | 0 | (8 * B + 24 * C)) / 6; |
700 | 0 | } |
701 | 0 | else |
702 | 0 | { |
703 | 0 | return 0.0; |
704 | 0 | } |
705 | 0 | } |
706 | | |
707 | | static int |
708 | | cubic_width (double r) |
709 | 0 | { |
710 | 0 | return MAX (2, ceil (r * 4)); |
711 | 0 | } |
712 | | |
713 | | /* PIXMAN_KERNEL_CATMULL_ROM: Catmull-Rom interpolation. Often called |
714 | | "cubic interpolation", "b-spline", or just "cubic" by other |
715 | | software. This filter has negative values so it can produce ringing |
716 | | and output pixels outside the range of input pixels. This is very |
717 | | close to lanczos2 so there is no reason to supply that as well. |
718 | | */ |
719 | | |
720 | | static double |
721 | | cubic_kernel (double x, double r) |
722 | 0 | { |
723 | 0 | return general_cubic (x, r, 0.0, 0.5); |
724 | 0 | } |
725 | | |
726 | | /* PIXMAN_KERNEL_MITCHELL: Cubic recommended by the Mitchell-Netravali |
727 | | paper. This has negative values and because the values at +/-1 are |
728 | | not zero it does not interpolate the pixels, meaning it will change |
729 | | an image even if there is no translation. |
730 | | */ |
731 | | |
732 | | static double |
733 | | mitchell_kernel (double x, double r) |
734 | 0 | { |
735 | 0 | return general_cubic (x, r, 1/3.0, 1/3.0); |
736 | 0 | } |
737 | | |
738 | | /* PIXMAN_KERNEL_NOTCH: Cubic recommended by the Mitchell-Netravali |
739 | | paper to remove postaliasing artifacts. This does not remove |
740 | | aliasing already present in the source image, though it may appear |
741 | | to due to it's excessive blurriness. In any case this is more |
742 | | useful than gaussian for image reconstruction. |
743 | | */ |
744 | | |
745 | | static double |
746 | | notch_kernel (double x, double r) |
747 | 0 | { |
748 | 0 | return general_cubic (x, r, 1.5, -0.25); |
749 | 0 | } |
750 | | |
751 | | /* PIXMAN_KERNEL_LANCZOS3: lanczos windowed sinc function from -3 to |
752 | | +3. Very popular with high-end software though I think any |
753 | | advantage over cubics is hidden by quantization and programming |
754 | | mistakes. You will see LANCZOS5 or even 7 sometimes. |
755 | | */ |
756 | | |
757 | | static double |
758 | | sinc (double x) |
759 | 0 | { |
760 | 0 | return x ? sin (M_PI * x) / (M_PI * x) : 1.0; |
761 | 0 | } |
762 | | |
763 | | static double |
764 | | lanczos (double x, double n) |
765 | 0 | { |
766 | 0 | return fabs (x) < n ? sinc (x) * sinc (x * (1.0 / n)) : 0.0; |
767 | 0 | } |
768 | | |
769 | | static double |
770 | | lanczos3_kernel (double x, double r) |
771 | 0 | { |
772 | 0 | if (r < 1.0) |
773 | 0 | return |
774 | 0 | lanczos3_kernel (x * 2 - .5, r * 2) + |
775 | 0 | lanczos3_kernel (x * 2 + .5, r * 2); |
776 | 0 | else |
777 | 0 | return lanczos (x / r, 3.0); |
778 | 0 | } |
779 | | |
780 | | static int |
781 | | lanczos3_width (double r) |
782 | 0 | { |
783 | 0 | return MAX (2, ceil (r * 6)); |
784 | 0 | } |
785 | | |
786 | | /* PIXMAN_KERNEL_LANCZOS3_STRETCHED - The LANCZOS3 kernel widened by |
787 | | 4/3. Recommended by Jim Blinn |
788 | | http://graphics.cs.cmu.edu/nsp/course/15-462/Fall07/462/papers/jaggy.pdf |
789 | | */ |
790 | | |
791 | | static double |
792 | | nice_kernel (double x, double r) |
793 | 0 | { |
794 | 0 | return lanczos3_kernel (x, r * (4.0/3)); |
795 | 0 | } |
796 | | |
797 | | static int |
798 | | nice_width (double r) |
799 | 0 | { |
800 | 0 | return MAX (2.0, ceil (r * 8)); |
801 | 0 | } |
802 | | |
803 | | /* PIXMAN_KERNEL_TENT: Triangle of width 2r. Lots of software uses |
804 | | this as a "better" filter, twice the size of a box but smaller than |
805 | | a cubic. |
806 | | |
807 | | When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and |
808 | | PIXMAN_KERNEL_TENT all produce the same filter, allowing |
809 | | them to be exchanged at this point. |
810 | | */ |
811 | | |
812 | | static double |
813 | | tent_kernel (double x, double r) |
814 | 0 | { |
815 | 0 | if (r < 1.0) |
816 | 0 | return box_kernel(x, r); |
817 | 0 | else |
818 | 0 | return MAX (1.0 - fabs(x / r), 0.0); |
819 | 0 | } |
820 | | |
821 | | static int |
822 | | tent_width (double r) |
823 | 0 | { |
824 | 0 | return r < 1.0 ? 2 : ceil(2 * r); |
825 | 0 | } |
826 | | |
827 | | |
828 | | static const filter_info_t filters[] = |
829 | | { |
830 | | { KERNEL_IMPULSE, impulse_kernel, impulse_width }, |
831 | | { KERNEL_BOX, box_kernel, box_width }, |
832 | | { KERNEL_LINEAR, linear_kernel, linear_width }, |
833 | | { KERNEL_MITCHELL, mitchell_kernel, cubic_width }, |
834 | | { KERNEL_NOTCH, notch_kernel, cubic_width }, |
835 | | { KERNEL_CATMULL_ROM, cubic_kernel, cubic_width }, |
836 | | { KERNEL_LANCZOS3, lanczos3_kernel, lanczos3_width }, |
837 | | { KERNEL_LANCZOS3_STRETCHED,nice_kernel, nice_width }, |
838 | | { KERNEL_TENT, tent_kernel, tent_width } |
839 | | }; |
840 | | |
841 | | /* Fills in one dimension of the filter array */ |
842 | | static void get_filter(kernel_t filter, double r, |
843 | | int width, int subsample, |
844 | | pixman_fixed_t* out) |
845 | 188 | { |
846 | 188 | int i; |
847 | 188 | pixman_fixed_t *p = out; |
848 | 188 | int n_phases = 1 << subsample; |
849 | 188 | double step = 1.0 / n_phases; |
850 | 188 | kernel_func_t func = filters[filter].func; |
851 | | |
852 | | /* special-case the impulse filter: */ |
853 | 188 | if (width <= 1) |
854 | 0 | { |
855 | 0 | for (i = 0; i < n_phases; ++i) |
856 | 0 | *p++ = pixman_fixed_1; |
857 | 0 | return; |
858 | 0 | } |
859 | | |
860 | 33.5k | for (i = 0; i < n_phases; ++i) |
861 | 33.3k | { |
862 | 33.3k | double frac = (i + .5) * step; |
863 | | /* Center of left-most pixel: */ |
864 | 33.3k | double x1 = ceil (frac - width / 2.0 - 0.5) - frac + 0.5; |
865 | 33.3k | double total = 0; |
866 | 33.3k | pixman_fixed_t new_total = 0; |
867 | 33.3k | int j; |
868 | | |
869 | 113k | for (j = 0; j < width; ++j) |
870 | 80.1k | { |
871 | 80.1k | double v = func(x1 + j, r); |
872 | 80.1k | total += v; |
873 | 80.1k | p[j] = pixman_double_to_fixed (v); |
874 | 80.1k | } |
875 | | |
876 | | /* Normalize */ |
877 | 33.3k | total = 1 / total; |
878 | 113k | for (j = 0; j < width; ++j) |
879 | 80.1k | new_total += (p[j] *= total); |
880 | | |
881 | | /* Put any error on center pixel */ |
882 | 33.3k | p[width / 2] += (pixman_fixed_1 - new_total); |
883 | | |
884 | 33.3k | p += width; |
885 | 33.3k | } |
886 | 188 | } |
887 | | |
888 | | |
889 | | /* Create the parameter list for a SEPARABLE_CONVOLUTION filter |
890 | | * with the given kernels and scale parameters. |
891 | | */ |
892 | | static pixman_fixed_t * |
893 | | create_separable_convolution (int *n_values, |
894 | | kernel_t xfilter, |
895 | | double sx, |
896 | | kernel_t yfilter, |
897 | | double sy) |
898 | 94 | { |
899 | 94 | int xwidth, xsubsample, ywidth, ysubsample, size_x, size_y; |
900 | 94 | pixman_fixed_t *params; |
901 | | |
902 | 94 | xwidth = filters[xfilter].width(sx); |
903 | 94 | xsubsample = 0; |
904 | 94 | if (xwidth > 1) |
905 | 688 | while (sx * (1 << xsubsample) <= 128.0) xsubsample++; |
906 | 94 | size_x = (1 << xsubsample) * xwidth; |
907 | | |
908 | 94 | ywidth = filters[yfilter].width(sy); |
909 | 94 | ysubsample = 0; |
910 | 94 | if (ywidth > 1) |
911 | 846 | while (sy * (1 << ysubsample) <= 128.0) ysubsample++; |
912 | 94 | size_y = (1 << ysubsample) * ywidth; |
913 | | |
914 | 94 | *n_values = 4 + size_x + size_y; |
915 | 94 | params = _cairo_malloc (*n_values * sizeof (pixman_fixed_t)); |
916 | 94 | if (!params) return 0; |
917 | | |
918 | 94 | params[0] = pixman_int_to_fixed (xwidth); |
919 | 94 | params[1] = pixman_int_to_fixed (ywidth); |
920 | 94 | params[2] = pixman_int_to_fixed (xsubsample); |
921 | 94 | params[3] = pixman_int_to_fixed (ysubsample); |
922 | | |
923 | 94 | get_filter(xfilter, sx, xwidth, xsubsample, params + 4); |
924 | 94 | get_filter(yfilter, sy, ywidth, ysubsample, params + 4 + size_x); |
925 | | |
926 | 94 | return params; |
927 | 94 | } |
928 | | |
929 | | /* ========================================================================== */ |
930 | | |
931 | | static cairo_bool_t |
932 | | _pixman_image_set_properties (pixman_image_t *pixman_image, |
933 | | const cairo_pattern_t *pattern, |
934 | | const cairo_rectangle_int_t *extents, |
935 | | int *ix,int *iy) |
936 | 476 | { |
937 | 476 | pixman_transform_t pixman_transform; |
938 | 476 | cairo_int_status_t status; |
939 | | |
940 | 476 | status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix, |
941 | 476 | pattern->filter, |
942 | 476 | extents->x + extents->width/2., |
943 | 476 | extents->y + extents->height/2., |
944 | 476 | &pixman_transform, ix, iy); |
945 | 476 | if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
946 | 0 | { |
947 | | /* If the transform is an identity, we don't need to set it |
948 | | * and we can use any filtering, so choose the fastest one. */ |
949 | 0 | pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0); |
950 | 0 | } |
951 | 476 | else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS || |
952 | 476 | ! pixman_image_set_transform (pixman_image, |
953 | 476 | &pixman_transform))) |
954 | 29 | { |
955 | 29 | return FALSE; |
956 | 29 | } |
957 | 447 | else |
958 | 447 | { |
959 | 447 | pixman_filter_t pixman_filter; |
960 | 447 | kernel_t kernel; |
961 | 447 | double dx, dy; |
962 | | |
963 | | /* Compute scale factors from the pattern matrix. These scale |
964 | | * factors are from user to pattern space, and as such they |
965 | | * are greater than 1.0 for downscaling and less than 1.0 for |
966 | | * upscaling. The factors are the size of an axis-aligned |
967 | | * rectangle with the same area as the parallelgram a 1x1 |
968 | | * square transforms to. |
969 | | */ |
970 | 447 | dx = hypot (pattern->matrix.xx, pattern->matrix.xy); |
971 | 447 | dy = hypot (pattern->matrix.yx, pattern->matrix.yy); |
972 | | |
973 | | /* Clip at maximum pixman_fixed number. Besides making it |
974 | | * passable to pixman, this avoids errors from inf and nan. |
975 | | */ |
976 | 447 | if (! (dx < 0x7FFF)) dx = 0x7FFF; |
977 | 447 | if (! (dy < 0x7FFF)) dy = 0x7FFF; |
978 | | |
979 | 447 | switch (pattern->filter) { |
980 | 0 | case CAIRO_FILTER_FAST: |
981 | 0 | pixman_filter = PIXMAN_FILTER_FAST; |
982 | 0 | break; |
983 | 94 | case CAIRO_FILTER_GOOD: |
984 | 94 | pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION; |
985 | 94 | kernel = KERNEL_BOX; |
986 | | /* Clip the filter size to prevent extreme slowness. This |
987 | | value could be raised if 2-pass filtering is done */ |
988 | 94 | if (dx > 16.0) dx = 16.0; |
989 | 94 | if (dy > 16.0) dy = 16.0; |
990 | | /* Match the bilinear filter for scales > .75: */ |
991 | 94 | if (dx < 1.0/0.75) dx = 1.0; |
992 | 94 | if (dy < 1.0/0.75) dy = 1.0; |
993 | 94 | break; |
994 | 0 | case CAIRO_FILTER_BEST: |
995 | 0 | pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION; |
996 | 0 | kernel = KERNEL_CATMULL_ROM; /* LANCZOS3 is better but not much */ |
997 | | /* Clip the filter size to prevent extreme slowness. This |
998 | | value could be raised if 2-pass filtering is done */ |
999 | 0 | if (dx > 16.0) { dx = 16.0; kernel = KERNEL_BOX; } |
1000 | | /* blur up to 2x scale, then blend to square pixels for larger: */ |
1001 | 0 | else if (dx < 1.0) { |
1002 | 0 | if (dx < 1.0/128) dx = 1.0/127; |
1003 | 0 | else if (dx < 0.5) dx = 1.0 / (1.0 / dx - 1.0); |
1004 | 0 | else dx = 1.0; |
1005 | 0 | } |
1006 | 0 | if (dy > 16.0) { dy = 16.0; kernel = KERNEL_BOX; } |
1007 | 0 | else if (dy < 1.0) { |
1008 | 0 | if (dy < 1.0/128) dy = 1.0/127; |
1009 | 0 | else if (dy < 0.5) dy = 1.0 / (1.0 / dy - 1.0); |
1010 | 0 | else dy = 1.0; |
1011 | 0 | } |
1012 | 0 | break; |
1013 | 223 | case CAIRO_FILTER_NEAREST: |
1014 | 223 | pixman_filter = PIXMAN_FILTER_NEAREST; |
1015 | 223 | break; |
1016 | 130 | case CAIRO_FILTER_BILINEAR: |
1017 | 130 | pixman_filter = PIXMAN_FILTER_BILINEAR; |
1018 | 130 | break; |
1019 | 0 | case CAIRO_FILTER_GAUSSIAN: |
1020 | | /* XXX: The GAUSSIAN value has no implementation in cairo |
1021 | | * whatsoever, so it was really a mistake to have it in the |
1022 | | * API. We could fix this by officially deprecating it, or |
1023 | | * else inventing semantics and providing an actual |
1024 | | * implementation for it. */ |
1025 | 0 | default: |
1026 | 0 | pixman_filter = PIXMAN_FILTER_BEST; |
1027 | 447 | } |
1028 | | |
1029 | 447 | if (pixman_filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION) { |
1030 | 94 | int n_params; |
1031 | 94 | pixman_fixed_t *params; |
1032 | 94 | params = create_separable_convolution |
1033 | 94 | (&n_params, kernel, dx, kernel, dy); |
1034 | 94 | pixman_image_set_filter (pixman_image, pixman_filter, |
1035 | 94 | params, n_params); |
1036 | 94 | free (params); |
1037 | 353 | } else { |
1038 | 353 | pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0); |
1039 | 353 | } |
1040 | 447 | } |
1041 | | |
1042 | 447 | { |
1043 | 447 | pixman_repeat_t pixman_repeat; |
1044 | | |
1045 | 447 | switch (pattern->extend) { |
1046 | 0 | default: |
1047 | 0 | case CAIRO_EXTEND_NONE: |
1048 | 0 | pixman_repeat = PIXMAN_REPEAT_NONE; |
1049 | 0 | break; |
1050 | 0 | case CAIRO_EXTEND_REPEAT: |
1051 | 0 | pixman_repeat = PIXMAN_REPEAT_NORMAL; |
1052 | 0 | break; |
1053 | 0 | case CAIRO_EXTEND_REFLECT: |
1054 | 0 | pixman_repeat = PIXMAN_REPEAT_REFLECT; |
1055 | 0 | break; |
1056 | 447 | case CAIRO_EXTEND_PAD: |
1057 | 447 | pixman_repeat = PIXMAN_REPEAT_PAD; |
1058 | 447 | break; |
1059 | 447 | } |
1060 | | |
1061 | 447 | pixman_image_set_repeat (pixman_image, pixman_repeat); |
1062 | 447 | } |
1063 | | |
1064 | 447 | if (pattern->has_component_alpha) |
1065 | 0 | pixman_image_set_component_alpha (pixman_image, TRUE); |
1066 | | |
1067 | 447 | return TRUE; |
1068 | 447 | } |
1069 | | |
1070 | | struct proxy { |
1071 | | cairo_surface_t base; |
1072 | | cairo_surface_t *image; |
1073 | | }; |
1074 | | |
1075 | | static cairo_status_t |
1076 | | proxy_acquire_source_image (void *abstract_surface, |
1077 | | cairo_image_surface_t **image_out, |
1078 | | void **image_extra) |
1079 | 0 | { |
1080 | 0 | struct proxy *proxy = abstract_surface; |
1081 | 0 | return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra); |
1082 | 0 | } |
1083 | | |
1084 | | static void |
1085 | | proxy_release_source_image (void *abstract_surface, |
1086 | | cairo_image_surface_t *image, |
1087 | | void *image_extra) |
1088 | 0 | { |
1089 | 0 | struct proxy *proxy = abstract_surface; |
1090 | 0 | _cairo_surface_release_source_image (proxy->image, image, image_extra); |
1091 | 0 | } |
1092 | | |
1093 | | static cairo_status_t |
1094 | | proxy_finish (void *abstract_surface) |
1095 | 0 | { |
1096 | 0 | return CAIRO_STATUS_SUCCESS; |
1097 | 0 | } |
1098 | | |
1099 | | static const cairo_surface_backend_t proxy_backend = { |
1100 | | CAIRO_INTERNAL_SURFACE_TYPE_NULL, |
1101 | | proxy_finish, |
1102 | | NULL, |
1103 | | |
1104 | | NULL, /* create similar */ |
1105 | | NULL, /* create similar image */ |
1106 | | NULL, /* map to image */ |
1107 | | NULL, /* unmap image */ |
1108 | | |
1109 | | _cairo_surface_default_source, |
1110 | | proxy_acquire_source_image, |
1111 | | proxy_release_source_image, |
1112 | | }; |
1113 | | |
1114 | | static cairo_surface_t * |
1115 | | attach_proxy (cairo_surface_t *source, |
1116 | | cairo_surface_t *image) |
1117 | 0 | { |
1118 | 0 | struct proxy *proxy; |
1119 | |
|
1120 | 0 | proxy = _cairo_malloc (sizeof (*proxy)); |
1121 | 0 | if (unlikely (proxy == NULL)) |
1122 | 0 | return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); |
1123 | | |
1124 | 0 | _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content, FALSE); |
1125 | |
|
1126 | 0 | proxy->image = image; |
1127 | 0 | _cairo_surface_attach_snapshot (source, &proxy->base, NULL); |
1128 | |
|
1129 | 0 | return &proxy->base; |
1130 | 0 | } |
1131 | | |
1132 | | static void |
1133 | | detach_proxy (cairo_surface_t *source, |
1134 | | cairo_surface_t *proxy) |
1135 | 0 | { |
1136 | 0 | cairo_surface_finish (proxy); |
1137 | 0 | cairo_surface_destroy (proxy); |
1138 | 0 | } |
1139 | | |
1140 | | static cairo_surface_t * |
1141 | | get_proxy (cairo_surface_t *proxy) |
1142 | 0 | { |
1143 | 0 | return ((struct proxy *)proxy)->image; |
1144 | 0 | } |
1145 | | |
1146 | | static pixman_image_t * |
1147 | | _pixman_image_for_recording (cairo_image_surface_t *dst, |
1148 | | const cairo_surface_pattern_t *pattern, |
1149 | | cairo_bool_t is_mask, |
1150 | | const cairo_rectangle_int_t *extents, |
1151 | | const cairo_rectangle_int_t *sample, |
1152 | | int *ix, int *iy) |
1153 | 0 | { |
1154 | 0 | cairo_surface_t *source, *clone, *proxy; |
1155 | 0 | cairo_rectangle_int_t limit; |
1156 | 0 | cairo_rectangle_int_t src_limit; |
1157 | 0 | pixman_image_t *pixman_image; |
1158 | 0 | cairo_status_t status; |
1159 | 0 | cairo_extend_t extend; |
1160 | 0 | cairo_matrix_t *m, matrix; |
1161 | 0 | double sx = 1.0, sy = 1.0; |
1162 | 0 | int tx = 0, ty = 0; |
1163 | |
|
1164 | 0 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
1165 | |
|
1166 | 0 | *ix = *iy = 0; |
1167 | |
|
1168 | 0 | source = _cairo_pattern_get_source (pattern, &limit); |
1169 | 0 | src_limit = limit; |
1170 | |
|
1171 | 0 | extend = pattern->base.extend; |
1172 | 0 | if (_cairo_rectangle_contains_rectangle (&limit, sample)) |
1173 | 0 | extend = CAIRO_EXTEND_NONE; |
1174 | |
|
1175 | 0 | if (extend == CAIRO_EXTEND_NONE) { |
1176 | 0 | if (! _cairo_rectangle_intersect (&limit, sample)) |
1177 | 0 | return _pixman_transparent_image (); |
1178 | 0 | } |
1179 | | |
1180 | 0 | if (! _cairo_matrix_is_identity (&pattern->base.matrix)) { |
1181 | 0 | double x1, y1, x2, y2; |
1182 | |
|
1183 | 0 | matrix = pattern->base.matrix; |
1184 | 0 | status = cairo_matrix_invert (&matrix); |
1185 | 0 | assert (status == CAIRO_STATUS_SUCCESS); |
1186 | | |
1187 | 0 | x1 = limit.x; |
1188 | 0 | y1 = limit.y; |
1189 | 0 | x2 = limit.x + limit.width; |
1190 | 0 | y2 = limit.y + limit.height; |
1191 | |
|
1192 | 0 | _cairo_matrix_transform_bounding_box (&matrix, |
1193 | 0 | &x1, &y1, &x2, &y2, NULL); |
1194 | |
|
1195 | 0 | limit.x = floor (x1); |
1196 | 0 | limit.y = floor (y1); |
1197 | 0 | limit.width = ceil (x2) - limit.x; |
1198 | 0 | limit.height = ceil (y2) - limit.y; |
1199 | 0 | sx = (double)src_limit.width / limit.width; |
1200 | 0 | sy = (double)src_limit.height / limit.height; |
1201 | 0 | } |
1202 | 0 | tx = limit.x; |
1203 | 0 | ty = limit.y; |
1204 | | |
1205 | | /* XXX transformations! */ |
1206 | 0 | proxy = _cairo_surface_has_snapshot (source, &proxy_backend); |
1207 | 0 | if (proxy != NULL) { |
1208 | 0 | clone = cairo_surface_reference (get_proxy (proxy)); |
1209 | 0 | goto done; |
1210 | 0 | } |
1211 | | |
1212 | 0 | if (is_mask) { |
1213 | 0 | clone = cairo_image_surface_create (CAIRO_FORMAT_A8, |
1214 | 0 | limit.width, limit.height); |
1215 | 0 | } else { |
1216 | 0 | if (dst->base.content == source->content) |
1217 | 0 | clone = cairo_image_surface_create (dst->format, |
1218 | 0 | limit.width, limit.height); |
1219 | 0 | else |
1220 | 0 | clone = _cairo_image_surface_create_with_content (source->content, |
1221 | 0 | limit.width, |
1222 | 0 | limit.height); |
1223 | 0 | } |
1224 | |
|
1225 | 0 | m = NULL; |
1226 | 0 | if (extend == CAIRO_EXTEND_NONE) { |
1227 | 0 | matrix = pattern->base.matrix; |
1228 | 0 | if (tx | ty) |
1229 | 0 | cairo_matrix_translate (&matrix, tx, ty); |
1230 | 0 | m = &matrix; |
1231 | 0 | } else { |
1232 | 0 | cairo_matrix_init_scale (&matrix, sx, sy); |
1233 | 0 | cairo_matrix_translate (&matrix, src_limit.x/sx, src_limit.y/sy); |
1234 | 0 | m = &matrix; |
1235 | 0 | } |
1236 | | |
1237 | | /* Handle recursion by returning future reads from the current image */ |
1238 | 0 | proxy = attach_proxy (source, clone); |
1239 | 0 | status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL); |
1240 | 0 | detach_proxy (source, proxy); |
1241 | 0 | if (unlikely (status)) { |
1242 | 0 | cairo_surface_destroy (clone); |
1243 | 0 | return NULL; |
1244 | 0 | } |
1245 | | |
1246 | 0 | done: |
1247 | 0 | pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image); |
1248 | 0 | cairo_surface_destroy (clone); |
1249 | |
|
1250 | 0 | if (extend == CAIRO_EXTEND_NONE) { |
1251 | 0 | *ix = -limit.x; |
1252 | 0 | *iy = -limit.y; |
1253 | 0 | } else { |
1254 | 0 | cairo_pattern_union_t tmp_pattern; |
1255 | 0 | _cairo_pattern_init_static_copy (&tmp_pattern.base, &pattern->base); |
1256 | 0 | matrix = pattern->base.matrix; |
1257 | 0 | status = cairo_matrix_invert(&matrix); |
1258 | 0 | assert (status == CAIRO_STATUS_SUCCESS); |
1259 | 0 | cairo_matrix_translate (&matrix, src_limit.x, src_limit.y); |
1260 | 0 | cairo_matrix_scale (&matrix, sx, sy); |
1261 | 0 | status = cairo_matrix_invert(&matrix); |
1262 | 0 | assert (status == CAIRO_STATUS_SUCCESS); |
1263 | 0 | cairo_pattern_set_matrix (&tmp_pattern.base, &matrix); |
1264 | 0 | if (! _pixman_image_set_properties (pixman_image, |
1265 | 0 | &tmp_pattern.base, extents, |
1266 | 0 | ix, iy)) { |
1267 | 0 | pixman_image_unref (pixman_image); |
1268 | 0 | pixman_image= NULL; |
1269 | 0 | } |
1270 | 0 | } |
1271 | | |
1272 | 0 | return pixman_image; |
1273 | 0 | } |
1274 | | |
1275 | | static pixman_image_t * |
1276 | | _pixman_image_for_surface (cairo_image_surface_t *dst, |
1277 | | const cairo_surface_pattern_t *pattern, |
1278 | | cairo_bool_t is_mask, |
1279 | | const cairo_rectangle_int_t *extents, |
1280 | | const cairo_rectangle_int_t *sample, |
1281 | | int *ix, int *iy) |
1282 | 906 | { |
1283 | 906 | cairo_extend_t extend = pattern->base.extend; |
1284 | 906 | pixman_image_t *pixman_image; |
1285 | | |
1286 | 906 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
1287 | | |
1288 | 906 | *ix = *iy = 0; |
1289 | 906 | pixman_image = NULL; |
1290 | 906 | if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1291 | 0 | return _pixman_image_for_recording(dst, pattern, |
1292 | 0 | is_mask, extents, sample, |
1293 | 0 | ix, iy); |
1294 | | |
1295 | 906 | if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE && |
1296 | 906 | (! is_mask || ! pattern->base.has_component_alpha || |
1297 | 906 | (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0)) |
1298 | 906 | { |
1299 | 906 | cairo_surface_t *defer_free = NULL; |
1300 | 906 | cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface; |
1301 | 906 | cairo_surface_type_t type; |
1302 | | |
1303 | 906 | if (_cairo_surface_is_snapshot (&source->base)) { |
1304 | 0 | defer_free = _cairo_surface_snapshot_get_target (&source->base); |
1305 | 0 | source = (cairo_image_surface_t *) defer_free; |
1306 | 0 | } |
1307 | | |
1308 | 906 | type = source->base.backend->type; |
1309 | 906 | if (type == CAIRO_SURFACE_TYPE_IMAGE) { |
1310 | 906 | if (extend != CAIRO_EXTEND_NONE && |
1311 | 906 | sample->x >= 0 && |
1312 | 906 | sample->y >= 0 && |
1313 | 906 | sample->x + sample->width <= source->width && |
1314 | 906 | sample->y + sample->height <= source->height) |
1315 | 441 | { |
1316 | 441 | extend = CAIRO_EXTEND_NONE; |
1317 | 441 | } |
1318 | | |
1319 | 906 | if (sample->width == 1 && sample->height == 1) { |
1320 | 430 | if (sample->x < 0 || |
1321 | 430 | sample->y < 0 || |
1322 | 430 | sample->x >= source->width || |
1323 | 430 | sample->y >= source->height) |
1324 | 0 | { |
1325 | 0 | if (extend == CAIRO_EXTEND_NONE) { |
1326 | 0 | cairo_surface_destroy (defer_free); |
1327 | 0 | return _pixman_transparent_image (); |
1328 | 0 | } |
1329 | 0 | } |
1330 | 430 | else |
1331 | 430 | { |
1332 | 430 | pixman_image = _pixel_to_solid (source, |
1333 | 430 | sample->x, sample->y); |
1334 | 430 | if (pixman_image) { |
1335 | 430 | cairo_surface_destroy (defer_free); |
1336 | 430 | return pixman_image; |
1337 | 430 | } |
1338 | 430 | } |
1339 | 430 | } |
1340 | | |
1341 | | #if PIXMAN_HAS_ATOMIC_OPS |
1342 | | /* avoid allocating a 'pattern' image if we can reuse the original */ |
1343 | | if (extend == CAIRO_EXTEND_NONE && |
1344 | | _cairo_matrix_is_pixman_translation (&pattern->base.matrix, |
1345 | | pattern->base.filter, |
1346 | | ix, iy)) |
1347 | | { |
1348 | | cairo_surface_destroy (defer_free); |
1349 | | return pixman_image_ref (source->pixman_image); |
1350 | | } |
1351 | | #endif |
1352 | | |
1353 | 476 | pixman_image = pixman_image_create_bits (source->pixman_format, |
1354 | 476 | source->width, |
1355 | 476 | source->height, |
1356 | 476 | (uint32_t *) source->data, |
1357 | 476 | source->stride); |
1358 | 476 | if (unlikely (pixman_image == NULL)) { |
1359 | 0 | cairo_surface_destroy (defer_free); |
1360 | 0 | return NULL; |
1361 | 0 | } |
1362 | | |
1363 | 476 | if (defer_free) { |
1364 | 0 | pixman_image_set_destroy_function (pixman_image, |
1365 | 0 | _defer_free_cleanup, |
1366 | 0 | defer_free); |
1367 | 0 | } |
1368 | 476 | } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) { |
1369 | 0 | cairo_surface_subsurface_t *sub; |
1370 | 0 | cairo_bool_t is_contained = FALSE; |
1371 | |
|
1372 | 0 | sub = (cairo_surface_subsurface_t *) source; |
1373 | 0 | source = (cairo_image_surface_t *) sub->target; |
1374 | |
|
1375 | 0 | if (sample->x >= 0 && |
1376 | 0 | sample->y >= 0 && |
1377 | 0 | sample->x + sample->width <= sub->extents.width && |
1378 | 0 | sample->y + sample->height <= sub->extents.height) |
1379 | 0 | { |
1380 | 0 | is_contained = TRUE; |
1381 | 0 | } |
1382 | |
|
1383 | 0 | if (sample->width == 1 && sample->height == 1) { |
1384 | 0 | if (is_contained) { |
1385 | 0 | pixman_image = _pixel_to_solid (source, |
1386 | 0 | sub->extents.x + sample->x, |
1387 | 0 | sub->extents.y + sample->y); |
1388 | 0 | if (pixman_image) |
1389 | 0 | return pixman_image; |
1390 | 0 | } else { |
1391 | 0 | if (extend == CAIRO_EXTEND_NONE) |
1392 | 0 | return _pixman_transparent_image (); |
1393 | 0 | } |
1394 | 0 | } |
1395 | | |
1396 | | #if PIXMAN_HAS_ATOMIC_OPS |
1397 | | *ix = sub->extents.x; |
1398 | | *iy = sub->extents.y; |
1399 | | if (is_contained && |
1400 | | _cairo_matrix_is_pixman_translation (&pattern->base.matrix, |
1401 | | pattern->base.filter, |
1402 | | ix, iy)) |
1403 | | { |
1404 | | return pixman_image_ref (source->pixman_image); |
1405 | | } |
1406 | | #endif |
1407 | | |
1408 | | /* Avoid sub-byte offsets, force a copy in that case. */ |
1409 | 0 | if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) { |
1410 | 0 | if (is_contained) { |
1411 | 0 | void *data = source->data |
1412 | 0 | + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 |
1413 | 0 | + sub->extents.y * source->stride; |
1414 | 0 | pixman_image = pixman_image_create_bits (source->pixman_format, |
1415 | 0 | sub->extents.width, |
1416 | 0 | sub->extents.height, |
1417 | 0 | data, |
1418 | 0 | source->stride); |
1419 | 0 | if (unlikely (pixman_image == NULL)) |
1420 | 0 | return NULL; |
1421 | 0 | } else { |
1422 | | /* XXX for a simple translation and EXTEND_NONE we can |
1423 | | * fix up the pattern matrix instead. |
1424 | | */ |
1425 | 0 | } |
1426 | 0 | } |
1427 | 0 | } |
1428 | 906 | } |
1429 | | |
1430 | 476 | if (pixman_image == NULL) { |
1431 | 0 | struct acquire_source_cleanup *cleanup; |
1432 | 0 | cairo_image_surface_t *image; |
1433 | 0 | void *extra; |
1434 | 0 | cairo_status_t status; |
1435 | |
|
1436 | 0 | status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra); |
1437 | 0 | if (unlikely (status)) |
1438 | 0 | return NULL; |
1439 | | |
1440 | 0 | pixman_image = pixman_image_create_bits (image->pixman_format, |
1441 | 0 | image->width, |
1442 | 0 | image->height, |
1443 | 0 | (uint32_t *) image->data, |
1444 | 0 | image->stride); |
1445 | 0 | if (unlikely (pixman_image == NULL)) { |
1446 | 0 | _cairo_surface_release_source_image (pattern->surface, image, extra); |
1447 | 0 | return NULL; |
1448 | 0 | } |
1449 | | |
1450 | 0 | cleanup = _cairo_malloc (sizeof (*cleanup)); |
1451 | 0 | if (unlikely (cleanup == NULL)) { |
1452 | 0 | _cairo_surface_release_source_image (pattern->surface, image, extra); |
1453 | 0 | pixman_image_unref (pixman_image); |
1454 | 0 | return NULL; |
1455 | 0 | } |
1456 | | |
1457 | 0 | cleanup->surface = pattern->surface; |
1458 | 0 | cleanup->image = image; |
1459 | 0 | cleanup->image_extra = extra; |
1460 | 0 | pixman_image_set_destroy_function (pixman_image, |
1461 | 0 | _acquire_source_cleanup, cleanup); |
1462 | 0 | } |
1463 | | |
1464 | 476 | if (! _pixman_image_set_properties (pixman_image, |
1465 | 476 | &pattern->base, extents, |
1466 | 476 | ix, iy)) { |
1467 | 29 | pixman_image_unref (pixman_image); |
1468 | 29 | pixman_image= NULL; |
1469 | 29 | } |
1470 | | |
1471 | 476 | return pixman_image; |
1472 | 476 | } |
1473 | | |
1474 | | struct raster_source_cleanup { |
1475 | | const cairo_pattern_t *pattern; |
1476 | | cairo_surface_t *surface; |
1477 | | cairo_image_surface_t *image; |
1478 | | void *image_extra; |
1479 | | }; |
1480 | | |
1481 | | static void |
1482 | | _raster_source_cleanup (pixman_image_t *pixman_image, |
1483 | | void *closure) |
1484 | 0 | { |
1485 | 0 | struct raster_source_cleanup *data = closure; |
1486 | |
|
1487 | 0 | _cairo_surface_release_source_image (data->surface, |
1488 | 0 | data->image, |
1489 | 0 | data->image_extra); |
1490 | |
|
1491 | 0 | _cairo_raster_source_pattern_release (data->pattern, |
1492 | 0 | data->surface); |
1493 | |
|
1494 | 0 | free (data); |
1495 | 0 | } |
1496 | | |
1497 | | static pixman_image_t * |
1498 | | _pixman_image_for_raster (cairo_image_surface_t *dst, |
1499 | | const cairo_raster_source_pattern_t *pattern, |
1500 | | cairo_bool_t is_mask, |
1501 | | const cairo_rectangle_int_t *extents, |
1502 | | const cairo_rectangle_int_t *sample, |
1503 | | int *ix, int *iy) |
1504 | 0 | { |
1505 | 0 | pixman_image_t *pixman_image; |
1506 | 0 | struct raster_source_cleanup *cleanup; |
1507 | 0 | cairo_image_surface_t *image; |
1508 | 0 | void *extra; |
1509 | 0 | cairo_status_t status; |
1510 | 0 | cairo_surface_t *surface; |
1511 | |
|
1512 | 0 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
1513 | |
|
1514 | 0 | *ix = *iy = 0; |
1515 | |
|
1516 | 0 | surface = _cairo_raster_source_pattern_acquire (&pattern->base, |
1517 | 0 | &dst->base, NULL); |
1518 | 0 | if (unlikely (surface == NULL || surface->status)) |
1519 | 0 | return NULL; |
1520 | | |
1521 | 0 | status = _cairo_surface_acquire_source_image (surface, &image, &extra); |
1522 | 0 | if (unlikely (status)) { |
1523 | 0 | _cairo_raster_source_pattern_release (&pattern->base, surface); |
1524 | 0 | return NULL; |
1525 | 0 | } |
1526 | | |
1527 | 0 | assert (image->width == pattern->extents.width); |
1528 | 0 | assert (image->height == pattern->extents.height); |
1529 | | |
1530 | 0 | pixman_image = pixman_image_create_bits (image->pixman_format, |
1531 | 0 | image->width, |
1532 | 0 | image->height, |
1533 | 0 | (uint32_t *) image->data, |
1534 | 0 | image->stride); |
1535 | 0 | if (unlikely (pixman_image == NULL)) { |
1536 | 0 | _cairo_surface_release_source_image (surface, image, extra); |
1537 | 0 | _cairo_raster_source_pattern_release (&pattern->base, surface); |
1538 | 0 | return NULL; |
1539 | 0 | } |
1540 | | |
1541 | 0 | cleanup = _cairo_malloc (sizeof (*cleanup)); |
1542 | 0 | if (unlikely (cleanup == NULL)) { |
1543 | 0 | pixman_image_unref (pixman_image); |
1544 | 0 | _cairo_surface_release_source_image (surface, image, extra); |
1545 | 0 | _cairo_raster_source_pattern_release (&pattern->base, surface); |
1546 | 0 | return NULL; |
1547 | 0 | } |
1548 | | |
1549 | 0 | cleanup->pattern = &pattern->base; |
1550 | 0 | cleanup->surface = surface; |
1551 | 0 | cleanup->image = image; |
1552 | 0 | cleanup->image_extra = extra; |
1553 | 0 | pixman_image_set_destroy_function (pixman_image, |
1554 | 0 | _raster_source_cleanup, cleanup); |
1555 | |
|
1556 | 0 | if (! _pixman_image_set_properties (pixman_image, |
1557 | 0 | &pattern->base, extents, |
1558 | 0 | ix, iy)) { |
1559 | 0 | pixman_image_unref (pixman_image); |
1560 | 0 | pixman_image= NULL; |
1561 | 0 | } |
1562 | |
|
1563 | 0 | return pixman_image; |
1564 | 0 | } |
1565 | | |
1566 | | pixman_image_t * |
1567 | | _pixman_image_for_pattern (cairo_image_surface_t *dst, |
1568 | | const cairo_pattern_t *pattern, |
1569 | | cairo_bool_t is_mask, |
1570 | | const cairo_rectangle_int_t *extents, |
1571 | | const cairo_rectangle_int_t *sample, |
1572 | | int *tx, int *ty) |
1573 | 21.8k | { |
1574 | 21.8k | *tx = *ty = 0; |
1575 | | |
1576 | 21.8k | TRACE ((stderr, "%s\n", __FUNCTION__)); |
1577 | | |
1578 | 21.8k | if (pattern == NULL) |
1579 | 0 | return _pixman_white_image (); |
1580 | | |
1581 | 21.8k | switch (pattern->type) { |
1582 | 0 | default: |
1583 | 0 | ASSERT_NOT_REACHED; |
1584 | 17.8k | case CAIRO_PATTERN_TYPE_SOLID: |
1585 | 17.8k | return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color); |
1586 | | |
1587 | 2.48k | case CAIRO_PATTERN_TYPE_RADIAL: |
1588 | 3.06k | case CAIRO_PATTERN_TYPE_LINEAR: |
1589 | 3.06k | return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern, |
1590 | 3.06k | extents, tx, ty); |
1591 | | |
1592 | 0 | case CAIRO_PATTERN_TYPE_MESH: |
1593 | 0 | return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern, |
1594 | 0 | extents, tx, ty); |
1595 | | |
1596 | 906 | case CAIRO_PATTERN_TYPE_SURFACE: |
1597 | 906 | return _pixman_image_for_surface (dst, |
1598 | 906 | (const cairo_surface_pattern_t *) pattern, |
1599 | 906 | is_mask, extents, sample, |
1600 | 906 | tx, ty); |
1601 | | |
1602 | 0 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
1603 | 0 | return _pixman_image_for_raster (dst, |
1604 | 0 | (const cairo_raster_source_pattern_t *) pattern, |
1605 | 0 | is_mask, extents, sample, |
1606 | 0 | tx, ty); |
1607 | 21.8k | } |
1608 | 21.8k | } |
1609 | | |
1610 | | static cairo_status_t |
1611 | | _cairo_image_source_finish (void *abstract_surface) |
1612 | 21.7k | { |
1613 | 21.7k | cairo_image_source_t *source = abstract_surface; |
1614 | | |
1615 | 21.7k | pixman_image_unref (source->pixman_image); |
1616 | 21.7k | return CAIRO_STATUS_SUCCESS; |
1617 | 21.7k | } |
1618 | | |
1619 | | const cairo_surface_backend_t _cairo_image_source_backend = { |
1620 | | CAIRO_SURFACE_TYPE_IMAGE, |
1621 | | _cairo_image_source_finish, |
1622 | | NULL, /* read-only wrapper */ |
1623 | | }; |
1624 | | |
1625 | | cairo_surface_t * |
1626 | | _cairo_image_source_create_for_pattern (cairo_surface_t *dst, |
1627 | | const cairo_pattern_t *pattern, |
1628 | | cairo_bool_t is_mask, |
1629 | | const cairo_rectangle_int_t *extents, |
1630 | | const cairo_rectangle_int_t *sample, |
1631 | | int *src_x, int *src_y) |
1632 | 21.7k | { |
1633 | 21.7k | cairo_image_source_t *source; |
1634 | | |
1635 | 21.7k | TRACE ((stderr, "%s\n", __FUNCTION__)); |
1636 | | |
1637 | 21.7k | source = _cairo_malloc (sizeof (cairo_image_source_t)); |
1638 | 21.7k | if (unlikely (source == NULL)) |
1639 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
1640 | | |
1641 | 21.7k | source->pixman_image = |
1642 | 21.7k | _pixman_image_for_pattern ((cairo_image_surface_t *)dst, |
1643 | 21.7k | pattern, is_mask, |
1644 | 21.7k | extents, sample, |
1645 | 21.7k | src_x, src_y); |
1646 | 21.7k | if (unlikely (source->pixman_image == NULL)) { |
1647 | 29 | free (source); |
1648 | 29 | return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); |
1649 | 29 | } |
1650 | | |
1651 | 21.7k | _cairo_surface_init (&source->base, |
1652 | 21.7k | &_cairo_image_source_backend, |
1653 | 21.7k | NULL, /* device */ |
1654 | 21.7k | CAIRO_CONTENT_COLOR_ALPHA, |
1655 | 21.7k | FALSE); /* is_vector */ |
1656 | | |
1657 | 21.7k | source->is_opaque_solid = |
1658 | 21.7k | pattern == NULL || _cairo_pattern_is_opaque_solid (pattern); |
1659 | | |
1660 | 21.7k | return &source->base; |
1661 | 21.7k | } |