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
4 * Copyright © 2003 University of Southern California
5 * Copyright © 2009,2010,2011 Intel Corporation
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.
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
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/
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.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is University of Southern
36 * Carl D. Worth <cworth@cworth.org>
37 * Chris Wilson <chris@chris-wilson.co.uk>
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.
47 #include "cairo-image-surface-private.h"
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"
58 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
61 #define PIXMAN_HAS_ATOMIC_OPS 1
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;
69 static pixman_image_t *
70 _pixman_transparent_image (void)
72 pixman_image_t *image;
74 TRACE ((stderr, "%s\n", __FUNCTION__));
76 image = __pixman_transparent_image;
77 if (unlikely (image == NULL)) {
85 image = pixman_image_create_solid_fill (&color);
86 if (unlikely (image == NULL))
89 if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
92 pixman_image_ref (image);
95 pixman_image_ref (image);
101 static pixman_image_t *
102 _pixman_black_image (void)
104 pixman_image_t *image;
106 TRACE ((stderr, "%s\n", __FUNCTION__));
108 image = __pixman_black_image;
109 if (unlikely (image == NULL)) {
110 pixman_color_t color;
115 color.alpha = 0xffff;
117 image = pixman_image_create_solid_fill (&color);
118 if (unlikely (image == NULL))
121 if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
124 pixman_image_ref (image);
127 pixman_image_ref (image);
133 static pixman_image_t *
134 _pixman_white_image (void)
136 pixman_image_t *image;
138 TRACE ((stderr, "%s\n", __FUNCTION__));
140 image = __pixman_white_image;
141 if (unlikely (image == NULL)) {
142 pixman_color_t color;
145 color.green = 0xffff;
147 color.alpha = 0xffff;
149 image = pixman_image_create_solid_fill (&color);
150 if (unlikely (image == NULL))
153 if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
156 pixman_image_ref (image);
159 pixman_image_ref (image);
166 hars_petruska_f54_1_random (void)
168 #define rol(x,k) ((x << k) | (x >> (32-k)))
170 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
176 pixman_image_t *image;
180 #else /* !PIXMAN_HAS_ATOMIC_OPS */
181 static pixman_image_t *
182 _pixman_transparent_image (void)
184 TRACE ((stderr, "%s\n", __FUNCTION__));
185 return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
188 static pixman_image_t *
189 _pixman_black_image (void)
191 TRACE ((stderr, "%s\n", __FUNCTION__));
192 return _pixman_image_for_color (CAIRO_COLOR_BLACK);
195 static pixman_image_t *
196 _pixman_white_image (void)
198 TRACE ((stderr, "%s\n", __FUNCTION__));
199 return _pixman_image_for_color (CAIRO_COLOR_WHITE);
201 #endif /* !PIXMAN_HAS_ATOMIC_OPS */
205 _pixman_image_for_color (const cairo_color_t *cairo_color)
207 pixman_color_t color;
208 pixman_image_t *image;
210 #if PIXMAN_HAS_ATOMIC_OPS
213 if (CAIRO_COLOR_IS_CLEAR (cairo_color))
214 return _pixman_transparent_image ();
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)
221 return _pixman_black_image ();
224 if (cairo_color->red_short >= 0xff00 &&
225 cairo_color->green_short >= 0xff00 &&
226 cairo_color->blue_short >= 0xff00)
228 return _pixman_white_image ();
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);
241 color.red = cairo_color->red_short;
242 color.green = cairo_color->green_short;
243 color.blue = cairo_color->blue_short;
244 color.alpha = cairo_color->alpha_short;
246 image = pixman_image_create_solid_fill (&color);
247 #if PIXMAN_HAS_ATOMIC_OPS
251 if (n_cached < ARRAY_LENGTH (cache)) {
254 i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
255 pixman_image_unref (cache[i].image);
257 cache[i].image = pixman_image_ref (image);
258 cache[i].color = *cairo_color;
261 CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
268 _cairo_image_reset_static_data (void)
270 #if PIXMAN_HAS_ATOMIC_OPS
272 pixman_image_unref (cache[--n_cached].image);
274 if (__pixman_transparent_image) {
275 pixman_image_unref (__pixman_transparent_image);
276 __pixman_transparent_image = NULL;
279 if (__pixman_black_image) {
280 pixman_image_unref (__pixman_black_image);
281 __pixman_black_image = NULL;
284 if (__pixman_white_image) {
285 pixman_image_unref (__pixman_white_image);
286 __pixman_white_image = NULL;
291 static pixman_image_t *
292 _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
293 const cairo_rectangle_int_t *extents,
296 pixman_image_t *pixman_image;
297 pixman_gradient_stop_t pixman_stops_static[2];
298 pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
299 pixman_transform_t pixman_transform;
300 cairo_matrix_t matrix;
301 cairo_circle_double_t extremes[2];
302 pixman_point_fixed_t p1, p2;
304 cairo_int_status_t status;
306 TRACE ((stderr, "%s\n", __FUNCTION__));
308 if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
309 pixman_stops = _cairo_malloc_ab (pattern->n_stops,
310 sizeof(pixman_gradient_stop_t));
311 if (unlikely (pixman_stops == NULL))
315 for (i = 0; i < pattern->n_stops; i++) {
316 pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
317 pixman_stops[i].color.red = pattern->stops[i].color.red_short;
318 pixman_stops[i].color.green = pattern->stops[i].color.green_short;
319 pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
320 pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
323 _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
325 p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
326 p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
327 p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
328 p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
330 if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
331 pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
335 pixman_fixed_t r1, r2;
337 r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
338 r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
340 pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
345 if (pixman_stops != pixman_stops_static)
348 if (unlikely (pixman_image == NULL))
352 status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
353 extents->x + extents->width/2.,
354 extents->y + extents->height/2.,
355 &pixman_transform, ix, iy);
356 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
357 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
358 ! pixman_image_set_transform (pixman_image, &pixman_transform))
360 pixman_image_unref (pixman_image);
366 pixman_repeat_t pixman_repeat;
368 switch (pattern->base.extend) {
370 case CAIRO_EXTEND_NONE:
371 pixman_repeat = PIXMAN_REPEAT_NONE;
373 case CAIRO_EXTEND_REPEAT:
374 pixman_repeat = PIXMAN_REPEAT_NORMAL;
376 case CAIRO_EXTEND_REFLECT:
377 pixman_repeat = PIXMAN_REPEAT_REFLECT;
379 case CAIRO_EXTEND_PAD:
380 pixman_repeat = PIXMAN_REPEAT_PAD;
384 pixman_image_set_repeat (pixman_image, pixman_repeat);
390 static pixman_image_t *
391 _pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
392 const cairo_rectangle_int_t *extents,
395 pixman_image_t *image;
398 TRACE ((stderr, "%s\n", __FUNCTION__));
402 width = extents->width;
403 height = extents->height;
405 image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
406 if (unlikely (image == NULL))
409 _cairo_mesh_pattern_rasterize (pattern,
410 pixman_image_get_data (image),
412 pixman_image_get_stride (image),
417 struct acquire_source_cleanup {
418 cairo_surface_t *surface;
419 cairo_image_surface_t *image;
424 _acquire_source_cleanup (pixman_image_t *pixman_image,
427 struct acquire_source_cleanup *data = closure;
429 _cairo_surface_release_source_image (data->surface,
436 _defer_free_cleanup (pixman_image_t *pixman_image,
439 cairo_surface_destroy (closure);
443 expand_channel (uint16_t v, uint32_t bits)
445 int offset = 16 - bits;
454 static pixman_image_t *
455 _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
458 pixman_color_t color;
460 TRACE ((stderr, "%s\n", __FUNCTION__));
462 switch (image->format) {
464 case CAIRO_FORMAT_INVALID:
468 case CAIRO_FORMAT_A1:
469 pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
470 return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
472 case CAIRO_FORMAT_A8:
473 color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
474 color.alpha |= color.alpha << 8;
475 if (color.alpha == 0)
476 return _pixman_transparent_image ();
477 if (color.alpha == 0xffff)
478 return _pixman_black_image ();
480 color.red = color.green = color.blue = 0;
481 return pixman_image_create_solid_fill (&color);
483 case CAIRO_FORMAT_RGB16_565:
484 pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
486 return _pixman_black_image ();
488 return _pixman_white_image ();
490 color.alpha = 0xffff;
491 color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
492 color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
493 color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
494 return pixman_image_create_solid_fill (&color);
496 case CAIRO_FORMAT_RGB30:
497 pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
498 pixel &= 0x3fffffff; /* ignore alpha bits */
500 return _pixman_black_image ();
501 if (pixel == 0x3fffffff)
502 return _pixman_white_image ();
504 /* convert 10bpc to 16bpc */
505 color.alpha = 0xffff;
506 color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
507 color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
508 color.blue = expand_channel(pixel & 0x3fff, 10);
509 return pixman_image_create_solid_fill (&color);
511 case CAIRO_FORMAT_ARGB32:
512 case CAIRO_FORMAT_RGB24:
513 pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
514 color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
515 if (color.alpha == 0)
516 return _pixman_transparent_image ();
517 if (pixel == 0xffffffff)
518 return _pixman_white_image ();
519 if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
520 return _pixman_black_image ();
522 color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
523 color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
524 color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
525 return pixman_image_create_solid_fill (&color);
530 _pixman_image_set_properties (pixman_image_t *pixman_image,
531 const cairo_pattern_t *pattern,
532 const cairo_rectangle_int_t *extents,
535 pixman_transform_t pixman_transform;
536 cairo_int_status_t status;
538 status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
540 extents->x + extents->width/2.,
541 extents->y + extents->height/2.,
542 &pixman_transform, ix, iy);
543 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
545 /* If the transform is an identity, we don't need to set it
546 * and we can use any filtering, so choose the fastest one. */
547 pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
549 else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
550 ! pixman_image_set_transform (pixman_image,
557 pixman_filter_t pixman_filter;
559 switch (pattern->filter) {
560 case CAIRO_FILTER_FAST:
561 pixman_filter = PIXMAN_FILTER_FAST;
563 case CAIRO_FILTER_GOOD:
564 pixman_filter = PIXMAN_FILTER_GOOD;
566 case CAIRO_FILTER_BEST:
567 pixman_filter = PIXMAN_FILTER_BEST;
569 case CAIRO_FILTER_NEAREST:
570 pixman_filter = PIXMAN_FILTER_NEAREST;
572 case CAIRO_FILTER_BILINEAR:
573 pixman_filter = PIXMAN_FILTER_BILINEAR;
575 case CAIRO_FILTER_GAUSSIAN:
576 /* XXX: The GAUSSIAN value has no implementation in cairo
577 * whatsoever, so it was really a mistake to have it in the
578 * API. We could fix this by officially deprecating it, or
579 * else inventing semantics and providing an actual
580 * implementation for it. */
582 pixman_filter = PIXMAN_FILTER_BEST;
585 pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
589 pixman_repeat_t pixman_repeat;
591 switch (pattern->extend) {
593 case CAIRO_EXTEND_NONE:
594 pixman_repeat = PIXMAN_REPEAT_NONE;
596 case CAIRO_EXTEND_REPEAT:
597 pixman_repeat = PIXMAN_REPEAT_NORMAL;
599 case CAIRO_EXTEND_REFLECT:
600 pixman_repeat = PIXMAN_REPEAT_REFLECT;
602 case CAIRO_EXTEND_PAD:
603 pixman_repeat = PIXMAN_REPEAT_PAD;
607 pixman_image_set_repeat (pixman_image, pixman_repeat);
610 if (pattern->has_component_alpha)
611 pixman_image_set_component_alpha (pixman_image, TRUE);
617 cairo_surface_t base;
618 cairo_surface_t *image;
621 static cairo_status_t
622 proxy_acquire_source_image (void *abstract_surface,
623 cairo_image_surface_t **image_out,
626 struct proxy *proxy = abstract_surface;
627 return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
631 proxy_release_source_image (void *abstract_surface,
632 cairo_image_surface_t *image,
635 struct proxy *proxy = abstract_surface;
636 _cairo_surface_release_source_image (proxy->image, image, image_extra);
639 static cairo_status_t
640 proxy_finish (void *abstract_surface)
642 return CAIRO_STATUS_SUCCESS;
645 static const cairo_surface_backend_t proxy_backend = {
646 CAIRO_INTERNAL_SURFACE_TYPE_NULL,
650 NULL, /* create similar */
651 NULL, /* create similar image */
652 NULL, /* map to image */
653 NULL, /* unmap image */
655 _cairo_surface_default_source,
656 proxy_acquire_source_image,
657 proxy_release_source_image,
660 static cairo_surface_t *
661 attach_proxy (cairo_surface_t *source,
662 cairo_surface_t *image)
666 proxy = malloc (sizeof (*proxy));
667 if (unlikely (proxy == NULL))
668 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
670 _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content);
672 proxy->image = image;
673 _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
679 detach_proxy (cairo_surface_t *source,
680 cairo_surface_t *proxy)
682 cairo_surface_finish (proxy);
683 cairo_surface_destroy (proxy);
686 static cairo_surface_t *
687 get_proxy (cairo_surface_t *proxy)
689 return ((struct proxy *)proxy)->image;
692 static pixman_image_t *
693 _pixman_image_for_recording (cairo_image_surface_t *dst,
694 const cairo_surface_pattern_t *pattern,
695 cairo_bool_t is_mask,
696 const cairo_rectangle_int_t *extents,
697 const cairo_rectangle_int_t *sample,
700 cairo_surface_t *source, *clone, *proxy;
701 cairo_rectangle_int_t limit;
702 pixman_image_t *pixman_image;
703 cairo_status_t status;
704 cairo_extend_t extend;
705 cairo_matrix_t *m, matrix;
708 TRACE ((stderr, "%s\n", __FUNCTION__));
712 source = _cairo_pattern_get_source (pattern, &limit);
714 extend = pattern->base.extend;
715 if (_cairo_rectangle_contains_rectangle (&limit, sample))
716 extend = CAIRO_EXTEND_NONE;
717 if (extend == CAIRO_EXTEND_NONE) {
718 if (! _cairo_rectangle_intersect (&limit, sample))
719 return _pixman_transparent_image ();
721 if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
722 double x1, y1, x2, y2;
724 matrix = pattern->base.matrix;
725 status = cairo_matrix_invert (&matrix);
726 assert (status == CAIRO_STATUS_SUCCESS);
730 x2 = limit.x + limit.width;
731 y2 = limit.y + limit.height;
733 _cairo_matrix_transform_bounding_box (&matrix,
734 &x1, &y1, &x2, &y2, NULL);
736 limit.x = floor (x1);
737 limit.y = floor (y1);
738 limit.width = ceil (x2) - limit.x;
739 limit.height = ceil (y2) - limit.y;
745 /* XXX transformations! */
746 proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
748 clone = cairo_surface_reference (get_proxy (proxy));
753 clone = cairo_image_surface_create (CAIRO_FORMAT_A8,
754 limit.width, limit.height);
756 if (dst->base.content == source->content)
757 clone = cairo_image_surface_create (dst->format,
758 limit.width, limit.height);
760 clone = _cairo_image_surface_create_with_content (source->content,
766 if (extend == CAIRO_EXTEND_NONE) {
767 matrix = pattern->base.matrix;
769 cairo_matrix_translate (&matrix, tx, ty);
772 /* XXX extract scale factor for repeating patterns */
775 /* Handle recursion by returning future reads from the current image */
776 proxy = attach_proxy (source, clone);
777 status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
778 detach_proxy (source, proxy);
779 if (unlikely (status)) {
780 cairo_surface_destroy (clone);
785 pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image);
786 cairo_surface_destroy (clone);
790 if (extend != CAIRO_EXTEND_NONE) {
791 if (! _pixman_image_set_properties (pixman_image,
792 &pattern->base, extents,
794 pixman_image_unref (pixman_image);
802 static pixman_image_t *
803 _pixman_image_for_surface (cairo_image_surface_t *dst,
804 const cairo_surface_pattern_t *pattern,
805 cairo_bool_t is_mask,
806 const cairo_rectangle_int_t *extents,
807 const cairo_rectangle_int_t *sample,
810 cairo_extend_t extend = pattern->base.extend;
811 pixman_image_t *pixman_image;
813 TRACE ((stderr, "%s\n", __FUNCTION__));
817 if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
818 return _pixman_image_for_recording(dst, pattern,
819 is_mask, extents, sample,
822 if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
823 (! is_mask || ! pattern->base.has_component_alpha ||
824 (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
826 cairo_surface_t *defer_free = NULL;
827 cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
828 cairo_surface_type_t type;
830 if (_cairo_surface_is_snapshot (&source->base)) {
831 defer_free = _cairo_surface_snapshot_get_target (&source->base);
832 source = (cairo_image_surface_t *) defer_free;
835 type = source->base.backend->type;
836 if (type == CAIRO_SURFACE_TYPE_IMAGE) {
837 if (extend != CAIRO_EXTEND_NONE &&
840 sample->x + sample->width <= source->width &&
841 sample->y + sample->height <= source->height)
843 extend = CAIRO_EXTEND_NONE;
846 if (sample->width == 1 && sample->height == 1) {
849 sample->x >= source->width ||
850 sample->y >= source->height)
852 if (extend == CAIRO_EXTEND_NONE) {
853 cairo_surface_destroy (defer_free);
854 return _pixman_transparent_image ();
859 pixman_image = _pixel_to_solid (source,
860 sample->x, sample->y);
862 cairo_surface_destroy (defer_free);
868 #if PIXMAN_HAS_ATOMIC_OPS
869 /* avoid allocating a 'pattern' image if we can reuse the original */
870 if (extend == CAIRO_EXTEND_NONE &&
871 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
872 pattern->base.filter,
875 cairo_surface_destroy (defer_free);
876 return pixman_image_ref (source->pixman_image);
880 pixman_image = pixman_image_create_bits (source->pixman_format,
883 (uint32_t *) source->data,
885 if (unlikely (pixman_image == NULL)) {
886 cairo_surface_destroy (defer_free);
891 pixman_image_set_destroy_function (pixman_image,
895 } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
896 cairo_surface_subsurface_t *sub;
897 cairo_bool_t is_contained = FALSE;
899 sub = (cairo_surface_subsurface_t *) source;
900 source = (cairo_image_surface_t *) sub->target;
902 if (sample->x >= 0 &&
904 sample->x + sample->width <= sub->extents.width &&
905 sample->y + sample->height <= sub->extents.height)
910 if (sample->width == 1 && sample->height == 1) {
912 pixman_image = _pixel_to_solid (source,
913 sub->extents.x + sample->x,
914 sub->extents.y + sample->y);
918 if (extend == CAIRO_EXTEND_NONE)
919 return _pixman_transparent_image ();
923 #if PIXMAN_HAS_ATOMIC_OPS
924 *ix = sub->extents.x;
925 *iy = sub->extents.y;
927 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
928 pattern->base.filter,
931 return pixman_image_ref (source->pixman_image);
935 /* Avoid sub-byte offsets, force a copy in that case. */
936 if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
938 void *data = source->data
939 + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
940 + sub->extents.y * source->stride;
941 pixman_image = pixman_image_create_bits (source->pixman_format,
946 if (unlikely (pixman_image == NULL))
949 /* XXX for a simple translation and EXTEND_NONE we can
950 * fix up the pattern matrix instead.
957 if (pixman_image == NULL) {
958 struct acquire_source_cleanup *cleanup;
959 cairo_image_surface_t *image;
961 cairo_status_t status;
963 status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
964 if (unlikely (status))
967 pixman_image = pixman_image_create_bits (image->pixman_format,
970 (uint32_t *) image->data,
972 if (unlikely (pixman_image == NULL)) {
973 _cairo_surface_release_source_image (pattern->surface, image, extra);
977 cleanup = malloc (sizeof (*cleanup));
978 if (unlikely (cleanup == NULL)) {
979 _cairo_surface_release_source_image (pattern->surface, image, extra);
980 pixman_image_unref (pixman_image);
984 cleanup->surface = pattern->surface;
985 cleanup->image = image;
986 cleanup->image_extra = extra;
987 pixman_image_set_destroy_function (pixman_image,
988 _acquire_source_cleanup, cleanup);
991 if (! _pixman_image_set_properties (pixman_image,
992 &pattern->base, extents,
994 pixman_image_unref (pixman_image);
1001 struct raster_source_cleanup {
1002 const cairo_pattern_t *pattern;
1003 cairo_surface_t *surface;
1004 cairo_image_surface_t *image;
1009 _raster_source_cleanup (pixman_image_t *pixman_image,
1012 struct raster_source_cleanup *data = closure;
1014 _cairo_surface_release_source_image (data->surface,
1018 _cairo_raster_source_pattern_release (data->pattern,
1024 static pixman_image_t *
1025 _pixman_image_for_raster (cairo_image_surface_t *dst,
1026 const cairo_raster_source_pattern_t *pattern,
1027 cairo_bool_t is_mask,
1028 const cairo_rectangle_int_t *extents,
1029 const cairo_rectangle_int_t *sample,
1032 pixman_image_t *pixman_image;
1033 struct raster_source_cleanup *cleanup;
1034 cairo_image_surface_t *image;
1036 cairo_status_t status;
1037 cairo_surface_t *surface;
1039 TRACE ((stderr, "%s\n", __FUNCTION__));
1043 surface = _cairo_raster_source_pattern_acquire (&pattern->base,
1045 if (unlikely (surface == NULL || surface->status))
1048 status = _cairo_surface_acquire_source_image (surface, &image, &extra);
1049 if (unlikely (status)) {
1050 _cairo_raster_source_pattern_release (&pattern->base, surface);
1054 assert (image->width == pattern->extents.width);
1055 assert (image->height == pattern->extents.height);
1057 pixman_image = pixman_image_create_bits (image->pixman_format,
1060 (uint32_t *) image->data,
1062 if (unlikely (pixman_image == NULL)) {
1063 _cairo_surface_release_source_image (surface, image, extra);
1064 _cairo_raster_source_pattern_release (&pattern->base, surface);
1068 cleanup = malloc (sizeof (*cleanup));
1069 if (unlikely (cleanup == NULL)) {
1070 pixman_image_unref (pixman_image);
1071 _cairo_surface_release_source_image (surface, image, extra);
1072 _cairo_raster_source_pattern_release (&pattern->base, surface);
1076 cleanup->pattern = &pattern->base;
1077 cleanup->surface = surface;
1078 cleanup->image = image;
1079 cleanup->image_extra = extra;
1080 pixman_image_set_destroy_function (pixman_image,
1081 _raster_source_cleanup, cleanup);
1083 if (! _pixman_image_set_properties (pixman_image,
1084 &pattern->base, extents,
1086 pixman_image_unref (pixman_image);
1090 return pixman_image;
1094 _pixman_image_for_pattern (cairo_image_surface_t *dst,
1095 const cairo_pattern_t *pattern,
1096 cairo_bool_t is_mask,
1097 const cairo_rectangle_int_t *extents,
1098 const cairo_rectangle_int_t *sample,
1103 TRACE ((stderr, "%s\n", __FUNCTION__));
1105 if (pattern == NULL)
1106 return _pixman_white_image ();
1108 switch (pattern->type) {
1111 case CAIRO_PATTERN_TYPE_SOLID:
1112 return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
1114 case CAIRO_PATTERN_TYPE_RADIAL:
1115 case CAIRO_PATTERN_TYPE_LINEAR:
1116 return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
1119 case CAIRO_PATTERN_TYPE_MESH:
1120 return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
1123 case CAIRO_PATTERN_TYPE_SURFACE:
1124 return _pixman_image_for_surface (dst,
1125 (const cairo_surface_pattern_t *) pattern,
1126 is_mask, extents, sample,
1129 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1130 return _pixman_image_for_raster (dst,
1131 (const cairo_raster_source_pattern_t *) pattern,
1132 is_mask, extents, sample,
1137 static cairo_status_t
1138 _cairo_image_source_finish (void *abstract_surface)
1140 cairo_image_source_t *source = abstract_surface;
1142 pixman_image_unref (source->pixman_image);
1143 return CAIRO_STATUS_SUCCESS;
1146 const cairo_surface_backend_t _cairo_image_source_backend = {
1147 CAIRO_SURFACE_TYPE_IMAGE,
1148 _cairo_image_source_finish,
1149 NULL, /* read-only wrapper */
1153 _cairo_image_source_create_for_pattern (cairo_surface_t *dst,
1154 const cairo_pattern_t *pattern,
1155 cairo_bool_t is_mask,
1156 const cairo_rectangle_int_t *extents,
1157 const cairo_rectangle_int_t *sample,
1158 int *src_x, int *src_y)
1160 cairo_image_source_t *source;
1162 TRACE ((stderr, "%s\n", __FUNCTION__));
1164 source = malloc (sizeof (cairo_image_source_t));
1165 if (unlikely (source == NULL))
1166 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1168 source->pixman_image =
1169 _pixman_image_for_pattern ((cairo_image_surface_t *)dst,
1173 if (unlikely (source->pixman_image == NULL)) {
1175 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
1178 _cairo_surface_init (&source->base,
1179 &_cairo_image_source_backend,
1181 CAIRO_CONTENT_COLOR_ALPHA);
1183 source->is_opaque_solid =
1184 pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
1186 return &source->base;