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"
57 #include "cairo-image-filters-private.h"
59 #if CAIRO_HAS_TG_SURFACE
60 #include "cairo-tg-private.h"
63 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
66 #define PIXMAN_HAS_ATOMIC_OPS 1
69 #if PIXMAN_HAS_ATOMIC_OPS
70 static pixman_image_t *__pixman_transparent_image;
71 static pixman_image_t *__pixman_black_image;
72 static pixman_image_t *__pixman_white_image;
74 static pixman_image_t *
75 _pixman_transparent_image (void)
77 pixman_image_t *image;
79 TRACE ((stderr, "%s\n", __FUNCTION__));
81 image = __pixman_transparent_image;
82 if (unlikely (image == NULL)) {
90 image = pixman_image_create_solid_fill (&color);
91 if (unlikely (image == NULL))
94 if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
97 pixman_image_ref (image);
100 pixman_image_ref (image);
106 static pixman_image_t *
107 _pixman_black_image (void)
109 pixman_image_t *image;
111 TRACE ((stderr, "%s\n", __FUNCTION__));
113 image = __pixman_black_image;
114 if (unlikely (image == NULL)) {
115 pixman_color_t color;
120 color.alpha = 0xffff;
122 image = pixman_image_create_solid_fill (&color);
123 if (unlikely (image == NULL))
126 if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
129 pixman_image_ref (image);
132 pixman_image_ref (image);
138 static pixman_image_t *
139 _pixman_white_image (void)
141 pixman_image_t *image;
143 TRACE ((stderr, "%s\n", __FUNCTION__));
145 image = __pixman_white_image;
146 if (unlikely (image == NULL)) {
147 pixman_color_t color;
150 color.green = 0xffff;
152 color.alpha = 0xffff;
154 image = pixman_image_create_solid_fill (&color);
155 if (unlikely (image == NULL))
158 if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
161 pixman_image_ref (image);
164 pixman_image_ref (image);
171 hars_petruska_f54_1_random (void)
173 #define rol(x,k) ((x << k) | (x >> (32-k)))
175 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
181 pixman_image_t *image;
185 #else /* !PIXMAN_HAS_ATOMIC_OPS */
186 static pixman_image_t *
187 _pixman_transparent_image (void)
189 TRACE ((stderr, "%s\n", __FUNCTION__));
190 return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
193 static pixman_image_t *
194 _pixman_black_image (void)
196 TRACE ((stderr, "%s\n", __FUNCTION__));
197 return _pixman_image_for_color (CAIRO_COLOR_BLACK);
200 static pixman_image_t *
201 _pixman_white_image (void)
203 TRACE ((stderr, "%s\n", __FUNCTION__));
204 return _pixman_image_for_color (CAIRO_COLOR_WHITE);
206 #endif /* !PIXMAN_HAS_ATOMIC_OPS */
210 _pixman_image_for_color (const cairo_color_t *cairo_color)
212 pixman_color_t color;
213 pixman_image_t *image;
215 #if PIXMAN_HAS_ATOMIC_OPS
218 if (CAIRO_COLOR_IS_CLEAR (cairo_color))
219 return _pixman_transparent_image ();
221 if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) {
222 if (cairo_color->red_short <= 0x00ff &&
223 cairo_color->green_short <= 0x00ff &&
224 cairo_color->blue_short <= 0x00ff)
226 return _pixman_black_image ();
229 if (cairo_color->red_short >= 0xff00 &&
230 cairo_color->green_short >= 0xff00 &&
231 cairo_color->blue_short >= 0xff00)
233 return _pixman_white_image ();
237 CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
238 for (i = 0; i < n_cached; i++) {
239 if (_cairo_color_equal (&cache[i].color, cairo_color)) {
240 image = pixman_image_ref (cache[i].image);
246 color.red = cairo_color->red_short;
247 color.green = cairo_color->green_short;
248 color.blue = cairo_color->blue_short;
249 color.alpha = cairo_color->alpha_short;
251 image = pixman_image_create_solid_fill (&color);
252 #if PIXMAN_HAS_ATOMIC_OPS
256 if (n_cached < ARRAY_LENGTH (cache)) {
259 i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
260 pixman_image_unref (cache[i].image);
262 cache[i].image = pixman_image_ref (image);
263 cache[i].color = *cairo_color;
266 CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
273 _cairo_image_reset_static_data (void)
275 #if PIXMAN_HAS_ATOMIC_OPS
277 pixman_image_unref (cache[--n_cached].image);
279 if (__pixman_transparent_image) {
280 pixman_image_unref (__pixman_transparent_image);
281 __pixman_transparent_image = NULL;
284 if (__pixman_black_image) {
285 pixman_image_unref (__pixman_black_image);
286 __pixman_black_image = NULL;
289 if (__pixman_white_image) {
290 pixman_image_unref (__pixman_white_image);
291 __pixman_white_image = NULL;
296 static pixman_image_t *
297 _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
298 const cairo_rectangle_int_t *extents,
301 pixman_image_t *pixman_image;
302 pixman_gradient_stop_t pixman_stops_static[2];
303 pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
304 pixman_transform_t pixman_transform;
305 cairo_matrix_t matrix;
306 cairo_circle_double_t extremes[2];
307 pixman_point_fixed_t p1, p2;
309 cairo_int_status_t status;
311 TRACE ((stderr, "%s\n", __FUNCTION__));
313 if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
314 pixman_stops = _cairo_malloc_ab (pattern->n_stops,
315 sizeof(pixman_gradient_stop_t));
316 if (unlikely (pixman_stops == NULL))
320 for (i = 0; i < pattern->n_stops; i++) {
321 pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
322 pixman_stops[i].color.red = pattern->stops[i].color.red_short;
323 pixman_stops[i].color.green = pattern->stops[i].color.green_short;
324 pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
325 pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
328 _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
330 p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
331 p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
332 p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
333 p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
335 if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
336 pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
340 pixman_fixed_t r1, r2;
342 r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
343 r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
345 pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
350 if (pixman_stops != pixman_stops_static)
353 if (unlikely (pixman_image == NULL))
357 status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
358 extents->x + extents->width/2.,
359 extents->y + extents->height/2.,
360 &pixman_transform, ix, iy);
361 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
362 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
363 ! pixman_image_set_transform (pixman_image, &pixman_transform))
365 pixman_image_unref (pixman_image);
371 pixman_repeat_t pixman_repeat;
373 switch (pattern->base.extend) {
375 case CAIRO_EXTEND_NONE:
376 pixman_repeat = PIXMAN_REPEAT_NONE;
378 case CAIRO_EXTEND_REPEAT:
379 pixman_repeat = PIXMAN_REPEAT_NORMAL;
381 case CAIRO_EXTEND_REFLECT:
382 pixman_repeat = PIXMAN_REPEAT_REFLECT;
384 case CAIRO_EXTEND_PAD:
385 pixman_repeat = PIXMAN_REPEAT_PAD;
389 pixman_image_set_repeat (pixman_image, pixman_repeat);
395 static pixman_image_t *
396 _pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
397 const cairo_rectangle_int_t *extents,
400 pixman_image_t *image;
403 TRACE ((stderr, "%s\n", __FUNCTION__));
407 width = extents->width;
408 height = extents->height;
410 image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
411 if (unlikely (image == NULL))
414 _cairo_mesh_pattern_rasterize (pattern,
415 pixman_image_get_data (image),
417 pixman_image_get_stride (image),
422 struct acquire_source_cleanup {
423 cairo_surface_t *surface;
424 cairo_image_surface_t *image;
429 _acquire_source_cleanup (pixman_image_t *pixman_image,
432 struct acquire_source_cleanup *data = closure;
434 _cairo_surface_release_source_image (data->surface,
441 _defer_free_cleanup (pixman_image_t *pixman_image,
444 cairo_surface_destroy (closure);
447 typedef struct _cairo_image_buffer
449 cairo_format_t format;
454 pixman_image_t *pixman_image;
455 pixman_format_code_t pixman_format;
456 } cairo_image_buffer_t;
459 _get_image_buffer (cairo_surface_t *surface, cairo_image_buffer_t *image_buffer)
461 if (surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE)
463 cairo_image_surface_t *image = (cairo_image_surface_t *)surface;
465 image_buffer->format = image->format;
466 image_buffer->data = image->data;
467 image_buffer->width = image->width;
468 image_buffer->height = image->height;
469 image_buffer->stride = image->stride;
470 image_buffer->pixman_image = image->pixman_image;
471 image_buffer->pixman_format = image->pixman_format;
473 #if CAIRO_HAS_TG_SURFACE
474 else if (surface->backend->type == CAIRO_SURFACE_TYPE_TG)
476 cairo_tg_surface_t *tg = (cairo_tg_surface_t *)surface;
478 image_buffer->format = tg->format;
479 image_buffer->data = tg->data;
480 image_buffer->width = tg->width;
481 image_buffer->height = tg->height;
482 image_buffer->stride = tg->stride;
483 image_buffer->pixman_image = ((cairo_image_surface_t *)(tg->image_surface))->pixman_image;
484 image_buffer->pixman_format = ((cairo_image_surface_t *)(tg->image_surface))->pixman_format;
486 /* flush the journal to make the memory image_buffer up-to-date. */
487 cairo_surface_flush (surface);
493 expand_channel (uint16_t v, uint32_t bits)
495 int offset = 16 - bits;
504 static pixman_image_t *
505 _pixel_to_solid (const cairo_image_buffer_t *image_buffer, int x, int y)
508 pixman_color_t color;
510 TRACE ((stderr, "%s\n", __FUNCTION__));
512 switch (image_buffer->format) {
514 case CAIRO_FORMAT_INVALID:
518 case CAIRO_FORMAT_A1:
519 pixel = *(uint8_t *) (image_buffer->data + y * image_buffer->stride + x/8);
520 return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
522 case CAIRO_FORMAT_A8:
523 color.alpha = *(uint8_t *) (image_buffer->data + y * image_buffer->stride + x);
524 color.alpha |= color.alpha << 8;
525 if (color.alpha == 0)
526 return _pixman_transparent_image ();
527 if (color.alpha == 0xffff)
528 return _pixman_black_image ();
530 color.red = color.green = color.blue = 0;
531 return pixman_image_create_solid_fill (&color);
533 case CAIRO_FORMAT_RGB16_565:
534 pixel = *(uint16_t *) (image_buffer->data + y * image_buffer->stride + 2 * x);
536 return _pixman_black_image ();
538 return _pixman_white_image ();
540 color.alpha = 0xffff;
541 color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
542 color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
543 color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
544 return pixman_image_create_solid_fill (&color);
546 case CAIRO_FORMAT_RGB30:
547 pixel = *(uint32_t *) (image_buffer->data + y * image_buffer->stride + 4 * x);
548 pixel &= 0x3fffffff; /* ignore alpha bits */
550 return _pixman_black_image ();
551 if (pixel == 0x3fffffff)
552 return _pixman_white_image ();
554 /* convert 10bpc to 16bpc */
555 color.alpha = 0xffff;
556 color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
557 color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
558 color.blue = expand_channel(pixel & 0x3fff, 10);
559 return pixman_image_create_solid_fill (&color);
561 case CAIRO_FORMAT_ARGB32:
562 case CAIRO_FORMAT_RGB24:
563 pixel = *(uint32_t *) (image_buffer->data + y * image_buffer->stride + 4 * x);
564 color.alpha = image_buffer->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
565 if (color.alpha == 0)
566 return _pixman_transparent_image ();
567 if (pixel == 0xffffffff)
568 return _pixman_white_image ();
569 if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
570 return _pixman_black_image ();
572 color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
573 color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
574 color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
575 return pixman_image_create_solid_fill (&color);
580 _pixman_image_set_properties (pixman_image_t *pixman_image,
581 const cairo_pattern_t *pattern,
582 const cairo_rectangle_int_t *extents,
585 pixman_transform_t pixman_transform;
586 cairo_int_status_t status;
588 status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
590 extents->x + extents->width/2.,
591 extents->y + extents->height/2.,
592 &pixman_transform, ix, iy);
593 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
595 /* If the transform is an identity, we don't need to set it
596 * and we can use any filtering, so choose the fastest one. */
597 pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
599 else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
600 ! pixman_image_set_transform (pixman_image,
607 pixman_filter_t pixman_filter;
609 switch (pattern->filter) {
610 case CAIRO_FILTER_FAST:
611 pixman_filter = PIXMAN_FILTER_FAST;
613 case CAIRO_FILTER_GOOD:
614 pixman_filter = PIXMAN_FILTER_GOOD;
616 case CAIRO_FILTER_BEST:
617 pixman_filter = PIXMAN_FILTER_BEST;
619 case CAIRO_FILTER_NEAREST:
620 pixman_filter = PIXMAN_FILTER_NEAREST;
622 case CAIRO_FILTER_BILINEAR:
623 pixman_filter = PIXMAN_FILTER_BILINEAR;
625 case CAIRO_FILTER_GAUSSIAN:
626 /* XXX: The GAUSSIAN value has no implementation in cairo
627 * whatsoever, so it was really a mistake to have it in the
628 * API. We could fix this by officially deprecating it, or
629 * else inventing semantics and providing an actual
630 * implementation for it. */
632 pixman_filter = PIXMAN_FILTER_BEST;
635 pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
639 pixman_repeat_t pixman_repeat;
641 switch (pattern->extend) {
643 case CAIRO_EXTEND_NONE:
644 pixman_repeat = PIXMAN_REPEAT_NONE;
646 case CAIRO_EXTEND_REPEAT:
647 pixman_repeat = PIXMAN_REPEAT_NORMAL;
649 case CAIRO_EXTEND_REFLECT:
650 pixman_repeat = PIXMAN_REPEAT_REFLECT;
652 case CAIRO_EXTEND_PAD:
653 pixman_repeat = PIXMAN_REPEAT_PAD;
657 pixman_image_set_repeat (pixman_image, pixman_repeat);
660 if (pattern->has_component_alpha)
661 pixman_image_set_component_alpha (pixman_image, TRUE);
667 cairo_surface_t base;
668 cairo_surface_t *image;
671 static cairo_status_t
672 proxy_acquire_source_image (void *abstract_surface,
673 cairo_image_surface_t **image_out,
676 struct proxy *proxy = abstract_surface;
677 return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
681 proxy_release_source_image (void *abstract_surface,
682 cairo_image_surface_t *image,
685 struct proxy *proxy = abstract_surface;
686 _cairo_surface_release_source_image (proxy->image, image, image_extra);
689 static cairo_status_t
690 proxy_finish (void *abstract_surface)
692 return CAIRO_STATUS_SUCCESS;
695 static const cairo_surface_backend_t proxy_backend = {
696 CAIRO_INTERNAL_SURFACE_TYPE_NULL,
700 NULL, /* create similar */
701 NULL, /* create similar image */
702 NULL, /* map to image */
703 NULL, /* unmap image */
705 _cairo_surface_default_source,
706 proxy_acquire_source_image,
707 proxy_release_source_image,
710 static cairo_surface_t *
711 attach_proxy (cairo_surface_t *source,
712 cairo_surface_t *image)
716 proxy = malloc (sizeof (*proxy));
717 if (unlikely (proxy == NULL))
718 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
720 _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content);
722 proxy->image = image;
723 _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
729 detach_proxy (cairo_surface_t *source,
730 cairo_surface_t *proxy)
732 cairo_surface_finish (proxy);
733 cairo_surface_destroy (proxy);
736 static cairo_surface_t *
737 get_proxy (cairo_surface_t *proxy)
739 return ((struct proxy *)proxy)->image;
742 static pixman_image_t *
743 _pixman_image_for_recording (cairo_image_surface_t *dst,
744 const cairo_surface_pattern_t *pattern,
745 cairo_bool_t is_mask,
746 const cairo_rectangle_int_t *extents,
747 const cairo_rectangle_int_t *sample,
750 cairo_surface_t *source, *clone, *proxy;
751 cairo_rectangle_int_t limit;
752 pixman_image_t *pixman_image;
753 cairo_status_t status;
754 cairo_extend_t extend;
755 cairo_matrix_t *m, matrix;
757 cairo_surface_t *blurred_surface;
759 TRACE ((stderr, "%s\n", __FUNCTION__));
763 source = _cairo_pattern_get_source (pattern, &limit);
765 extend = pattern->base.extend;
766 if (_cairo_rectangle_contains_rectangle (&limit, sample))
767 extend = CAIRO_EXTEND_NONE;
768 if (extend == CAIRO_EXTEND_NONE) {
769 if (! _cairo_rectangle_intersect (&limit, sample))
770 return _pixman_transparent_image ();
772 if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
773 double x1, y1, x2, y2;
775 matrix = pattern->base.matrix;
776 status = cairo_matrix_invert (&matrix);
777 assert (status == CAIRO_STATUS_SUCCESS);
781 x2 = limit.x + limit.width;
782 y2 = limit.y + limit.height;
784 _cairo_matrix_transform_bounding_box (&matrix,
785 &x1, &y1, &x2, &y2, NULL);
787 limit.x = floor (x1);
788 limit.y = floor (y1);
789 limit.width = ceil (x2) - limit.x;
790 limit.height = ceil (y2) - limit.y;
796 /* XXX transformations! */
797 proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
799 clone = cairo_surface_reference (get_proxy (proxy));
804 clone = cairo_image_surface_create (CAIRO_FORMAT_A8,
805 limit.width, limit.height);
807 if (dst->base.content == source->content)
808 clone = cairo_image_surface_create (dst->format,
809 limit.width, limit.height);
811 clone = _cairo_image_surface_create_with_content (source->content,
817 if (extend == CAIRO_EXTEND_NONE) {
818 matrix = pattern->base.matrix;
820 cairo_matrix_translate (&matrix, tx, ty);
823 /* XXX extract scale factor for repeating patterns */
826 /* Handle recursion by returning future reads from the current image */
827 proxy = attach_proxy (source, clone);
828 status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
829 detach_proxy (source, proxy);
830 if (unlikely (status)) {
831 cairo_surface_destroy (clone);
836 /* filter with gaussian */
837 blurred_surface = _cairo_image_gaussian_filter (clone, &pattern->base);
839 pixman_image = pixman_image_ref (((cairo_image_surface_t *)blurred_surface)->pixman_image);
840 cairo_surface_destroy (blurred_surface);
841 cairo_surface_destroy (clone);
845 if (extend != CAIRO_EXTEND_NONE) {
846 if (! _pixman_image_set_properties (pixman_image,
847 &pattern->base, extents,
849 pixman_image_unref (pixman_image);
857 static inline cairo_bool_t
858 _surface_type_is_image_buffer (cairo_surface_type_t type)
860 #if CAIRO_HAS_TG_SURFACE
861 return type == CAIRO_SURFACE_TYPE_IMAGE || type == CAIRO_SURFACE_TYPE_TG;
863 return type == CAIRO_SURFACE_TYPE_IMAGE;
867 static pixman_image_t *
868 _pixman_image_for_surface (cairo_image_surface_t *dst,
869 const cairo_surface_pattern_t *pattern,
870 cairo_bool_t is_mask,
871 const cairo_rectangle_int_t *extents,
872 const cairo_rectangle_int_t *sample,
875 cairo_extend_t extend = pattern->base.extend;
876 pixman_image_t *pixman_image = NULL;
877 pixman_image_t *blurred_pixman_image = NULL;
878 cairo_surface_t *blurred_surface = NULL;
880 TRACE ((stderr, "%s\n", __FUNCTION__));
884 if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
885 return _pixman_image_for_recording(dst, pattern,
886 is_mask, extents, sample,
889 if (_surface_type_is_image_buffer (pattern->surface->type) &&
890 (! is_mask || ! pattern->base.has_component_alpha ||
891 (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
893 cairo_surface_t *defer_free = NULL;
894 cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
895 cairo_image_buffer_t image_buffer;
897 if (_cairo_surface_is_snapshot (&source->base)) {
898 defer_free = _cairo_surface_snapshot_get_target (&source->base);
899 source = (cairo_image_surface_t *) defer_free;
902 if (_surface_type_is_image_buffer (source->base.backend->type)) {
903 _get_image_buffer (source, &image_buffer);
905 if (extend != CAIRO_EXTEND_NONE &&
908 sample->x + sample->width <= image_buffer.width &&
909 sample->y + sample->height <= image_buffer.height)
911 extend = CAIRO_EXTEND_NONE;
914 if (sample->width == 1 && sample->height == 1) {
917 sample->x >= image_buffer.width ||
918 sample->y >= image_buffer.height)
920 if (extend == CAIRO_EXTEND_NONE) {
921 cairo_surface_destroy (defer_free);
922 return _pixman_transparent_image ();
927 pixman_image = _pixel_to_solid (&image_buffer, sample->x, sample->y);
929 cairo_surface_destroy (defer_free);
935 #if PIXMAN_HAS_ATOMIC_OPS
936 /* avoid allocating a 'pattern' image if we can reuse the original */
937 if (extend == CAIRO_EXTEND_NONE &&
938 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
939 pattern->base.filter,
942 cairo_surface_destroy (defer_free);
943 /* filter with gaussian */
944 if (pattern->filter == CAIRO_FILTER_GAUSSIAN) {
945 blurred_surface = _cairo_image_gaussian_filter (&source->base, &pattern->base);
946 blurred_pixman_image = pixman_image_ref (((cairo_image_surface_t *)blurred_surface)->pixman_image);
947 cairo_surface_destroy (blurred_surface);
948 return blurred_pixman_image;
951 return pixman_image_ref (image_buffer.pixman_image);
955 if (pattern->base.filter != CAIRO_FILTER_GAUSSIAN) {
956 pixman_image = pixman_image_create_bits (image_buffer.pixman_format,
959 (uint32_t *) image_buffer.data,
960 image_buffer.stride);
961 if (unlikely (pixman_image == NULL)) {
962 cairo_surface_destroy (defer_free);
964 cairo_surface_destroy (blurred_surface);
965 if (blurred_pixman_image)
966 pixman_image_unref (blurred_pixman_image);
971 pixman_image_set_destroy_function (pixman_image,
977 blurred_surface = _cairo_image_gaussian_filter (&source->base, &pattern->base);
978 } else if (source->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
979 cairo_surface_subsurface_t *sub;
980 cairo_bool_t is_contained = FALSE;
982 sub = (cairo_surface_subsurface_t *) source;
983 source = sub->target;
985 _get_image_buffer (source, &image_buffer);
987 if (sample->x >= 0 &&
989 sample->x + sample->width <= sub->extents.width &&
990 sample->y + sample->height <= sub->extents.height)
995 if (sample->width == 1 && sample->height == 1) {
997 pixman_image = _pixel_to_solid (&image_buffer,
998 sub->extents.x + sample->x,
999 sub->extents.y + sample->y);
1001 return pixman_image;
1003 if (extend == CAIRO_EXTEND_NONE)
1004 return _pixman_transparent_image ();
1008 #if PIXMAN_HAS_ATOMIC_OPS
1009 *ix = sub->extents.x;
1010 *iy = sub->extents.y;
1012 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
1013 pattern->base.filter,
1016 /* filter with gaussian */
1017 if (pattern->filter == CAIRO_FILTER_GAUSSIAN) {
1018 blurred_surface = _cairo_image_gaussian_filter (&source->base, &pattern->base);
1019 blurred_pixman_image = pixman_image_ref (((cairo_image_surface_t *)blurred_surface)->pixman_image);
1020 cairo_surface_destroy (blurred_surface);
1021 return blurred_pixman_image;
1026 /* Avoid sub-byte offsets, force a copy in that case. */
1027 if (pattern->base.filter != CAIRO_FILTER_GAUSSIAN) {
1028 if (PIXMAN_FORMAT_BPP (image_buffer.pixman_format) >= 8) {
1030 void *data = image_buffer.data
1031 + sub->extents.x * PIXMAN_FORMAT_BPP(image_buffer.pixman_format)/8
1032 + sub->extents.y * image_buffer.stride;
1033 pixman_image = pixman_image_create_bits (image_buffer.pixman_format,
1035 sub->extents.height,
1037 image_buffer.stride);
1038 if (unlikely (pixman_image == NULL)) {
1039 if (blurred_surface)
1040 cairo_surface_destroy (blurred_surface);
1041 if (blurred_pixman_image)
1042 pixman_image_unref (blurred_pixman_image);
1046 /* XXX for a simple translation and EXTEND_NONE we can
1047 * fix up the pattern matrix instead.
1054 blurred_surface = _cairo_image_gaussian_filter (&source->base, &pattern->base);
1058 if (pixman_image == NULL && blurred_surface == NULL) {
1059 struct acquire_source_cleanup *cleanup;
1060 cairo_image_surface_t *image;
1062 cairo_status_t status;
1064 status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
1065 if (unlikely (status)) {
1066 if (blurred_surface)
1067 cairo_surface_destroy (blurred_surface);
1068 if (blurred_pixman_image)
1069 pixman_image_unref (blurred_pixman_image);
1073 if (pattern->base.filter != CAIRO_FILTER_GAUSSIAN) {
1074 pixman_image = pixman_image_create_bits (image->pixman_format,
1077 (uint32_t *) image->data,
1079 if (unlikely (pixman_image == NULL)) {
1080 _cairo_surface_release_source_image (pattern->surface, image, extra);
1081 if (blurred_surface)
1082 cairo_surface_destroy (blurred_surface);
1083 if (blurred_pixman_image)
1084 pixman_image_unref (blurred_pixman_image);
1089 /* filter with gaussian */
1090 blurred_surface = _cairo_image_gaussian_filter (&image->base, &pattern->base);
1092 cleanup = malloc (sizeof (*cleanup));
1093 if (unlikely (cleanup == NULL)) {
1094 _cairo_surface_release_source_image (pattern->surface, image, extra);
1096 pixman_image_unref (pixman_image);
1097 if (blurred_surface)
1098 cairo_surface_destroy (blurred_surface);
1099 if (blurred_pixman_image)
1100 pixman_image_unref (blurred_pixman_image);
1105 cleanup->surface = pattern->surface;
1106 cleanup->image = image;
1107 cleanup->image_extra = extra;
1108 pixman_image_set_destroy_function (pixman_image,
1109 _acquire_source_cleanup, cleanup);
1113 if (blurred_surface) {
1114 blurred_pixman_image = pixman_image_ref (((cairo_image_surface_t *)blurred_surface)->pixman_image);
1115 cairo_surface_destroy (blurred_surface);
1118 if (blurred_pixman_image) {
1119 if (! _pixman_image_set_properties (blurred_pixman_image,
1120 &pattern->base, extents,
1122 pixman_image_unref (blurred_pixman_image);
1123 blurred_pixman_image= NULL;
1127 if (! _pixman_image_set_properties (pixman_image,
1128 &pattern->base, extents,
1130 pixman_image_unref (pixman_image);
1135 if (blurred_pixman_image) {
1137 pixman_image_unref (pixman_image);
1140 blurred_pixman_image = pixman_image;
1142 return blurred_pixman_image;
1145 struct raster_source_cleanup {
1146 const cairo_pattern_t *pattern;
1147 cairo_surface_t *surface;
1148 cairo_image_surface_t *image;
1153 _raster_source_cleanup (pixman_image_t *pixman_image,
1156 struct raster_source_cleanup *data = closure;
1158 _cairo_surface_release_source_image (data->surface,
1162 _cairo_raster_source_pattern_release (data->pattern,
1168 static pixman_image_t *
1169 _pixman_image_for_raster (cairo_image_surface_t *dst,
1170 const cairo_raster_source_pattern_t *pattern,
1171 cairo_bool_t is_mask,
1172 const cairo_rectangle_int_t *extents,
1173 const cairo_rectangle_int_t *sample,
1176 pixman_image_t *pixman_image;
1177 struct raster_source_cleanup *cleanup;
1178 cairo_image_surface_t *image;
1180 cairo_status_t status;
1181 cairo_surface_t *surface;
1183 TRACE ((stderr, "%s\n", __FUNCTION__));
1187 surface = _cairo_raster_source_pattern_acquire (&pattern->base,
1189 if (unlikely (surface == NULL || surface->status))
1192 status = _cairo_surface_acquire_source_image (surface, &image, &extra);
1193 if (unlikely (status)) {
1194 _cairo_raster_source_pattern_release (&pattern->base, surface);
1198 assert (image->width == pattern->extents.width);
1199 assert (image->height == pattern->extents.height);
1201 pixman_image = pixman_image_create_bits (image->pixman_format,
1204 (uint32_t *) image->data,
1206 if (unlikely (pixman_image == NULL)) {
1207 _cairo_surface_release_source_image (surface, image, extra);
1208 _cairo_raster_source_pattern_release (&pattern->base, surface);
1212 cleanup = malloc (sizeof (*cleanup));
1213 if (unlikely (cleanup == NULL)) {
1214 pixman_image_unref (pixman_image);
1215 _cairo_surface_release_source_image (surface, image, extra);
1216 _cairo_raster_source_pattern_release (&pattern->base, surface);
1220 cleanup->pattern = &pattern->base;
1221 cleanup->surface = surface;
1222 cleanup->image = image;
1223 cleanup->image_extra = extra;
1224 pixman_image_set_destroy_function (pixman_image,
1225 _raster_source_cleanup, cleanup);
1227 if (! _pixman_image_set_properties (pixman_image,
1228 &pattern->base, extents,
1230 pixman_image_unref (pixman_image);
1234 return pixman_image;
1238 _pixman_image_for_pattern (cairo_image_surface_t *dst,
1239 const cairo_pattern_t *pattern,
1240 cairo_bool_t is_mask,
1241 const cairo_rectangle_int_t *extents,
1242 const cairo_rectangle_int_t *sample,
1247 TRACE ((stderr, "%s\n", __FUNCTION__));
1249 if (pattern == NULL)
1250 return _pixman_white_image ();
1252 switch (pattern->type) {
1255 case CAIRO_PATTERN_TYPE_SOLID:
1256 return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
1258 case CAIRO_PATTERN_TYPE_RADIAL:
1259 case CAIRO_PATTERN_TYPE_LINEAR:
1260 return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
1263 case CAIRO_PATTERN_TYPE_MESH:
1264 return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
1267 case CAIRO_PATTERN_TYPE_SURFACE:
1268 return _pixman_image_for_surface (dst,
1269 (const cairo_surface_pattern_t *) pattern,
1270 is_mask, extents, sample,
1273 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1274 return _pixman_image_for_raster (dst,
1275 (const cairo_raster_source_pattern_t *) pattern,
1276 is_mask, extents, sample,
1281 static cairo_status_t
1282 _cairo_image_source_finish (void *abstract_surface)
1284 cairo_image_source_t *source = abstract_surface;
1286 pixman_image_unref (source->pixman_image);
1287 return CAIRO_STATUS_SUCCESS;
1290 const cairo_surface_backend_t _cairo_image_source_backend = {
1291 CAIRO_SURFACE_TYPE_IMAGE,
1292 _cairo_image_source_finish,
1293 NULL, /* read-only wrapper */
1297 _cairo_image_source_create_for_pattern (cairo_surface_t *dst,
1298 const cairo_pattern_t *pattern,
1299 cairo_bool_t is_mask,
1300 const cairo_rectangle_int_t *extents,
1301 const cairo_rectangle_int_t *sample,
1302 int *src_x, int *src_y)
1304 cairo_image_source_t *source;
1306 TRACE ((stderr, "%s\n", __FUNCTION__));
1308 source = malloc (sizeof (cairo_image_source_t));
1309 if (unlikely (source == NULL))
1310 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1312 source->pixman_image =
1313 _pixman_image_for_pattern ((cairo_image_surface_t *)dst,
1317 if (unlikely (source->pixman_image == NULL)) {
1319 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
1322 _cairo_surface_init (&source->base,
1323 &_cairo_image_source_backend,
1325 CAIRO_CONTENT_COLOR_ALPHA);
1327 source->is_opaque_solid =
1328 pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
1330 return &source->base;