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
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
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.
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
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/
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.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is University of Southern
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
43 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
45 #include "cairo-xlib-private.h"
46 #include "cairo-xlib-surface-private.h"
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"
59 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
61 static cairo_xlib_surface_t *
62 unwrap_source (const cairo_surface_pattern_t *pattern)
64 cairo_rectangle_int_t limits;
65 return (cairo_xlib_surface_t *)_cairo_pattern_get_source (pattern, &limits);
69 _cairo_xlib_source_finish (void *abstract_surface)
71 cairo_xlib_source_t *source = abstract_surface;
73 XRenderFreePicture (source->dpy, source->picture);
74 return CAIRO_STATUS_SUCCESS;
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 */
84 _cairo_xlib_proxy_finish (void *abstract_surface)
86 cairo_xlib_proxy_t *proxy = abstract_surface;
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;
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 */
100 static cairo_surface_t *
101 source (cairo_xlib_surface_t *dst, Picture picture)
103 cairo_xlib_source_t *source;
106 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
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));
114 _cairo_surface_init (&source->base,
115 &cairo_xlib_source_backend,
117 CAIRO_CONTENT_COLOR_ALPHA);
119 /* The source exists only within an operation */
120 source->picture = picture;
121 source->dpy = dst->display->display;
123 return &source->base;
127 hars_petruska_f54_1_random (void)
129 #define rol(x,k) ((x << k) | (x >> (32-k)))
131 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
135 static const XTransform identity = {
137 { 1 << 16, 0x00000, 0x00000 },
138 { 0x00000, 1 << 16, 0x00000 },
139 { 0x00000, 0x00000, 1 << 16 },
144 picture_set_matrix (cairo_xlib_display_t *display,
146 const cairo_matrix_t *matrix,
147 cairo_filter_t filter,
153 XTransform xtransform;
154 pixman_transform_t *pixman_transform;
155 cairo_int_status_t status;
157 /* Casting between pixman_transform_t and XTransform is safe because
158 * they happen to be the exact same type.
160 pixman_transform = (pixman_transform_t *) &xtransform;
161 status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
164 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
166 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
169 if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
172 /* a late check in case we perturb the matrix too far */
173 if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display))
176 XRenderSetPictureTransform (display->display, picture, &xtransform);
180 static cairo_status_t
181 picture_set_filter (Display *dpy,
183 cairo_filter_t filter)
185 const char *render_filter;
188 case CAIRO_FILTER_FAST:
189 render_filter = FilterFast;
191 case CAIRO_FILTER_GOOD:
192 render_filter = FilterGood;
194 case CAIRO_FILTER_BEST:
195 render_filter = FilterBest;
197 case CAIRO_FILTER_NEAREST:
198 render_filter = FilterNearest;
200 case CAIRO_FILTER_BILINEAR:
201 render_filter = FilterBilinear;
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. */
210 render_filter = FilterBest;
214 XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0);
215 return CAIRO_STATUS_SUCCESS;
219 extend_to_repeat (cairo_extend_t extend)
224 case CAIRO_EXTEND_NONE:
226 case CAIRO_EXTEND_REPEAT:
228 case CAIRO_EXTEND_REFLECT:
229 return RepeatReflect;
230 case CAIRO_EXTEND_PAD:
236 picture_set_properties (cairo_xlib_display_t *display,
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)
243 XRenderPictureAttributes pa;
246 if (! picture_set_matrix (display, picture, matrix, pattern->filter,
247 extents->x + extents->width / 2,
248 extents->y + extents->height / 2,
252 picture_set_filter (display->display, picture, pattern->filter);
254 if (pattern->has_component_alpha) {
255 pa.component_alpha = 1;
256 mask |= CPComponentAlpha;
259 if (pattern->extend != CAIRO_EXTEND_NONE) {
260 pa.repeat = extend_to_repeat (pattern->extend);
265 XRenderChangePicture (display->display, picture, mask, &pa);
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)
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;
283 src = (cairo_xlib_surface_t *)
284 _cairo_surface_create_similar_scratch (&dst->base,
285 is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
288 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
289 cairo_surface_destroy (&src->base);
293 map_extents = *extents;
294 map_extents.x = map_extents.y = 0;
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,
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);
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);
312 src->picture = XRenderCreatePicture (dpy,
313 src->drawable, src->xrender_format,
316 *src_x = -extents->x;
317 *src_y = -extents->y;
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)
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];
333 XRenderColor *colors;
335 unsigned int i, n_stops;
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);
343 assert (gradient->n_stops > 0);
344 n_stops = MAX (gradient->n_stops, 2);
346 if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
348 stops = (XFixed *) buf;
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));
359 colors = (XRenderColor *) (stops + n_stops);
360 for (i = 0; i < gradient->n_stops; i++) {
362 _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
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;
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) {
375 _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
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;
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
393 XSync (display->display, False);
396 _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
398 if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
399 XLinearGradient grad;
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);
406 picture = XRenderCreateLinearGradient (display->display, &grad,
410 XRadialGradient grad;
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);
419 picture = XRenderCreateRadialGradient (display->display, &grad,
424 if (stops != (XFixed *) buf)
428 if (! picture_set_properties (display, picture,
429 &gradient->base, &gradient->base.matrix,
432 XRenderFreePicture (display->display, picture);
433 return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
436 return source (dst, picture);
439 static cairo_surface_t *
440 color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
442 XRenderColor xrender_color;
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;
450 XRenderCreateSolidFill (dst->display->display,
454 static cairo_surface_t *
455 alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha)
457 cairo_xlib_display_t *display = dst->display;
459 if (display->alpha[alpha] == NULL) {
462 color.red_short = color.green_short = color.blue_short = 0;
463 color.alpha_short = alpha << 8 | alpha;
465 display->alpha[alpha] = color_source (dst, &color);
468 return cairo_surface_reference (display->alpha[alpha]);
471 static cairo_surface_t *
472 white_source (cairo_xlib_surface_t *dst)
474 cairo_xlib_display_t *display = dst->display;
476 if (display->white == NULL)
477 display->white = color_source (dst, CAIRO_COLOR_WHITE);
479 return cairo_surface_reference (display->white);
482 static cairo_surface_t *
483 opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
485 cairo_xlib_display_t *display = dst->display;
488 color->red_short >> 8 << 16 |
489 color->green_short >> 8 << 8 |
490 color->blue_short >> 8 << 0;
493 if (display->last_solid_cache[0].color == pixel)
494 return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]);
496 for (i = 0; i < 16; i++) {
497 if (display->solid_cache[i] == pixel)
501 i = hars_petruska_f54_1_random () % 16;
502 cairo_surface_destroy (display->solid[i]);
504 display->solid[i] = color_source (dst, color);
505 display->solid_cache[i] = pixel;
508 display->last_solid_cache[0].color = pixel;
509 display->last_solid_cache[0].index = i;
510 return cairo_surface_reference (display->solid[i]);
513 static cairo_surface_t *
514 transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
516 cairo_xlib_display_t *display = dst->display;
518 color->alpha_short >> 8 << 24 |
519 color->red_short >> 8 << 16 |
520 color->green_short >> 8 << 8 |
521 color->blue_short >> 8 << 0;
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]);
529 for (i = 16; i < 32; i++) {
530 if (display->solid_cache[i] == pixel)
534 i = 16 + (hars_petruska_f54_1_random () % 16);
535 cairo_surface_destroy (display->solid[i]);
537 display->solid[i] = color_source (dst, color);
538 display->solid_cache[i] = pixel;
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]);
547 static cairo_surface_t *
548 solid_source (cairo_xlib_surface_t *dst,
549 const cairo_color_t *color)
551 if ((color->red_short | color->green_short | color->blue_short) <= 0xff)
552 return alpha_source (dst, color->alpha_short >> 8);
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);
558 return opaque_source (dst, color);
560 return transparent_source (dst, color);
563 static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst,
564 cairo_xlib_surface_t *src)
566 Display *dpy = dst->display->display;
567 cairo_xlib_source_t *source = &src->embedded_source;
569 /* As these are frequent and meant to be fast, we track pictures for
570 * native surface and minimise update requests.
572 if (source->picture == None) {
573 XRenderPictureAttributes pa;
575 _cairo_surface_init (&source->base,
576 &cairo_xlib_source_backend,
578 CAIRO_CONTENT_COLOR_ALPHA);
580 pa.subwindow_mode = IncludeInferiors;
581 source->picture = XRenderCreatePicture (dpy,
584 CPSubwindowMode, &pa);
586 source->has_component_alpha = 0;
587 source->has_matrix = 0;
588 source->filter = CAIRO_FILTER_NEAREST;
589 source->extend = CAIRO_EXTEND_NONE;
592 return (cairo_xlib_source_t *) cairo_surface_reference (&source->base);
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)
602 Display *dpy = dst->display->display;
603 cairo_int_status_t status;
604 XTransform xtransform;
605 XRenderPictureAttributes pa;
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,
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;
622 source->has_matrix = 1;
623 if (status == CAIRO_INT_STATUS_SUCCESS)
624 XRenderSetPictureTransform (dpy, source->picture, &xtransform);
626 if (source->filter != pattern->base.filter) {
627 picture_set_filter (dpy, source->picture, pattern->base.filter);
628 source->filter = pattern->base.filter;
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;
637 if (source->extend != pattern->base.extend) {
638 pa.repeat = extend_to_repeat (pattern->base.extend);
640 source->extend = pattern->base.extend;
644 XRenderChangePicture (dpy, source->picture, mask, &pa);
646 return &source->base;
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)
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;
667 sub = (cairo_surface_subsurface_t *) pattern->surface;
669 if (sample->x >= 0 && sample->y >= 0 &&
670 sample->x + sample->width <= sub->extents.width &&
671 sample->y + sample->height <= sub->extents.height)
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);
678 if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
679 _cairo_matrix_is_translation (&pattern->base.matrix))
681 *src_x += pattern->base.matrix.x0 + sub->extents.x;
682 *src_y += pattern->base.matrix.y0 + sub->extents.y;
684 _cairo_xlib_surface_ensure_picture (src);
685 return cairo_surface_reference (&src->base);
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));
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;
702 src = (cairo_xlib_surface_t *)
703 _cairo_surface_create_similar_scratch (&dst->base,
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);
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,
720 _cairo_pattern_fini (&local_pattern.base);
722 if (unlikely (status)) {
723 cairo_surface_destroy (&src->base);
724 return _cairo_surface_create_in_error (status);
727 _cairo_xlib_surface_ensure_picture (src);
728 _cairo_surface_subsurface_set_snapshot (&sub->base, &src->base);
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;
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,
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;
750 source->has_matrix = 1;
751 if (status == CAIRO_INT_STATUS_SUCCESS)
752 XRenderSetPictureTransform (dpy, src->picture, &xtransform);
754 if (source->filter != pattern->base.filter) {
755 picture_set_filter (dpy, src->picture, pattern->base.filter);
756 source->filter = pattern->base.filter;
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;
765 if (source->extend != pattern->base.extend) {
766 pa.repeat = extend_to_repeat (pattern->base.extend);
768 source->extend = pattern->base.extend;
772 XRenderChangePicture (dpy, src->picture, mask, &pa);
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)
785 cairo_xlib_surface_t *src;
786 cairo_int_status_t status;
788 if (_cairo_surface_is_subsurface (pattern->surface))
789 return subsurface_source (dst, pattern, is_mask,
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);
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))
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);
810 return embedded_source (dst, pattern, extents, src_x, src_y,
811 init_source (dst, src));
814 static cairo_surface_t *
815 recording_pattern_get_surface (const cairo_pattern_t *pattern)
817 cairo_surface_t *surface;
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);
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)
835 cairo_xlib_surface_t *src;
836 cairo_matrix_t matrix, m;
837 cairo_status_t status;
838 cairo_rectangle_int_t upload, limit;
841 if (_cairo_surface_get_extents (pattern->surface, &limit) &&
842 ! _cairo_rectangle_intersect (&upload, &limit))
844 if (pattern->base.extend == CAIRO_EXTEND_NONE)
845 return alpha_source (dst, 0);
850 src = (cairo_xlib_surface_t *)
851 _cairo_surface_create_similar_scratch (&dst->base,
852 pattern->surface->content,
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);
860 cairo_matrix_init_translate (&matrix, upload.x, upload.y);
861 status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base),
864 if (unlikely (status)) {
865 cairo_surface_destroy (&src->base);
866 return _cairo_surface_create_in_error (status);
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);
875 _cairo_xlib_surface_ensure_picture (src);
876 if (! picture_set_properties (src->display, src->picture,
877 &pattern->base, &matrix, extents,
880 cairo_surface_destroy (&src->base);
881 return render_pattern (dst, &pattern->base, is_mask,
882 extents, src_x, src_y);
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)
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;
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;
909 cairo_surface_reference (src);
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);
918 _cairo_surface_init (&proxy->source.base,
919 &cairo_xlib_proxy_backend,
921 CAIRO_CONTENT_COLOR_ALPHA);
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),
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;
935 return embedded_source (dst, pattern, extents, src_x, src_y,
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);
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)
955 src = _cairo_xlib_surface_create_similar_shm (&dst->base,
956 _cairo_format_from_content (pattern->surface->content),
960 _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
961 cairo_matrix_init_translate (&local_pattern.base.matrix,
964 map_extents = upload;
965 map_extents.x = map_extents.y = 0;
967 status = _cairo_surface_paint (src,
968 CAIRO_OPERATOR_SOURCE,
971 _cairo_pattern_fini (&local_pattern.base);
973 if (unlikely (status)) {
974 cairo_surface_destroy (src);
975 return _cairo_surface_create_in_error (status);
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,
987 if (src->device == dst->base.device &&
988 _cairo_xlib_shm_surface_get_pixmap (src)) {
989 pattern = &local_pattern;
990 goto prepare_shm_image;
993 xsrc = (cairo_xlib_surface_t *)
994 _cairo_surface_create_similar_scratch (&dst->base,
998 if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
999 cairo_surface_destroy (src);
1000 cairo_surface_destroy (&xsrc->base);
1004 status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
1006 upload.width, upload.height,
1008 cairo_surface_destroy (src);
1010 _cairo_xlib_surface_ensure_picture (xsrc);
1011 if (! picture_set_properties (xsrc->display,
1013 &local_pattern.base,
1014 &local_pattern.base.matrix,
1018 cairo_surface_destroy (&xsrc->base);
1019 return render_pattern (dst, &pattern->base,
1028 pattern_is_supported (cairo_xlib_display_t *display,
1029 const cairo_pattern_t *pattern)
1031 if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
1034 if (display->buggy_pad_reflect) {
1035 if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
1039 if (display->buggy_gradients) {
1040 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1044 if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
1045 if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
1049 if (! CAIRO_RENDER_HAS_FILTERS (display)) {
1050 /* No filters implies no transforms, so we optimise away BILINEAR */
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)
1063 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
1065 *src_x = *src_y = 0;
1067 if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1068 if (pattern == NULL)
1069 pattern = &_cairo_pattern_white.base;
1071 return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
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,
1084 if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1085 return record_source (dst, spattern, is_mask,
1089 return surface_source (dst, spattern, is_mask,
1094 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1095 pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1097 cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
1098 return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
1102 return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
1105 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */