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