Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc.
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
 *	Behdad Esfahbod 
38
 *	Chris Wilson 
39
 *	Karl Tomlinson , Mozilla Corporation
40
 */
41
#include "cairoint.h"
42
 
43
#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
44
 
45
#include "cairo-xlib-private.h"
46
#include "cairo-xlib-surface-private.h"
47
 
48
#include "cairo-error-private.h"
49
#include "cairo-image-surface-inline.h"
50
#include "cairo-paginated-private.h"
51
#include "cairo-pattern-inline.h"
52
#include "cairo-recording-surface-private.h"
53
#include "cairo-surface-backend-private.h"
54
#include "cairo-surface-offset-private.h"
55
#include "cairo-surface-observer-private.h"
56
#include "cairo-surface-snapshot-inline.h"
57
#include "cairo-surface-subsurface-inline.h"
58
 
59
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
60
 
61
static cairo_xlib_surface_t *
62
unwrap_source (const cairo_surface_pattern_t *pattern)
63
{
64
    cairo_rectangle_int_t limits;
65
    return (cairo_xlib_surface_t *)_cairo_pattern_get_source (pattern, &limits);
66
}
67
 
68
static cairo_status_t
69
_cairo_xlib_source_finish (void *abstract_surface)
70
{
71
    cairo_xlib_source_t *source = abstract_surface;
72
 
73
    XRenderFreePicture (source->dpy, source->picture);
74
    if (source->pixmap)
75
	    XFreePixmap (source->dpy, source->pixmap);
76
    return CAIRO_STATUS_SUCCESS;
77
}
78
 
79
static const cairo_surface_backend_t cairo_xlib_source_backend = {
80
    CAIRO_SURFACE_TYPE_XLIB,
81
    _cairo_xlib_source_finish,
82
    NULL, /* read-only wrapper */
83
};
84
 
85
static cairo_status_t
86
_cairo_xlib_proxy_finish (void *abstract_surface)
87
{
88
    cairo_xlib_proxy_t *proxy = abstract_surface;
89
 
90
    _cairo_xlib_shm_surface_mark_active (proxy->owner);
91
    XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
92
    if (proxy->source.pixmap)
93
	    XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
94
    cairo_surface_destroy (proxy->owner);
95
    return CAIRO_STATUS_SUCCESS;
96
}
97
 
98
static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
99
    CAIRO_SURFACE_TYPE_XLIB,
100
    _cairo_xlib_proxy_finish,
101
    NULL, /* read-only wrapper */
102
};
103
 
104
static cairo_surface_t *
105
source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
106
{
107
    cairo_xlib_source_t *source;
108
 
109
    if (picture == None)
110
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
111
 
112
    source = malloc (sizeof (*source));
113
    if (unlikely (source == NULL)) {
114
	XRenderFreePicture (dst->display->display, picture);
115
	if (pixmap)
116
		XFreePixmap (dst->display->display, pixmap);
117
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
118
    }
119
 
120
    _cairo_surface_init (&source->base,
121
			 &cairo_xlib_source_backend,
122
			 NULL, /* device */
123
			 CAIRO_CONTENT_COLOR_ALPHA);
124
 
125
    /* The source exists only within an operation */
126
    source->picture = picture;
127
    source->pixmap = pixmap;
128
    source->dpy = dst->display->display;
129
 
130
    return &source->base;
131
}
132
 
133
static uint32_t
134
hars_petruska_f54_1_random (void)
135
{
136
#define rol(x,k) ((x << k) | (x >> (32-k)))
137
    static uint32_t x;
138
    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
139
#undef rol
140
}
141
 
142
static const XTransform identity = {
143
    {
144
	{ 1 << 16, 0x00000, 0x00000 },
145
	{ 0x00000, 1 << 16, 0x00000 },
146
	{ 0x00000, 0x00000, 1 << 16 },
147
    }
148
};
149
 
150
static cairo_bool_t
151
picture_set_matrix (cairo_xlib_display_t *display,
152
		    Picture picture,
153
		    const cairo_matrix_t *matrix,
154
		    cairo_filter_t        filter,
155
		    double                xc,
156
		    double                yc,
157
		    int                  *x_offset,
158
		    int                  *y_offset)
159
{
160
    XTransform xtransform;
161
    pixman_transform_t *pixman_transform;
162
    cairo_int_status_t status;
163
 
164
    /* Casting between pixman_transform_t and XTransform is safe because
165
     * they happen to be the exact same type.
166
     */
167
    pixman_transform = (pixman_transform_t *) &xtransform;
168
    status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
169
						    pixman_transform,
170
						    x_offset, y_offset);
171
    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
172
	return TRUE;
173
    if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
174
	return FALSE;
175
 
176
    if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
177
	return TRUE;
178
 
179
    /* a late check in case we perturb the matrix too far */
180
    if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display))
181
	return FALSE;
182
 
183
    XRenderSetPictureTransform (display->display, picture, &xtransform);
184
    return TRUE;
185
}
186
 
187
static cairo_status_t
188
picture_set_filter (Display *dpy,
189
		    Picture picture,
190
		    cairo_filter_t filter)
191
{
192
    const char *render_filter;
193
 
194
    switch (filter) {
195
    case CAIRO_FILTER_FAST:
196
	render_filter = FilterFast;
197
	break;
198
    case CAIRO_FILTER_GOOD:
199
	render_filter = FilterGood;
200
	break;
201
    case CAIRO_FILTER_BEST:
202
	render_filter = FilterBest;
203
	break;
204
    case CAIRO_FILTER_NEAREST:
205
	render_filter = FilterNearest;
206
	break;
207
    case CAIRO_FILTER_BILINEAR:
208
	render_filter = FilterBilinear;
209
	break;
210
    case CAIRO_FILTER_GAUSSIAN:
211
	/* XXX: The GAUSSIAN value has no implementation in cairo
212
	 * whatsoever, so it was really a mistake to have it in the
213
	 * API. We could fix this by officially deprecating it, or
214
	 * else inventing semantics and providing an actual
215
	 * implementation for it. */
216
    default:
217
	render_filter = FilterBest;
218
	break;
219
    }
220
 
221
    XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0);
222
    return CAIRO_STATUS_SUCCESS;
223
}
224
 
225
static int
226
extend_to_repeat (cairo_extend_t extend)
227
{
228
    switch (extend) {
229
    default:
230
	ASSERT_NOT_REACHED;
231
    case CAIRO_EXTEND_NONE:
232
	return RepeatNone;
233
    case CAIRO_EXTEND_REPEAT:
234
	return RepeatNormal;
235
    case CAIRO_EXTEND_REFLECT:
236
	return RepeatReflect;
237
    case CAIRO_EXTEND_PAD:
238
	return RepeatPad;
239
    }
240
}
241
 
242
static cairo_bool_t
243
picture_set_properties (cairo_xlib_display_t *display,
244
			Picture picture,
245
			const cairo_pattern_t *pattern,
246
			const cairo_matrix_t *matrix,
247
			const cairo_rectangle_int_t *extents,
248
			int *x_off, int *y_off)
249
{
250
    XRenderPictureAttributes pa;
251
    int mask = 0;
252
 
253
    if (! picture_set_matrix (display, picture, matrix, pattern->filter,
254
			      extents->x + extents->width / 2,
255
			      extents->y + extents->height / 2,
256
			      x_off, y_off))
257
	return FALSE;
258
 
259
    picture_set_filter (display->display, picture, pattern->filter);
260
 
261
    if (pattern->has_component_alpha) {
262
	pa.component_alpha = 1;
263
	mask |= CPComponentAlpha;
264
    }
265
 
266
    if (pattern->extend != CAIRO_EXTEND_NONE) {
267
	pa.repeat = extend_to_repeat (pattern->extend);
268
	mask |= CPRepeat;
269
    }
270
 
271
    if (mask)
272
	XRenderChangePicture (display->display, picture, mask, &pa);
273
 
274
    return TRUE;
275
}
276
 
277
static cairo_surface_t *
278
render_pattern (cairo_xlib_surface_t *dst,
279
		const cairo_pattern_t *pattern,
280
		cairo_bool_t is_mask,
281
		const cairo_rectangle_int_t *extents,
282
		int *src_x, int *src_y)
283
{
284
    Display *dpy = dst->display->display;
285
    cairo_xlib_surface_t *src;
286
    cairo_image_surface_t *image;
287
    cairo_status_t status;
288
    cairo_rectangle_int_t map_extents;
289
 
290
    src = (cairo_xlib_surface_t *)
291
	_cairo_surface_create_similar_scratch (&dst->base,
292
					       is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
293
					       extents->width,
294
					       extents->height);
295
    if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
296
	cairo_surface_destroy (&src->base);
297
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
298
    }
299
 
300
    map_extents = *extents;
301
    map_extents.x = map_extents.y = 0;
302
 
303
    image = _cairo_surface_map_to_image (&src->base, &map_extents);
304
    status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
305
					  CAIRO_OPERATOR_SOURCE, pattern,
306
					  NULL);
307
    status = _cairo_surface_unmap_image (&src->base, image);
308
    if (unlikely (status)) {
309
	cairo_surface_destroy (&src->base);
310
	return _cairo_surface_create_in_error (status);
311
    }
312
 
313
    status = _cairo_xlib_surface_put_shm (src);
314
    if (unlikely (status)) {
315
	cairo_surface_destroy (&src->base);
316
	return _cairo_surface_create_in_error (status);
317
    }
318
 
319
    src->picture = XRenderCreatePicture (dpy,
320
					 src->drawable, src->xrender_format,
321
					 0, NULL);
322
 
323
    *src_x = -extents->x;
324
    *src_y = -extents->y;
325
    return &src->base;
326
}
327
 
328
static cairo_surface_t *
329
gradient_source (cairo_xlib_surface_t *dst,
330
		 const cairo_gradient_pattern_t *gradient,
331
		 cairo_bool_t is_mask,
332
		 const cairo_rectangle_int_t *extents,
333
		 int *src_x, int *src_y)
334
{
335
    cairo_xlib_display_t *display = dst->display;
336
    cairo_matrix_t matrix = gradient->base.matrix;
337
    char buf[CAIRO_STACK_BUFFER_SIZE];
338
    cairo_circle_double_t extremes[2];
339
    XFixed *stops;
340
    XRenderColor *colors;
341
    Picture picture;
342
    unsigned int i, n_stops;
343
 
344
    /* The RENDER specification says that the inner circle has
345
     * to be completely contained inside the outer one. */
346
    if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL &&
347
	! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
348
	return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
349
 
350
    assert (gradient->n_stops > 0);
351
    n_stops = MAX (gradient->n_stops, 2);
352
 
353
    if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
354
    {
355
	stops = (XFixed *) buf;
356
    }
357
    else
358
    {
359
	stops =
360
	    _cairo_malloc_ab (n_stops,
361
			      sizeof (XFixed) + sizeof (XRenderColor));
362
	if (unlikely (stops == NULL))
363
	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
364
    }
365
 
366
    colors = (XRenderColor *) (stops + n_stops);
367
    for (i = 0; i < gradient->n_stops; i++) {
368
	stops[i] =
369
	    _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
370
 
371
	colors[i].red   = gradient->stops[i].color.red_short;
372
	colors[i].green = gradient->stops[i].color.green_short;
373
	colors[i].blue  = gradient->stops[i].color.blue_short;
374
	colors[i].alpha = gradient->stops[i].color.alpha_short;
375
    }
376
 
377
    /* RENDER does not support gradients with less than 2
378
     * stops. If a gradient has only a single stop, duplicate
379
     * it to make RENDER happy. */
380
    if (gradient->n_stops == 1) {
381
	stops[1] =
382
	    _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
383
 
384
	colors[1].red   = gradient->stops[0].color.red_short;
385
	colors[1].green = gradient->stops[0].color.green_short;
386
	colors[1].blue  = gradient->stops[0].color.blue_short;
387
	colors[1].alpha = gradient->stops[0].color.alpha_short;
388
    }
389
 
390
#if 0
391
    /* For some weird reason the X server is sometimes getting
392
     * CreateGradient requests with bad length. So far I've only seen
393
     * XRenderCreateLinearGradient request with 4 stops sometime end up
394
     * with length field matching 0 stops at the server side. I've
395
     * looked at the libXrender code and I can't see anything that
396
     * could cause this behavior. However, for some reason having a
397
     * XSync call here seems to avoid the issue so I'll keep it here
398
     * until it's solved.
399
     */
400
    XSync (display->display, False);
401
#endif
402
 
403
    _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
404
 
405
    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
406
	XLinearGradient grad;
407
 
408
	grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
409
	grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
410
	grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
411
	grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
412
 
413
	picture = XRenderCreateLinearGradient (display->display, &grad,
414
					       stops, colors,
415
					       n_stops);
416
    } else {
417
	XRadialGradient grad;
418
 
419
	grad.inner.x      = _cairo_fixed_16_16_from_double (extremes[0].center.x);
420
	grad.inner.y      = _cairo_fixed_16_16_from_double (extremes[0].center.y);
421
	grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
422
	grad.outer.x      = _cairo_fixed_16_16_from_double (extremes[1].center.x);
423
	grad.outer.y      = _cairo_fixed_16_16_from_double (extremes[1].center.y);
424
	grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
425
 
426
	picture = XRenderCreateRadialGradient (display->display, &grad,
427
					       stops, colors,
428
					       n_stops);
429
    }
430
 
431
    if (stops != (XFixed *) buf)
432
	free (stops);
433
 
434
    *src_x = *src_y = 0;
435
    if (! picture_set_properties (display, picture,
436
				  &gradient->base, &gradient->base.matrix,
437
				  extents,
438
				  src_x, src_y)) {
439
	XRenderFreePicture (display->display, picture);
440
	return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
441
    }
442
 
443
    return source (dst, picture, None);
444
}
445
 
446
static cairo_surface_t *
447
color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
448
{
449
    Display *dpy = dst->display->display;
450
    XRenderColor xcolor;
451
    Picture picture;
452
    Pixmap pixmap = None;
453
 
454
    xcolor.red   = color->red_short;
455
    xcolor.green = color->green_short;
456
    xcolor.blue  = color->blue_short;
457
    xcolor.alpha = color->alpha_short;
458
 
459
    if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
460
	picture = XRenderCreateSolidFill (dpy, &xcolor);
461
    } else {
462
	XRenderPictureAttributes pa;
463
	int mask = 0;
464
 
465
	pa.repeat = RepeatNormal;
466
	mask |= CPRepeat;
467
 
468
	pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
469
	picture = XRenderCreatePicture (dpy, pixmap,
470
					_cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
471
					mask, &pa);
472
 
473
	if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
474
	    XRectangle r = { 0, 0, 1, 1};
475
	    XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
476
	} else {
477
	    XGCValues gcv;
478
	    GC gc;
479
 
480
	    gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
481
					    32, pixmap);
482
	    if (unlikely (gc == NULL)) {
483
		XFreePixmap (dpy, pixmap);
484
		return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
485
	    }
486
 
487
	    gcv.foreground = 0;
488
	    gcv.foreground |= color->alpha_short >> 8 << 24;
489
	    gcv.foreground |= color->red_short   >> 8 << 16;
490
	    gcv.foreground |= color->green_short >> 8 << 8;
491
	    gcv.foreground |= color->blue_short  >> 8 << 0;
492
	    gcv.fill_style = FillSolid;
493
 
494
	    XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
495
	    XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
496
 
497
	    _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
498
	}
499
    }
500
 
501
    return source (dst, picture, pixmap);
502
}
503
 
504
static cairo_surface_t *
505
alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha)
506
{
507
    cairo_xlib_display_t *display = dst->display;
508
 
509
    if (display->alpha[alpha] == NULL) {
510
	cairo_color_t color;
511
 
512
	color.red_short = color.green_short = color.blue_short = 0;
513
	color.alpha_short = alpha << 8 | alpha;
514
 
515
	display->alpha[alpha] = color_source (dst, &color);
516
    }
517
 
518
    return cairo_surface_reference (display->alpha[alpha]);
519
}
520
 
521
static cairo_surface_t *
522
white_source (cairo_xlib_surface_t *dst)
523
{
524
    cairo_xlib_display_t *display = dst->display;
525
 
526
    if (display->white == NULL)
527
	display->white = color_source (dst, CAIRO_COLOR_WHITE);
528
 
529
    return cairo_surface_reference (display->white);
530
}
531
 
532
static cairo_surface_t *
533
opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
534
{
535
    cairo_xlib_display_t *display = dst->display;
536
    uint32_t pixel =
537
	0xff000000 |
538
	color->red_short   >> 8 << 16 |
539
	color->green_short >> 8 << 8 |
540
	color->blue_short  >> 8 << 0;
541
    int i;
542
 
543
    if (display->last_solid_cache[0].color == pixel)
544
	return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]);
545
 
546
    for (i = 0; i < 16; i++) {
547
	if (display->solid_cache[i] == pixel)
548
	    goto done;
549
    }
550
 
551
    i = hars_petruska_f54_1_random () % 16;
552
    cairo_surface_destroy (display->solid[i]);
553
 
554
    display->solid[i] = color_source (dst, color);
555
    display->solid_cache[i] = pixel;
556
 
557
done:
558
    display->last_solid_cache[0].color = pixel;
559
    display->last_solid_cache[0].index = i;
560
    return cairo_surface_reference (display->solid[i]);
561
}
562
 
563
static cairo_surface_t *
564
transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
565
{
566
    cairo_xlib_display_t *display = dst->display;
567
    uint32_t pixel =
568
	color->alpha_short >> 8 << 24 |
569
	color->red_short   >> 8 << 16 |
570
	color->green_short >> 8 << 8 |
571
	color->blue_short  >> 8 << 0;
572
    int i;
573
 
574
    if (display->last_solid_cache[1].color == pixel) {
575
    assert (display->solid[display->last_solid_cache[1].index]);
576
	return cairo_surface_reference (display->solid[display->last_solid_cache[1].index]);
577
    }
578
 
579
    for (i = 16; i < 32; i++) {
580
	if (display->solid_cache[i] == pixel)
581
	    goto done;
582
    }
583
 
584
    i = 16 + (hars_petruska_f54_1_random () % 16);
585
    cairo_surface_destroy (display->solid[i]);
586
 
587
    display->solid[i] = color_source (dst, color);
588
    display->solid_cache[i] = pixel;
589
 
590
done:
591
    display->last_solid_cache[1].color = pixel;
592
    display->last_solid_cache[1].index = i;
593
    assert (display->solid[i]);
594
    return cairo_surface_reference (display->solid[i]);
595
}
596
 
597
static cairo_surface_t *
598
solid_source (cairo_xlib_surface_t *dst,
599
	      const cairo_color_t *color)
600
{
601
    if ((color->red_short | color->green_short | color->blue_short) <= 0xff)
602
	return alpha_source (dst, color->alpha_short >> 8);
603
 
604
    if (CAIRO_ALPHA_SHORT_IS_OPAQUE (color->alpha_short)) {
605
	if (color->red_short >= 0xff00 && color->green_short >= 0xff00 && color->blue_short >= 0xff00)
606
	    return white_source (dst);
607
 
608
	return opaque_source (dst, color);
609
    } else
610
	return transparent_source (dst, color);
611
}
612
 
613
static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst,
614
					 cairo_xlib_surface_t *src)
615
{
616
    Display *dpy = dst->display->display;
617
    cairo_xlib_source_t *source = &src->embedded_source;
618
 
619
    /* As these are frequent and meant to be fast, we track pictures for
620
     * native surface and minimise update requests.
621
     */
622
    if (source->picture == None) {
623
	XRenderPictureAttributes pa;
624
 
625
	_cairo_surface_init (&source->base,
626
			     &cairo_xlib_source_backend,
627
			     NULL, /* device */
628
			     CAIRO_CONTENT_COLOR_ALPHA);
629
 
630
	pa.subwindow_mode = IncludeInferiors;
631
	source->picture = XRenderCreatePicture (dpy,
632
						src->drawable,
633
						src->xrender_format,
634
						CPSubwindowMode, &pa);
635
 
636
	source->has_component_alpha = 0;
637
	source->has_matrix = 0;
638
	source->filter = CAIRO_FILTER_NEAREST;
639
	source->extend = CAIRO_EXTEND_NONE;
640
    }
641
 
642
    return (cairo_xlib_source_t *) cairo_surface_reference (&source->base);
643
}
644
 
645
static cairo_surface_t *
646
embedded_source (cairo_xlib_surface_t *dst,
647
		 const cairo_surface_pattern_t *pattern,
648
		 const cairo_rectangle_int_t *extents,
649
		 int *src_x, int *src_y,
650
		 cairo_xlib_source_t *source)
651
{
652
    Display *dpy = dst->display->display;
653
    cairo_int_status_t status;
654
    XTransform xtransform;
655
    XRenderPictureAttributes pa;
656
    unsigned mask = 0;
657
 
658
    status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
659
						    pattern->base.filter,
660
						    extents->x + extents->width / 2,
661
						    extents->y + extents->height / 2,
662
						    (pixman_transform_t *)&xtransform,
663
						    src_x, src_y);
664
 
665
    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
666
	if (source->has_matrix) {
667
	    source->has_matrix = 0;
668
	    memcpy (&xtransform, &identity, sizeof (identity));
669
	    status = CAIRO_INT_STATUS_SUCCESS;
670
	}
671
    } else
672
	source->has_matrix = 1;
673
    if (status == CAIRO_INT_STATUS_SUCCESS)
674
	XRenderSetPictureTransform (dpy, source->picture, &xtransform);
675
 
676
    if (source->filter != pattern->base.filter) {
677
	picture_set_filter (dpy, source->picture, pattern->base.filter);
678
	source->filter = pattern->base.filter;
679
    }
680
 
681
    if (source->has_component_alpha != pattern->base.has_component_alpha) {
682
	pa.component_alpha = pattern->base.has_component_alpha;
683
	mask |= CPComponentAlpha;
684
	source->has_component_alpha = pattern->base.has_component_alpha;
685
    }
686
 
687
    if (source->extend != pattern->base.extend) {
688
	pa.repeat = extend_to_repeat (pattern->base.extend);
689
	mask |= CPRepeat;
690
	source->extend = pattern->base.extend;
691
    }
692
 
693
    if (mask)
694
	XRenderChangePicture (dpy, source->picture, mask, &pa);
695
 
696
    return &source->base;
697
}
698
 
699
static cairo_surface_t *
700
subsurface_source (cairo_xlib_surface_t *dst,
701
		   const cairo_surface_pattern_t *pattern,
702
		   cairo_bool_t is_mask,
703
		   const cairo_rectangle_int_t *extents,
704
		   const cairo_rectangle_int_t *sample,
705
		   int *src_x, int *src_y)
706
{
707
    cairo_surface_subsurface_t *sub;
708
    cairo_xlib_surface_t *src;
709
    cairo_xlib_source_t *source;
710
    Display *dpy = dst->display->display;
711
    cairo_int_status_t status;
712
    cairo_surface_pattern_t local_pattern;
713
    XTransform xtransform;
714
    XRenderPictureAttributes pa;
715
    unsigned mask = 0;
716
 
717
    sub = (cairo_surface_subsurface_t *) pattern->surface;
718
 
719
    if (sample->x >= 0 && sample->y >= 0 &&
720
	sample->x + sample->width  <= sub->extents.width &&
721
	sample->y + sample->height <= sub->extents.height)
722
    {
723
	src = (cairo_xlib_surface_t *) sub->target;
724
	status = _cairo_surface_flush (&src->base, 0);
725
	if (unlikely (status))
726
	    return _cairo_surface_create_in_error (status);
727
 
728
	if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
729
	    _cairo_matrix_is_translation (&pattern->base.matrix))
730
	{
731
	    *src_x += pattern->base.matrix.x0 + sub->extents.x;
732
	    *src_y += pattern->base.matrix.y0 + sub->extents.y;
733
 
734
	    _cairo_xlib_surface_ensure_picture (src);
735
	    return cairo_surface_reference (&src->base);
736
	}
737
	else
738
	{
739
	    cairo_surface_pattern_t local_pattern = *pattern;
740
	    local_pattern.base.matrix.x0 += sub->extents.x;
741
	    local_pattern.base.matrix.y0 += sub->extents.y;
742
	    local_pattern.base.extend = CAIRO_EXTEND_NONE;
743
	    return embedded_source (dst, &local_pattern, extents,
744
				    src_x, src_y, init_source (dst, src));
745
	}
746
    }
747
 
748
    if (sub->snapshot && sub->snapshot->type == CAIRO_SURFACE_TYPE_XLIB) {
749
	src = (cairo_xlib_surface_t *) cairo_surface_reference (sub->snapshot);
750
	source = &src->embedded_source;
751
    } else {
752
	src = (cairo_xlib_surface_t *)
753
	    _cairo_surface_create_similar_scratch (&dst->base,
754
						   sub->base.content,
755
						   sub->extents.width,
756
						   sub->extents.height);
757
	if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
758
	    cairo_surface_destroy (&src->base);
759
	    return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
760
	}
761
 
762
	_cairo_pattern_init_for_surface (&local_pattern, sub->target);
763
	cairo_matrix_init_translate (&local_pattern.base.matrix,
764
				     sub->extents.x, sub->extents.y);
765
	local_pattern.base.filter = CAIRO_FILTER_NEAREST;
766
	status = _cairo_surface_paint (&src->base,
767
				       CAIRO_OPERATOR_SOURCE,
768
				       &local_pattern.base,
769
				       NULL);
770
	_cairo_pattern_fini (&local_pattern.base);
771
 
772
	if (unlikely (status)) {
773
	    cairo_surface_destroy (&src->base);
774
	    return _cairo_surface_create_in_error (status);
775
	}
776
 
777
	_cairo_xlib_surface_ensure_picture (src);
778
	_cairo_surface_subsurface_set_snapshot (&sub->base, &src->base);
779
 
780
	source = &src->embedded_source;
781
	source->has_component_alpha = 0;
782
	source->has_matrix = 0;
783
	source->filter = CAIRO_FILTER_NEAREST;
784
	source->extend = CAIRO_EXTEND_NONE;
785
    }
786
 
787
    status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
788
						    pattern->base.filter,
789
						    extents->x + extents->width / 2,
790
						    extents->y + extents->height / 2,
791
						    (pixman_transform_t *)&xtransform,
792
						    src_x, src_y);
793
    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
794
	if (source->has_matrix) {
795
	    source->has_matrix = 0;
796
	    memcpy (&xtransform, &identity, sizeof (identity));
797
	    status = CAIRO_INT_STATUS_SUCCESS;
798
	}
799
    } else
800
	source->has_matrix = 1;
801
    if (status == CAIRO_INT_STATUS_SUCCESS)
802
	XRenderSetPictureTransform (dpy, src->picture, &xtransform);
803
 
804
    if (source->filter != pattern->base.filter) {
805
	picture_set_filter (dpy, src->picture, pattern->base.filter);
806
	source->filter = pattern->base.filter;
807
    }
808
 
809
    if (source->has_component_alpha != pattern->base.has_component_alpha) {
810
	pa.component_alpha = pattern->base.has_component_alpha;
811
	mask |= CPComponentAlpha;
812
	source->has_component_alpha = pattern->base.has_component_alpha;
813
    }
814
 
815
    if (source->extend != pattern->base.extend) {
816
	pa.repeat = extend_to_repeat (pattern->base.extend);
817
	mask |= CPRepeat;
818
	source->extend = pattern->base.extend;
819
    }
820
 
821
    if (mask)
822
	XRenderChangePicture (dpy, src->picture, mask, &pa);
823
 
824
    return &src->base;
825
}
826
 
827
static cairo_surface_t *
828
native_source (cairo_xlib_surface_t *dst,
829
	       const cairo_surface_pattern_t *pattern,
830
	       cairo_bool_t is_mask,
831
	       const cairo_rectangle_int_t *extents,
832
	       const cairo_rectangle_int_t *sample,
833
	       int *src_x, int *src_y)
834
{
835
    cairo_xlib_surface_t *src;
836
    cairo_int_status_t status;
837
 
838
    if (_cairo_surface_is_subsurface (pattern->surface))
839
	return subsurface_source (dst, pattern, is_mask,
840
				  extents, sample,
841
				  src_x, src_y);
842
 
843
    src = unwrap_source (pattern);
844
    status = _cairo_surface_flush (&src->base, 0);
845
    if (unlikely (status))
846
	return _cairo_surface_create_in_error (status);
847
 
848
    if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
849
	sample->x >= 0 && sample->y >= 0 &&
850
	sample->x + sample->width  <= src->width &&
851
	sample->y + sample->height <= src->height &&
852
	_cairo_matrix_is_translation (&pattern->base.matrix))
853
    {
854
	*src_x += pattern->base.matrix.x0;
855
	*src_y += pattern->base.matrix.y0;
856
	_cairo_xlib_surface_ensure_picture (src);
857
	return cairo_surface_reference (&src->base);
858
    }
859
 
860
    return embedded_source (dst, pattern, extents, src_x, src_y,
861
			    init_source (dst, src));
862
}
863
 
864
static cairo_surface_t *
865
recording_pattern_get_surface (const cairo_pattern_t *pattern)
866
{
867
    cairo_surface_t *surface;
868
 
869
    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
870
    if (_cairo_surface_is_paginated (surface))
871
	surface = _cairo_paginated_surface_get_recording (surface);
872
    if (_cairo_surface_is_snapshot (surface))
873
	surface = _cairo_surface_snapshot_get_target (surface);
874
    return surface;
875
}
876
 
877
static cairo_surface_t *
878
record_source (cairo_xlib_surface_t *dst,
879
	       const cairo_surface_pattern_t *pattern,
880
	       cairo_bool_t is_mask,
881
	       const cairo_rectangle_int_t *extents,
882
	       const cairo_rectangle_int_t *sample,
883
	       int *src_x, int *src_y)
884
{
885
    cairo_xlib_surface_t *src;
886
    cairo_matrix_t matrix, m;
887
    cairo_status_t status;
888
    cairo_rectangle_int_t upload, limit;
889
 
890
    upload = *sample;
891
    if (_cairo_surface_get_extents (pattern->surface, &limit) &&
892
	! _cairo_rectangle_intersect (&upload, &limit))
893
    {
894
	if (pattern->base.extend == CAIRO_EXTEND_NONE)
895
	    return alpha_source (dst, 0);
896
 
897
	upload = limit;
898
    }
899
 
900
    src = (cairo_xlib_surface_t *)
901
	_cairo_surface_create_similar_scratch (&dst->base,
902
					       pattern->surface->content,
903
					       upload.width,
904
					       upload.height);
905
    if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
906
	cairo_surface_destroy (&src->base);
907
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
908
    }
909
 
910
    cairo_matrix_init_translate (&matrix, upload.x, upload.y);
911
    status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base),
912
							&matrix, &src->base,
913
							NULL);
914
    if (unlikely (status)) {
915
	cairo_surface_destroy (&src->base);
916
	return _cairo_surface_create_in_error (status);
917
    }
918
 
919
    matrix = pattern->base.matrix;
920
    if (upload.x | upload.y) {
921
	cairo_matrix_init_translate (&m, -upload.x, -upload.y);
922
	cairo_matrix_multiply (&matrix, &matrix, &m);
923
    }
924
 
925
    _cairo_xlib_surface_ensure_picture (src);
926
    if (! picture_set_properties (src->display, src->picture,
927
				  &pattern->base, &matrix, extents,
928
				  src_x, src_y))
929
    {
930
	cairo_surface_destroy (&src->base);
931
	return render_pattern (dst, &pattern->base, is_mask,
932
			       extents, src_x, src_y);
933
    }
934
 
935
    return &src->base;
936
}
937
 
938
static cairo_surface_t *
939
surface_source (cairo_xlib_surface_t *dst,
940
		const cairo_surface_pattern_t *pattern,
941
		cairo_bool_t is_mask,
942
		const cairo_rectangle_int_t *extents,
943
		const cairo_rectangle_int_t *sample,
944
		int *src_x, int *src_y)
945
{
946
    cairo_surface_t *src;
947
    cairo_xlib_surface_t *xsrc;
948
    cairo_surface_pattern_t local_pattern;
949
    cairo_status_t status;
950
    cairo_rectangle_int_t upload, limit;
951
 
952
    src = pattern->surface;
953
    if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
954
	src->device == dst->base.device &&
955
	_cairo_xlib_shm_surface_get_pixmap (src)) {
956
	cairo_xlib_proxy_t *proxy;
957
 
958
	proxy = malloc (sizeof(*proxy));
959
	if (unlikely (proxy == NULL))
960
	    return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
961
 
962
	_cairo_surface_init (&proxy->source.base,
963
			     &cairo_xlib_proxy_backend,
964
			     dst->base.device,
965
			     src->content);
966
 
967
	proxy->source.dpy = dst->display->display;
968
	proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
969
						      _cairo_xlib_shm_surface_get_pixmap (src),
970
						      _cairo_xlib_shm_surface_get_xrender_format (src),
971
						      0, NULL);
972
	proxy->source.pixmap = None;
973
 
974
	proxy->source.has_component_alpha = 0;
975
	proxy->source.has_matrix = 0;
976
	proxy->source.filter = CAIRO_FILTER_NEAREST;
977
	proxy->source.extend = CAIRO_EXTEND_NONE;
978
	proxy->owner = cairo_surface_reference (src);
979
 
980
	return embedded_source (dst, pattern, extents, src_x, src_y,
981
				&proxy->source);
982
    }
983
 
984
    upload = *sample;
985
    if (_cairo_surface_get_extents (pattern->surface, &limit)) {
986
	if (pattern->base.extend == CAIRO_EXTEND_NONE) {
987
	    if (! _cairo_rectangle_intersect (&upload, &limit))
988
		return alpha_source (dst, 0);
989
	} else if (pattern->base.extend == CAIRO_EXTEND_PAD) {
990
	    if (! _cairo_rectangle_intersect (&upload, &limit))
991
		upload = limit;
992
	} else {
993
	    if (upload.x < limit.x ||
994
		upload.x + upload.width > limit.x + limit.width ||
995
		upload.y < limit.y ||
996
		upload.y + upload.height > limit.y + limit.height)
997
	    {
998
		upload = limit;
999
	    }
1000
	}
1001
    }
1002
 
1003
    xsrc = (cairo_xlib_surface_t *)
1004
	    _cairo_surface_create_similar_scratch (&dst->base,
1005
						   src->content,
1006
						   upload.width,
1007
						   upload.height);
1008
    if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
1009
	cairo_surface_destroy (src);
1010
	cairo_surface_destroy (&xsrc->base);
1011
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1012
    }
1013
 
1014
    if (_cairo_surface_is_image (src)) {
1015
	status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
1016
						 upload.x, upload.y,
1017
						 upload.width, upload.height,
1018
						 0, 0);
1019
    } else {
1020
	cairo_image_surface_t *image;
1021
	cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
1022
 
1023
	image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
1024
 
1025
	_cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
1026
	cairo_matrix_init_translate (&local_pattern.base.matrix,
1027
				     upload.x, upload.y);
1028
 
1029
	status = _cairo_surface_paint (&image->base,
1030
				       CAIRO_OPERATOR_SOURCE,
1031
				       &local_pattern.base,
1032
				       NULL);
1033
	_cairo_pattern_fini (&local_pattern.base);
1034
 
1035
	status = _cairo_surface_unmap_image (&xsrc->base, image);
1036
	if (unlikely (status)) {
1037
	    cairo_surface_destroy (&xsrc->base);
1038
	    return _cairo_surface_create_in_error (status);
1039
	}
1040
 
1041
	status = _cairo_xlib_surface_put_shm (xsrc);
1042
	if (unlikely (status)) {
1043
	    cairo_surface_destroy (&xsrc->base);
1044
	    return _cairo_surface_create_in_error (status);
1045
	}
1046
    }
1047
 
1048
    _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
1049
    if (upload.x | upload.y) {
1050
	cairo_matrix_t m;
1051
	cairo_matrix_init_translate (&m, -upload.x, -upload.y);
1052
	cairo_matrix_multiply (&local_pattern.base.matrix,
1053
			       &local_pattern.base.matrix,
1054
			       &m);
1055
    }
1056
 
1057
    *src_x = *src_y = 0;
1058
    _cairo_xlib_surface_ensure_picture (xsrc);
1059
    if (! picture_set_properties (xsrc->display,
1060
				  xsrc->picture,
1061
				  &local_pattern.base,
1062
				  &local_pattern.base.matrix,
1063
				  extents,
1064
				  src_x, src_y))
1065
    {
1066
	cairo_surface_destroy (&xsrc->base);
1067
	return render_pattern (dst, &pattern->base,
1068
			       is_mask, extents,
1069
			       src_x, src_y);
1070
    }
1071
 
1072
    return &xsrc->base;
1073
}
1074
 
1075
static cairo_bool_t
1076
pattern_is_supported (cairo_xlib_display_t *display,
1077
		      const cairo_pattern_t *pattern)
1078
{
1079
    if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
1080
	return FALSE;
1081
 
1082
    if (display->buggy_pad_reflect) {
1083
	if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
1084
	    return FALSE;
1085
    }
1086
 
1087
    if (display->buggy_gradients) {
1088
	if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1089
	    return FALSE;
1090
    }
1091
 
1092
    if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
1093
	if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
1094
	    return FALSE;
1095
    }
1096
 
1097
    if (! CAIRO_RENDER_HAS_FILTERS (display)) {
1098
	    /* No filters implies no transforms, so we optimise away BILINEAR */
1099
    }
1100
 
1101
    return TRUE;
1102
}
1103
cairo_surface_t *
1104
_cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
1105
				       const cairo_pattern_t *pattern,
1106
				       cairo_bool_t is_mask,
1107
				       const cairo_rectangle_int_t *extents,
1108
				       const cairo_rectangle_int_t *sample,
1109
				       int *src_x, int *src_y)
1110
{
1111
    cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
1112
 
1113
    *src_x = *src_y = 0;
1114
 
1115
    if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1116
	if (pattern == NULL)
1117
	    pattern = &_cairo_pattern_white.base;
1118
 
1119
	return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
1120
    }
1121
 
1122
    if (pattern_is_supported (dst->display, pattern)) {
1123
	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1124
	    cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern;
1125
	    if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB &&
1126
		_cairo_xlib_surface_same_screen (dst,
1127
						 unwrap_source (spattern)))
1128
		return native_source (dst, spattern, is_mask,
1129
				      extents, sample,
1130
				      src_x, src_y);
1131
 
1132
	    if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1133
		return record_source (dst, spattern, is_mask,
1134
				      extents, sample,
1135
				      src_x, src_y);
1136
 
1137
	    return surface_source (dst, spattern, is_mask,
1138
				   extents, sample,
1139
				   src_x, src_y);
1140
	}
1141
 
1142
	if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1143
	    pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1144
	{
1145
	    cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
1146
	    return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
1147
	}
1148
    }
1149
 
1150
    return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
1151
}
1152
 
1153
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */