Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-image-source.c
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 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
59
60 #if CAIRO_NO_MUTEX
61 #define PIXMAN_HAS_ATOMIC_OPS 1
62 #endif
63
64 #if PIXMAN_HAS_ATOMIC_OPS
65 static pixman_image_t *__pixman_transparent_image;
66 static pixman_image_t *__pixman_black_image;
67 static pixman_image_t *__pixman_white_image;
68
69 static pixman_image_t *
70 _pixman_transparent_image (void)
71 {
72     pixman_image_t *image;
73
74     TRACE ((stderr, "%s\n", __FUNCTION__));
75
76     image = __pixman_transparent_image;
77     if (unlikely (image == NULL)) {
78         pixman_color_t color;
79
80         color.red   = 0x00;
81         color.green = 0x00;
82         color.blue  = 0x00;
83         color.alpha = 0x00;
84
85         image = pixman_image_create_solid_fill (&color);
86         if (unlikely (image == NULL))
87             return NULL;
88
89         if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
90                                        NULL, image))
91         {
92             pixman_image_ref (image);
93         }
94     } else {
95         pixman_image_ref (image);
96     }
97
98     return image;
99 }
100
101 static pixman_image_t *
102 _pixman_black_image (void)
103 {
104     pixman_image_t *image;
105
106     TRACE ((stderr, "%s\n", __FUNCTION__));
107
108     image = __pixman_black_image;
109     if (unlikely (image == NULL)) {
110         pixman_color_t color;
111
112         color.red   = 0x00;
113         color.green = 0x00;
114         color.blue  = 0x00;
115         color.alpha = 0xffff;
116
117         image = pixman_image_create_solid_fill (&color);
118         if (unlikely (image == NULL))
119             return NULL;
120
121         if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
122                                        NULL, image))
123         {
124             pixman_image_ref (image);
125         }
126     } else {
127         pixman_image_ref (image);
128     }
129
130     return image;
131 }
132
133 static pixman_image_t *
134 _pixman_white_image (void)
135 {
136     pixman_image_t *image;
137
138     TRACE ((stderr, "%s\n", __FUNCTION__));
139
140     image = __pixman_white_image;
141     if (unlikely (image == NULL)) {
142         pixman_color_t color;
143
144         color.red   = 0xffff;
145         color.green = 0xffff;
146         color.blue  = 0xffff;
147         color.alpha = 0xffff;
148
149         image = pixman_image_create_solid_fill (&color);
150         if (unlikely (image == NULL))
151             return NULL;
152
153         if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
154                                        NULL, image))
155         {
156             pixman_image_ref (image);
157         }
158     } else {
159         pixman_image_ref (image);
160     }
161
162     return image;
163 }
164
165 static uint32_t
166 hars_petruska_f54_1_random (void)
167 {
168 #define rol(x,k) ((x << k) | (x >> (32-k)))
169     static uint32_t x;
170     return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
171 #undef rol
172 }
173
174 static struct {
175     cairo_color_t color;
176     pixman_image_t *image;
177 } cache[16];
178 static int n_cached;
179
180 #else  /* !PIXMAN_HAS_ATOMIC_OPS */
181 static pixman_image_t *
182 _pixman_transparent_image (void)
183 {
184     TRACE ((stderr, "%s\n", __FUNCTION__));
185     return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
186 }
187
188 static pixman_image_t *
189 _pixman_black_image (void)
190 {
191     TRACE ((stderr, "%s\n", __FUNCTION__));
192     return _pixman_image_for_color (CAIRO_COLOR_BLACK);
193 }
194
195 static pixman_image_t *
196 _pixman_white_image (void)
197 {
198     TRACE ((stderr, "%s\n", __FUNCTION__));
199     return _pixman_image_for_color (CAIRO_COLOR_WHITE);
200 }
201 #endif /* !PIXMAN_HAS_ATOMIC_OPS */
202
203
204 pixman_image_t *
205 _pixman_image_for_color (const cairo_color_t *cairo_color)
206 {
207     pixman_color_t color;
208     pixman_image_t *image;
209
210 #if PIXMAN_HAS_ATOMIC_OPS
211     int i;
212
213     if (CAIRO_COLOR_IS_CLEAR (cairo_color))
214         return _pixman_transparent_image ();
215
216     if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) {
217         if (cairo_color->red_short <= 0x00ff &&
218             cairo_color->green_short <= 0x00ff &&
219             cairo_color->blue_short <= 0x00ff)
220         {
221             return _pixman_black_image ();
222         }
223
224         if (cairo_color->red_short >= 0xff00 &&
225             cairo_color->green_short >= 0xff00 &&
226             cairo_color->blue_short >= 0xff00)
227         {
228             return _pixman_white_image ();
229         }
230     }
231
232     CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
233     for (i = 0; i < n_cached; i++) {
234         if (_cairo_color_equal (&cache[i].color, cairo_color)) {
235             image = pixman_image_ref (cache[i].image);
236             goto UNLOCK;
237         }
238     }
239 #endif
240
241     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;
245
246     image = pixman_image_create_solid_fill (&color);
247 #if PIXMAN_HAS_ATOMIC_OPS
248     if (image == NULL)
249         goto UNLOCK;
250
251     if (n_cached < ARRAY_LENGTH (cache)) {
252         i = n_cached++;
253     } else {
254         i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
255         pixman_image_unref (cache[i].image);
256     }
257     cache[i].image = pixman_image_ref (image);
258     cache[i].color = *cairo_color;
259
260 UNLOCK:
261     CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
262 #endif
263     return image;
264 }
265
266
267 void
268 _cairo_image_reset_static_data (void)
269 {
270 #if PIXMAN_HAS_ATOMIC_OPS
271     while (n_cached)
272         pixman_image_unref (cache[--n_cached].image);
273
274     if (__pixman_transparent_image) {
275         pixman_image_unref (__pixman_transparent_image);
276         __pixman_transparent_image = NULL;
277     }
278
279     if (__pixman_black_image) {
280         pixman_image_unref (__pixman_black_image);
281         __pixman_black_image = NULL;
282     }
283
284     if (__pixman_white_image) {
285         pixman_image_unref (__pixman_white_image);
286         __pixman_white_image = NULL;
287     }
288 #endif
289 }
290
291 static pixman_image_t *
292 _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
293                             const cairo_rectangle_int_t *extents,
294                             int *ix, int *iy)
295 {
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;
303     unsigned int i;
304     cairo_int_status_t status;
305
306     TRACE ((stderr, "%s\n", __FUNCTION__));
307
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))
312             return NULL;
313     }
314
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;
321     }
322
323     _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
324
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);
329
330     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
331         pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
332                                                             pixman_stops,
333                                                             pattern->n_stops);
334     } else {
335         pixman_fixed_t r1, r2;
336
337         r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
338         r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
339
340         pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
341                                                             pixman_stops,
342                                                             pattern->n_stops);
343     }
344
345     if (pixman_stops != pixman_stops_static)
346         free (pixman_stops);
347
348     if (unlikely (pixman_image == NULL))
349         return NULL;
350
351     *ix = *iy = 0;
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))
359         {
360             pixman_image_unref (pixman_image);
361             return NULL;
362         }
363     }
364
365     {
366         pixman_repeat_t pixman_repeat;
367
368         switch (pattern->base.extend) {
369         default:
370         case CAIRO_EXTEND_NONE:
371             pixman_repeat = PIXMAN_REPEAT_NONE;
372             break;
373         case CAIRO_EXTEND_REPEAT:
374             pixman_repeat = PIXMAN_REPEAT_NORMAL;
375             break;
376         case CAIRO_EXTEND_REFLECT:
377             pixman_repeat = PIXMAN_REPEAT_REFLECT;
378             break;
379         case CAIRO_EXTEND_PAD:
380             pixman_repeat = PIXMAN_REPEAT_PAD;
381             break;
382         }
383
384         pixman_image_set_repeat (pixman_image, pixman_repeat);
385     }
386
387     return pixman_image;
388 }
389
390 static pixman_image_t *
391 _pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
392                         const cairo_rectangle_int_t *extents,
393                         int *tx, int *ty)
394 {
395     pixman_image_t *image;
396     int width, height;
397
398     TRACE ((stderr, "%s\n", __FUNCTION__));
399
400     *tx = -extents->x;
401     *ty = -extents->y;
402     width = extents->width;
403     height = extents->height;
404
405     image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
406     if (unlikely (image == NULL))
407         return NULL;
408
409     _cairo_mesh_pattern_rasterize (pattern,
410                                    pixman_image_get_data (image),
411                                    width, height,
412                                    pixman_image_get_stride (image),
413                                    *tx, *ty);
414     return image;
415 }
416
417 struct acquire_source_cleanup {
418     cairo_surface_t *surface;
419     cairo_image_surface_t *image;
420     void *image_extra;
421 };
422
423 static void
424 _acquire_source_cleanup (pixman_image_t *pixman_image,
425                          void *closure)
426 {
427     struct acquire_source_cleanup *data = closure;
428
429     _cairo_surface_release_source_image (data->surface,
430                                          data->image,
431                                          data->image_extra);
432     free (data);
433 }
434
435 static void
436 _defer_free_cleanup (pixman_image_t *pixman_image,
437                      void *closure)
438 {
439     cairo_surface_destroy (closure);
440 }
441
442 static uint16_t
443 expand_channel (uint16_t v, uint32_t bits)
444 {
445     int offset = 16 - bits;
446     while (offset > 0) {
447         v |= v >> bits;
448         offset -= bits;
449         bits += bits;
450     }
451     return v;
452 }
453
454 static pixman_image_t *
455 _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
456 {
457     uint32_t pixel;
458     pixman_color_t color;
459
460     TRACE ((stderr, "%s\n", __FUNCTION__));
461
462     switch (image->format) {
463     default:
464     case CAIRO_FORMAT_INVALID:
465         ASSERT_NOT_REACHED;
466         return NULL;
467
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 ();
471
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 ();
479
480         color.red = color.green = color.blue = 0;
481         return pixman_image_create_solid_fill (&color);
482
483     case CAIRO_FORMAT_RGB16_565:
484         pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
485         if (pixel == 0)
486             return _pixman_black_image ();
487         if (pixel == 0xffff)
488             return _pixman_white_image ();
489
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);
495
496     case CAIRO_FORMAT_RGB30:
497         pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
498         pixel &= 0x3fffffff; /* ignore alpha bits */
499         if (pixel == 0)
500             return _pixman_black_image ();
501         if (pixel == 0x3fffffff)
502             return _pixman_white_image ();
503
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);
510
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 ();
521
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);
526     }
527 }
528
529 static cairo_bool_t
530 _pixman_image_set_properties (pixman_image_t *pixman_image,
531                               const cairo_pattern_t *pattern,
532                               const cairo_rectangle_int_t *extents,
533                               int *ix,int *iy)
534 {
535     pixman_transform_t pixman_transform;
536     cairo_int_status_t status;
537
538     status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
539                                                     pattern->filter,
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)
544     {
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);
548     }
549     else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
550                        ! pixman_image_set_transform (pixman_image,
551                                                      &pixman_transform)))
552     {
553         return FALSE;
554     }
555     else
556     {
557         pixman_filter_t pixman_filter;
558
559         switch (pattern->filter) {
560         case CAIRO_FILTER_FAST:
561             pixman_filter = PIXMAN_FILTER_FAST;
562             break;
563         case CAIRO_FILTER_GOOD:
564             pixman_filter = PIXMAN_FILTER_GOOD;
565             break;
566         case CAIRO_FILTER_BEST:
567             pixman_filter = PIXMAN_FILTER_BEST;
568             break;
569         case CAIRO_FILTER_NEAREST:
570             pixman_filter = PIXMAN_FILTER_NEAREST;
571             break;
572         case CAIRO_FILTER_BILINEAR:
573             pixman_filter = PIXMAN_FILTER_BILINEAR;
574             break;
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. */
581         default:
582             pixman_filter = PIXMAN_FILTER_BEST;
583         }
584
585         pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
586     }
587
588     {
589         pixman_repeat_t pixman_repeat;
590
591         switch (pattern->extend) {
592         default:
593         case CAIRO_EXTEND_NONE:
594             pixman_repeat = PIXMAN_REPEAT_NONE;
595             break;
596         case CAIRO_EXTEND_REPEAT:
597             pixman_repeat = PIXMAN_REPEAT_NORMAL;
598             break;
599         case CAIRO_EXTEND_REFLECT:
600             pixman_repeat = PIXMAN_REPEAT_REFLECT;
601             break;
602         case CAIRO_EXTEND_PAD:
603             pixman_repeat = PIXMAN_REPEAT_PAD;
604             break;
605         }
606
607         pixman_image_set_repeat (pixman_image, pixman_repeat);
608     }
609
610     if (pattern->has_component_alpha)
611         pixman_image_set_component_alpha (pixman_image, TRUE);
612
613     return TRUE;
614 }
615
616 struct proxy {
617     cairo_surface_t base;
618     cairo_surface_t *image;
619 };
620
621 static cairo_status_t
622 proxy_acquire_source_image (void                         *abstract_surface,
623                             cairo_image_surface_t       **image_out,
624                             void                        **image_extra)
625 {
626     struct proxy *proxy = abstract_surface;
627     return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
628 }
629
630 static void
631 proxy_release_source_image (void                        *abstract_surface,
632                             cairo_image_surface_t       *image,
633                             void                        *image_extra)
634 {
635     struct proxy *proxy = abstract_surface;
636     _cairo_surface_release_source_image (proxy->image, image, image_extra);
637 }
638
639 static cairo_status_t
640 proxy_finish (void *abstract_surface)
641 {
642     return CAIRO_STATUS_SUCCESS;
643 }
644
645 static const cairo_surface_backend_t proxy_backend  = {
646     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
647     proxy_finish,
648     NULL,
649
650     NULL, /* create similar */
651     NULL, /* create similar image */
652     NULL, /* map to image */
653     NULL, /* unmap image */
654
655     _cairo_surface_default_source,
656     proxy_acquire_source_image,
657     proxy_release_source_image,
658 };
659
660 static cairo_surface_t *
661 attach_proxy (cairo_surface_t *source,
662               cairo_surface_t *image)
663 {
664     struct proxy *proxy;
665
666     proxy = malloc (sizeof (*proxy));
667     if (unlikely (proxy == NULL))
668         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
669
670     _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content);
671
672     proxy->image = image;
673     _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
674
675     return &proxy->base;
676 }
677
678 static void
679 detach_proxy (cairo_surface_t *source,
680               cairo_surface_t *proxy)
681 {
682     cairo_surface_finish (proxy);
683     cairo_surface_destroy (proxy);
684 }
685
686 static cairo_surface_t *
687 get_proxy (cairo_surface_t *proxy)
688 {
689     return ((struct proxy *)proxy)->image;
690 }
691
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,
698                              int *ix, int *iy)
699 {
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;
706     int tx = 0, ty = 0;
707
708     TRACE ((stderr, "%s\n", __FUNCTION__));
709
710     *ix = *iy = 0;
711
712     source = _cairo_pattern_get_source (pattern, &limit);
713
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 ();
720
721         if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
722             double x1, y1, x2, y2;
723
724             matrix = pattern->base.matrix;
725             status = cairo_matrix_invert (&matrix);
726             assert (status == CAIRO_STATUS_SUCCESS);
727
728             x1 = limit.x;
729             y1 = limit.y;
730             x2 = limit.x + limit.width;
731             y2 = limit.y + limit.height;
732
733             _cairo_matrix_transform_bounding_box (&matrix,
734                                                   &x1, &y1, &x2, &y2, NULL);
735
736             limit.x = floor (x1);
737             limit.y = floor (y1);
738             limit.width  = ceil (x2) - limit.x;
739             limit.height = ceil (y2) - limit.y;
740         }
741     }
742     tx = limit.x;
743     ty = limit.y;
744
745     /* XXX transformations! */
746     proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
747     if (proxy != NULL) {
748         clone = cairo_surface_reference (get_proxy (proxy));
749         goto done;
750     }
751
752     if (is_mask) {
753             clone = cairo_image_surface_create (CAIRO_FORMAT_A8,
754                                                 limit.width, limit.height);
755     } else {
756         if (dst->base.content == source->content)
757             clone = cairo_image_surface_create (dst->format,
758                                                 limit.width, limit.height);
759         else
760             clone = _cairo_image_surface_create_with_content (source->content,
761                                                               limit.width,
762                                                               limit.height);
763     }
764
765     m = NULL;
766     if (extend == CAIRO_EXTEND_NONE) {
767         matrix = pattern->base.matrix;
768         if (tx | ty)
769             cairo_matrix_translate (&matrix, tx, ty);
770         m = &matrix;
771     } else {
772         /* XXX extract scale factor for repeating patterns */
773     }
774
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);
781         return NULL;
782     }
783
784 done:
785     pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image);
786     cairo_surface_destroy (clone);
787
788     *ix = -limit.x;
789     *iy = -limit.y;
790     if (extend != CAIRO_EXTEND_NONE) {
791         if (! _pixman_image_set_properties (pixman_image,
792                                             &pattern->base, extents,
793                                             ix, iy)) {
794             pixman_image_unref (pixman_image);
795             pixman_image= NULL;
796         }
797     }
798
799     return pixman_image;
800 }
801
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,
808                            int *ix, int *iy)
809 {
810     cairo_extend_t extend = pattern->base.extend;
811     pixman_image_t *pixman_image;
812
813     TRACE ((stderr, "%s\n", __FUNCTION__));
814
815     *ix = *iy = 0;
816     pixman_image = NULL;
817     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
818         return _pixman_image_for_recording(dst, pattern,
819                                            is_mask, extents, sample,
820                                            ix, iy);
821
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))
825     {
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;
829
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;
833         }
834
835         type = source->base.backend->type;
836         if (type == CAIRO_SURFACE_TYPE_IMAGE) {
837             if (extend != CAIRO_EXTEND_NONE &&
838                 sample->x >= 0 &&
839                 sample->y >= 0 &&
840                 sample->x + sample->width  <= source->width &&
841                 sample->y + sample->height <= source->height)
842             {
843                 extend = CAIRO_EXTEND_NONE;
844             }
845
846             if (sample->width == 1 && sample->height == 1) {
847                 if (sample->x < 0 ||
848                     sample->y < 0 ||
849                     sample->x >= source->width ||
850                     sample->y >= source->height)
851                 {
852                     if (extend == CAIRO_EXTEND_NONE) {
853                         cairo_surface_destroy (defer_free);
854                         return _pixman_transparent_image ();
855                     }
856                 }
857                 else
858                 {
859                     pixman_image = _pixel_to_solid (source,
860                                                     sample->x, sample->y);
861                     if (pixman_image) {
862                         cairo_surface_destroy (defer_free);
863                         return pixman_image;
864                     }
865                 }
866             }
867
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,
873                                                      ix, iy))
874             {
875                 cairo_surface_destroy (defer_free);
876                 return pixman_image_ref (source->pixman_image);
877             }
878 #endif
879
880             pixman_image = pixman_image_create_bits (source->pixman_format,
881                                                      source->width,
882                                                      source->height,
883                                                      (uint32_t *) source->data,
884                                                      source->stride);
885             if (unlikely (pixman_image == NULL)) {
886                 cairo_surface_destroy (defer_free);
887                 return NULL;
888             }
889
890             if (defer_free) {
891                 pixman_image_set_destroy_function (pixman_image,
892                                                    _defer_free_cleanup,
893                                                    defer_free);
894             }
895         } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
896             cairo_surface_subsurface_t *sub;
897             cairo_bool_t is_contained = FALSE;
898
899             sub = (cairo_surface_subsurface_t *) source;
900             source = (cairo_image_surface_t *) sub->target;
901
902             if (sample->x >= 0 &&
903                 sample->y >= 0 &&
904                 sample->x + sample->width  <= sub->extents.width &&
905                 sample->y + sample->height <= sub->extents.height)
906             {
907                 is_contained = TRUE;
908             }
909
910             if (sample->width == 1 && sample->height == 1) {
911                 if (is_contained) {
912                     pixman_image = _pixel_to_solid (source,
913                                                     sub->extents.x + sample->x,
914                                                     sub->extents.y + sample->y);
915                     if (pixman_image)
916                         return pixman_image;
917                 } else {
918                     if (extend == CAIRO_EXTEND_NONE)
919                         return _pixman_transparent_image ();
920                 }
921             }
922
923 #if PIXMAN_HAS_ATOMIC_OPS
924             *ix = sub->extents.x;
925             *iy = sub->extents.y;
926             if (is_contained &&
927                 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
928                                                      pattern->base.filter,
929                                                      ix, iy))
930             {
931                 return pixman_image_ref (source->pixman_image);
932             }
933 #endif
934
935             /* Avoid sub-byte offsets, force a copy in that case. */
936             if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
937                 if (is_contained) {
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,
942                                                              sub->extents.width,
943                                                              sub->extents.height,
944                                                              data,
945                                                              source->stride);
946                     if (unlikely (pixman_image == NULL))
947                         return NULL;
948                 } else {
949                     /* XXX for a simple translation and EXTEND_NONE we can
950                      * fix up the pattern matrix instead.
951                      */
952                 }
953             }
954         }
955     }
956
957     if (pixman_image == NULL) {
958         struct acquire_source_cleanup *cleanup;
959         cairo_image_surface_t *image;
960         void *extra;
961         cairo_status_t status;
962
963         status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
964         if (unlikely (status))
965             return NULL;
966
967         pixman_image = pixman_image_create_bits (image->pixman_format,
968                                                  image->width,
969                                                  image->height,
970                                                  (uint32_t *) image->data,
971                                                  image->stride);
972         if (unlikely (pixman_image == NULL)) {
973             _cairo_surface_release_source_image (pattern->surface, image, extra);
974             return NULL;
975         }
976
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);
981             return NULL;
982         }
983
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);
989     }
990
991     if (! _pixman_image_set_properties (pixman_image,
992                                         &pattern->base, extents,
993                                         ix, iy)) {
994         pixman_image_unref (pixman_image);
995         pixman_image= NULL;
996     }
997
998     return pixman_image;
999 }
1000
1001 struct raster_source_cleanup {
1002     const cairo_pattern_t *pattern;
1003     cairo_surface_t *surface;
1004     cairo_image_surface_t *image;
1005     void *image_extra;
1006 };
1007
1008 static void
1009 _raster_source_cleanup (pixman_image_t *pixman_image,
1010                         void *closure)
1011 {
1012     struct raster_source_cleanup *data = closure;
1013
1014     _cairo_surface_release_source_image (data->surface,
1015                                          data->image,
1016                                          data->image_extra);
1017
1018     _cairo_raster_source_pattern_release (data->pattern,
1019                                           data->surface);
1020
1021     free (data);
1022 }
1023
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,
1030                           int *ix, int *iy)
1031 {
1032     pixman_image_t *pixman_image;
1033     struct raster_source_cleanup *cleanup;
1034     cairo_image_surface_t *image;
1035     void *extra;
1036     cairo_status_t status;
1037     cairo_surface_t *surface;
1038
1039     TRACE ((stderr, "%s\n", __FUNCTION__));
1040
1041     *ix = *iy = 0;
1042
1043     surface = _cairo_raster_source_pattern_acquire (&pattern->base,
1044                                                     &dst->base, NULL);
1045     if (unlikely (surface == NULL || surface->status))
1046         return NULL;
1047
1048     status = _cairo_surface_acquire_source_image (surface, &image, &extra);
1049     if (unlikely (status)) {
1050         _cairo_raster_source_pattern_release (&pattern->base, surface);
1051         return NULL;
1052     }
1053
1054     assert (image->width == pattern->extents.width);
1055     assert (image->height == pattern->extents.height);
1056
1057     pixman_image = pixman_image_create_bits (image->pixman_format,
1058                                              image->width,
1059                                              image->height,
1060                                              (uint32_t *) image->data,
1061                                              image->stride);
1062     if (unlikely (pixman_image == NULL)) {
1063         _cairo_surface_release_source_image (surface, image, extra);
1064         _cairo_raster_source_pattern_release (&pattern->base, surface);
1065         return NULL;
1066     }
1067
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);
1073         return NULL;
1074     }
1075
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);
1082
1083     if (! _pixman_image_set_properties (pixman_image,
1084                                         &pattern->base, extents,
1085                                         ix, iy)) {
1086         pixman_image_unref (pixman_image);
1087         pixman_image= NULL;
1088     }
1089
1090     return pixman_image;
1091 }
1092
1093 pixman_image_t *
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,
1099                            int *tx, int *ty)
1100 {
1101     *tx = *ty = 0;
1102
1103     TRACE ((stderr, "%s\n", __FUNCTION__));
1104
1105     if (pattern == NULL)
1106         return _pixman_white_image ();
1107
1108     switch (pattern->type) {
1109     default:
1110         ASSERT_NOT_REACHED;
1111     case CAIRO_PATTERN_TYPE_SOLID:
1112         return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
1113
1114     case CAIRO_PATTERN_TYPE_RADIAL:
1115     case CAIRO_PATTERN_TYPE_LINEAR:
1116         return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
1117                                            extents, tx, ty);
1118
1119     case CAIRO_PATTERN_TYPE_MESH:
1120         return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
1121                                            extents, tx, ty);
1122
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,
1127                                           tx, ty);
1128
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,
1133                                          tx, ty);
1134     }
1135 }
1136
1137 static cairo_status_t
1138 _cairo_image_source_finish (void *abstract_surface)
1139 {
1140     cairo_image_source_t *source = abstract_surface;
1141
1142     pixman_image_unref (source->pixman_image);
1143     return CAIRO_STATUS_SUCCESS;
1144 }
1145
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 */
1150 };
1151
1152 cairo_surface_t *
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)
1159 {
1160     cairo_image_source_t *source;
1161
1162     TRACE ((stderr, "%s\n", __FUNCTION__));
1163
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));
1167
1168     source->pixman_image =
1169         _pixman_image_for_pattern ((cairo_image_surface_t *)dst,
1170                                    pattern, is_mask,
1171                                    extents, sample,
1172                                    src_x, src_y);
1173     if (unlikely (source->pixman_image == NULL)) {
1174         free (source);
1175         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
1176     }
1177
1178     _cairo_surface_init (&source->base,
1179                          &_cairo_image_source_backend,
1180                          NULL, /* device */
1181                          CAIRO_CONTENT_COLOR_ALPHA);
1182
1183     source->is_opaque_solid =
1184         pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
1185
1186     return &source->base;
1187 }