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