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