Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3959 Serge 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 
37
 *	Chris Wilson 
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
}