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-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"
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);
75 XFreePixmap (source->dpy, source->pixmap);
76 return CAIRO_STATUS_SUCCESS;
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 */
86 _cairo_xlib_proxy_finish (void *abstract_surface)
88 cairo_xlib_proxy_t *proxy = abstract_surface;
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;
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 */
104 static cairo_surface_t *
105 source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
107 cairo_xlib_source_t *source;
110 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
112 source = malloc (sizeof (*source));
113 if (unlikely (source == NULL)) {
114 XRenderFreePicture (dst->display->display, picture);
116 XFreePixmap (dst->display->display, pixmap);
117 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
120 _cairo_surface_init (&source->base,
121 &cairo_xlib_source_backend,
123 CAIRO_CONTENT_COLOR_ALPHA);
125 /* The source exists only within an operation */
126 source->picture = picture;
127 source->pixmap = pixmap;
128 source->dpy = dst->display->display;
130 return &source->base;
134 hars_petruska_f54_1_random (void)
136 #define rol(x,k) ((x << k) | (x >> (32-k)))
138 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
142 static const XTransform identity = {
144 { 1 << 16, 0x00000, 0x00000 },
145 { 0x00000, 1 << 16, 0x00000 },
146 { 0x00000, 0x00000, 1 << 16 },
151 picture_set_matrix (cairo_xlib_display_t *display,
153 const cairo_matrix_t *matrix,
154 cairo_filter_t filter,
160 XTransform xtransform;
161 pixman_transform_t *pixman_transform;
162 cairo_int_status_t status;
164 /* Casting between pixman_transform_t and XTransform is safe because
165 * they happen to be the exact same type.
167 pixman_transform = (pixman_transform_t *) &xtransform;
168 status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
171 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
173 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
176 if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
179 /* a late check in case we perturb the matrix too far */
180 if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display))
183 XRenderSetPictureTransform (display->display, picture, &xtransform);
187 static cairo_status_t
188 picture_set_filter (Display *dpy,
190 cairo_filter_t filter)
192 const char *render_filter;
195 case CAIRO_FILTER_FAST:
196 render_filter = FilterFast;
198 case CAIRO_FILTER_GOOD:
199 render_filter = FilterGood;
201 case CAIRO_FILTER_BEST:
202 render_filter = FilterBest;
204 case CAIRO_FILTER_NEAREST:
205 render_filter = FilterNearest;
207 case CAIRO_FILTER_BILINEAR:
208 render_filter = FilterBilinear;
210 case CAIRO_FILTER_GAUSSIAN:
211 /* XXX: The GAUSSIAN value has no implementation in cairo
212 * whatsoever, so it was really a mistake to have it in the
213 * API. We could fix this by officially deprecating it, or
214 * else inventing semantics and providing an actual
215 * implementation for it. */
217 render_filter = FilterBest;
221 XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0);
222 return CAIRO_STATUS_SUCCESS;
226 extend_to_repeat (cairo_extend_t extend)
231 case CAIRO_EXTEND_NONE:
233 case CAIRO_EXTEND_REPEAT:
235 case CAIRO_EXTEND_REFLECT:
236 return RepeatReflect;
237 case CAIRO_EXTEND_PAD:
243 picture_set_properties (cairo_xlib_display_t *display,
245 const cairo_pattern_t *pattern,
246 const cairo_matrix_t *matrix,
247 const cairo_rectangle_int_t *extents,
248 int *x_off, int *y_off)
250 XRenderPictureAttributes pa;
253 if (! picture_set_matrix (display, picture, matrix, pattern->filter,
254 extents->x + extents->width / 2,
255 extents->y + extents->height / 2,
259 picture_set_filter (display->display, picture, pattern->filter);
261 if (pattern->has_component_alpha) {
262 pa.component_alpha = 1;
263 mask |= CPComponentAlpha;
266 if (pattern->extend != CAIRO_EXTEND_NONE) {
267 pa.repeat = extend_to_repeat (pattern->extend);
272 XRenderChangePicture (display->display, picture, mask, &pa);
277 static cairo_surface_t *
278 render_pattern (cairo_xlib_surface_t *dst,
279 const cairo_pattern_t *pattern,
280 cairo_bool_t is_mask,
281 const cairo_rectangle_int_t *extents,
282 int *src_x, int *src_y)
284 Display *dpy = dst->display->display;
285 cairo_xlib_surface_t *src;
286 cairo_image_surface_t *image;
287 cairo_status_t status;
288 cairo_rectangle_int_t map_extents;
290 src = (cairo_xlib_surface_t *)
291 _cairo_surface_create_similar_scratch (&dst->base,
292 is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
295 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
296 cairo_surface_destroy (&src->base);
300 map_extents = *extents;
301 map_extents.x = map_extents.y = 0;
303 image = _cairo_surface_map_to_image (&src->base, &map_extents);
304 status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
305 CAIRO_OPERATOR_SOURCE, pattern,
307 status = _cairo_surface_unmap_image (&src->base, image);
308 if (unlikely (status)) {
309 cairo_surface_destroy (&src->base);
310 return _cairo_surface_create_in_error (status);
313 status = _cairo_xlib_surface_put_shm (src);
314 if (unlikely (status)) {
315 cairo_surface_destroy (&src->base);
316 return _cairo_surface_create_in_error (status);
319 src->picture = XRenderCreatePicture (dpy,
320 src->drawable, src->xrender_format,
323 *src_x = -extents->x;
324 *src_y = -extents->y;
328 static cairo_surface_t *
329 gradient_source (cairo_xlib_surface_t *dst,
330 const cairo_gradient_pattern_t *gradient,
331 cairo_bool_t is_mask,
332 const cairo_rectangle_int_t *extents,
333 int *src_x, int *src_y)
335 cairo_xlib_display_t *display = dst->display;
336 cairo_matrix_t matrix = gradient->base.matrix;
337 char buf[CAIRO_STACK_BUFFER_SIZE];
338 cairo_circle_double_t extremes[2];
340 XRenderColor *colors;
342 unsigned int i, n_stops;
344 /* The RENDER specification says that the inner circle has
345 * to be completely contained inside the outer one. */
346 if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL &&
347 ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
348 return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
350 assert (gradient->n_stops > 0);
351 n_stops = MAX (gradient->n_stops, 2);
353 if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
355 stops = (XFixed *) buf;
360 _cairo_malloc_ab (n_stops,
361 sizeof (XFixed) + sizeof (XRenderColor));
362 if (unlikely (stops == NULL))
363 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
366 colors = (XRenderColor *) (stops + n_stops);
367 for (i = 0; i < gradient->n_stops; i++) {
369 _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
371 colors[i].red = gradient->stops[i].color.red_short;
372 colors[i].green = gradient->stops[i].color.green_short;
373 colors[i].blue = gradient->stops[i].color.blue_short;
374 colors[i].alpha = gradient->stops[i].color.alpha_short;
377 /* RENDER does not support gradients with less than 2
378 * stops. If a gradient has only a single stop, duplicate
379 * it to make RENDER happy. */
380 if (gradient->n_stops == 1) {
382 _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
384 colors[1].red = gradient->stops[0].color.red_short;
385 colors[1].green = gradient->stops[0].color.green_short;
386 colors[1].blue = gradient->stops[0].color.blue_short;
387 colors[1].alpha = gradient->stops[0].color.alpha_short;
391 /* For some weird reason the X server is sometimes getting
392 * CreateGradient requests with bad length. So far I've only seen
393 * XRenderCreateLinearGradient request with 4 stops sometime end up
394 * with length field matching 0 stops at the server side. I've
395 * looked at the libXrender code and I can't see anything that
396 * could cause this behavior. However, for some reason having a
397 * XSync call here seems to avoid the issue so I'll keep it here
400 XSync (display->display, False);
403 _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
405 if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
406 XLinearGradient grad;
408 grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
409 grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
410 grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
411 grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
413 picture = XRenderCreateLinearGradient (display->display, &grad,
417 XRadialGradient grad;
419 grad.inner.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
420 grad.inner.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
421 grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
422 grad.outer.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
423 grad.outer.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
424 grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
426 picture = XRenderCreateRadialGradient (display->display, &grad,
431 if (stops != (XFixed *) buf)
435 if (! picture_set_properties (display, picture,
436 &gradient->base, &gradient->base.matrix,
439 XRenderFreePicture (display->display, picture);
440 return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
443 return source (dst, picture, None);
446 static cairo_surface_t *
447 color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
449 Display *dpy = dst->display->display;
452 Pixmap pixmap = None;
454 xcolor.red = color->red_short;
455 xcolor.green = color->green_short;
456 xcolor.blue = color->blue_short;
457 xcolor.alpha = color->alpha_short;
459 if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
460 picture = XRenderCreateSolidFill (dpy, &xcolor);
462 XRenderPictureAttributes pa;
465 pa.repeat = RepeatNormal;
468 pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
469 picture = XRenderCreatePicture (dpy, pixmap,
470 _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
473 if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
474 XRectangle r = { 0, 0, 1, 1};
475 XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
480 gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
482 if (unlikely (gc == NULL)) {
483 XFreePixmap (dpy, pixmap);
484 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
488 gcv.foreground |= color->alpha_short >> 8 << 24;
489 gcv.foreground |= color->red_short >> 8 << 16;
490 gcv.foreground |= color->green_short >> 8 << 8;
491 gcv.foreground |= color->blue_short >> 8 << 0;
492 gcv.fill_style = FillSolid;
494 XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
495 XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
497 _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
501 return source (dst, picture, pixmap);
504 static cairo_surface_t *
505 alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha)
507 cairo_xlib_display_t *display = dst->display;
509 if (display->alpha[alpha] == NULL) {
512 color.red_short = color.green_short = color.blue_short = 0;
513 color.alpha_short = alpha << 8 | alpha;
515 display->alpha[alpha] = color_source (dst, &color);
518 return cairo_surface_reference (display->alpha[alpha]);
521 static cairo_surface_t *
522 white_source (cairo_xlib_surface_t *dst)
524 cairo_xlib_display_t *display = dst->display;
526 if (display->white == NULL)
527 display->white = color_source (dst, CAIRO_COLOR_WHITE);
529 return cairo_surface_reference (display->white);
532 static cairo_surface_t *
533 opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
535 cairo_xlib_display_t *display = dst->display;
538 color->red_short >> 8 << 16 |
539 color->green_short >> 8 << 8 |
540 color->blue_short >> 8 << 0;
543 if (display->last_solid_cache[0].color == pixel)
544 return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]);
546 for (i = 0; i < 16; i++) {
547 if (display->solid_cache[i] == pixel)
551 i = hars_petruska_f54_1_random () % 16;
552 cairo_surface_destroy (display->solid[i]);
554 display->solid[i] = color_source (dst, color);
555 display->solid_cache[i] = pixel;
558 display->last_solid_cache[0].color = pixel;
559 display->last_solid_cache[0].index = i;
560 return cairo_surface_reference (display->solid[i]);
563 static cairo_surface_t *
564 transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
566 cairo_xlib_display_t *display = dst->display;
568 color->alpha_short >> 8 << 24 |
569 color->red_short >> 8 << 16 |
570 color->green_short >> 8 << 8 |
571 color->blue_short >> 8 << 0;
574 if (display->last_solid_cache[1].color == pixel) {
575 assert (display->solid[display->last_solid_cache[1].index]);
576 return cairo_surface_reference (display->solid[display->last_solid_cache[1].index]);
579 for (i = 16; i < 32; i++) {
580 if (display->solid_cache[i] == pixel)
584 i = 16 + (hars_petruska_f54_1_random () % 16);
585 cairo_surface_destroy (display->solid[i]);
587 display->solid[i] = color_source (dst, color);
588 display->solid_cache[i] = pixel;
591 display->last_solid_cache[1].color = pixel;
592 display->last_solid_cache[1].index = i;
593 assert (display->solid[i]);
594 return cairo_surface_reference (display->solid[i]);
597 static cairo_surface_t *
598 solid_source (cairo_xlib_surface_t *dst,
599 const cairo_color_t *color)
601 if ((color->red_short | color->green_short | color->blue_short) <= 0xff)
602 return alpha_source (dst, color->alpha_short >> 8);
604 if (CAIRO_ALPHA_SHORT_IS_OPAQUE (color->alpha_short)) {
605 if (color->red_short >= 0xff00 && color->green_short >= 0xff00 && color->blue_short >= 0xff00)
606 return white_source (dst);
608 return opaque_source (dst, color);
610 return transparent_source (dst, color);
613 static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst,
614 cairo_xlib_surface_t *src)
616 Display *dpy = dst->display->display;
617 cairo_xlib_source_t *source = &src->embedded_source;
619 /* As these are frequent and meant to be fast, we track pictures for
620 * native surface and minimise update requests.
622 if (source->picture == None) {
623 XRenderPictureAttributes pa;
625 _cairo_surface_init (&source->base,
626 &cairo_xlib_source_backend,
628 CAIRO_CONTENT_COLOR_ALPHA);
630 pa.subwindow_mode = IncludeInferiors;
631 source->picture = XRenderCreatePicture (dpy,
634 CPSubwindowMode, &pa);
636 source->has_component_alpha = 0;
637 source->has_matrix = 0;
638 source->filter = CAIRO_FILTER_NEAREST;
639 source->extend = CAIRO_EXTEND_NONE;
642 return (cairo_xlib_source_t *) cairo_surface_reference (&source->base);
645 static cairo_surface_t *
646 embedded_source (cairo_xlib_surface_t *dst,
647 const cairo_surface_pattern_t *pattern,
648 const cairo_rectangle_int_t *extents,
649 int *src_x, int *src_y,
650 cairo_xlib_source_t *source)
652 Display *dpy = dst->display->display;
653 cairo_int_status_t status;
654 XTransform xtransform;
655 XRenderPictureAttributes pa;
658 status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
659 pattern->base.filter,
660 extents->x + extents->width / 2,
661 extents->y + extents->height / 2,
662 (pixman_transform_t *)&xtransform,
665 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
666 if (source->has_matrix) {
667 source->has_matrix = 0;
668 memcpy (&xtransform, &identity, sizeof (identity));
669 status = CAIRO_INT_STATUS_SUCCESS;
672 source->has_matrix = 1;
673 if (status == CAIRO_INT_STATUS_SUCCESS)
674 XRenderSetPictureTransform (dpy, source->picture, &xtransform);
676 if (source->filter != pattern->base.filter) {
677 picture_set_filter (dpy, source->picture, pattern->base.filter);
678 source->filter = pattern->base.filter;
681 if (source->has_component_alpha != pattern->base.has_component_alpha) {
682 pa.component_alpha = pattern->base.has_component_alpha;
683 mask |= CPComponentAlpha;
684 source->has_component_alpha = pattern->base.has_component_alpha;
687 if (source->extend != pattern->base.extend) {
688 pa.repeat = extend_to_repeat (pattern->base.extend);
690 source->extend = pattern->base.extend;
694 XRenderChangePicture (dpy, source->picture, mask, &pa);
696 return &source->base;
699 static cairo_surface_t *
700 subsurface_source (cairo_xlib_surface_t *dst,
701 const cairo_surface_pattern_t *pattern,
702 cairo_bool_t is_mask,
703 const cairo_rectangle_int_t *extents,
704 const cairo_rectangle_int_t *sample,
705 int *src_x, int *src_y)
707 cairo_surface_subsurface_t *sub;
708 cairo_xlib_surface_t *src;
709 cairo_xlib_source_t *source;
710 Display *dpy = dst->display->display;
711 cairo_int_status_t status;
712 cairo_surface_pattern_t local_pattern;
713 XTransform xtransform;
714 XRenderPictureAttributes pa;
717 sub = (cairo_surface_subsurface_t *) pattern->surface;
719 if (sample->x >= 0 && sample->y >= 0 &&
720 sample->x + sample->width <= sub->extents.width &&
721 sample->y + sample->height <= sub->extents.height)
723 src = (cairo_xlib_surface_t *) sub->target;
724 status = _cairo_surface_flush (&src->base, 0);
725 if (unlikely (status))
726 return _cairo_surface_create_in_error (status);
728 if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
729 _cairo_matrix_is_translation (&pattern->base.matrix))
731 *src_x += pattern->base.matrix.x0 + sub->extents.x;
732 *src_y += pattern->base.matrix.y0 + sub->extents.y;
734 _cairo_xlib_surface_ensure_picture (src);
735 return cairo_surface_reference (&src->base);
739 cairo_surface_pattern_t local_pattern = *pattern;
740 local_pattern.base.matrix.x0 += sub->extents.x;
741 local_pattern.base.matrix.y0 += sub->extents.y;
742 local_pattern.base.extend = CAIRO_EXTEND_NONE;
743 return embedded_source (dst, &local_pattern, extents,
744 src_x, src_y, init_source (dst, src));
748 if (sub->snapshot && sub->snapshot->type == CAIRO_SURFACE_TYPE_XLIB) {
749 src = (cairo_xlib_surface_t *) cairo_surface_reference (sub->snapshot);
750 source = &src->embedded_source;
752 src = (cairo_xlib_surface_t *)
753 _cairo_surface_create_similar_scratch (&dst->base,
756 sub->extents.height);
757 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
758 cairo_surface_destroy (&src->base);
759 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
762 _cairo_pattern_init_for_surface (&local_pattern, sub->target);
763 cairo_matrix_init_translate (&local_pattern.base.matrix,
764 sub->extents.x, sub->extents.y);
765 local_pattern.base.filter = CAIRO_FILTER_NEAREST;
766 status = _cairo_surface_paint (&src->base,
767 CAIRO_OPERATOR_SOURCE,
770 _cairo_pattern_fini (&local_pattern.base);
772 if (unlikely (status)) {
773 cairo_surface_destroy (&src->base);
774 return _cairo_surface_create_in_error (status);
777 _cairo_xlib_surface_ensure_picture (src);
778 _cairo_surface_subsurface_set_snapshot (&sub->base, &src->base);
780 source = &src->embedded_source;
781 source->has_component_alpha = 0;
782 source->has_matrix = 0;
783 source->filter = CAIRO_FILTER_NEAREST;
784 source->extend = CAIRO_EXTEND_NONE;
787 status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
788 pattern->base.filter,
789 extents->x + extents->width / 2,
790 extents->y + extents->height / 2,
791 (pixman_transform_t *)&xtransform,
793 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
794 if (source->has_matrix) {
795 source->has_matrix = 0;
796 memcpy (&xtransform, &identity, sizeof (identity));
797 status = CAIRO_INT_STATUS_SUCCESS;
800 source->has_matrix = 1;
801 if (status == CAIRO_INT_STATUS_SUCCESS)
802 XRenderSetPictureTransform (dpy, src->picture, &xtransform);
804 if (source->filter != pattern->base.filter) {
805 picture_set_filter (dpy, src->picture, pattern->base.filter);
806 source->filter = pattern->base.filter;
809 if (source->has_component_alpha != pattern->base.has_component_alpha) {
810 pa.component_alpha = pattern->base.has_component_alpha;
811 mask |= CPComponentAlpha;
812 source->has_component_alpha = pattern->base.has_component_alpha;
815 if (source->extend != pattern->base.extend) {
816 pa.repeat = extend_to_repeat (pattern->base.extend);
818 source->extend = pattern->base.extend;
822 XRenderChangePicture (dpy, src->picture, mask, &pa);
827 static cairo_surface_t *
828 native_source (cairo_xlib_surface_t *dst,
829 const cairo_surface_pattern_t *pattern,
830 cairo_bool_t is_mask,
831 const cairo_rectangle_int_t *extents,
832 const cairo_rectangle_int_t *sample,
833 int *src_x, int *src_y)
835 cairo_xlib_surface_t *src;
836 cairo_int_status_t status;
838 if (_cairo_surface_is_subsurface (pattern->surface))
839 return subsurface_source (dst, pattern, is_mask,
843 src = unwrap_source (pattern);
844 status = _cairo_surface_flush (&src->base, 0);
845 if (unlikely (status))
846 return _cairo_surface_create_in_error (status);
848 if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
849 sample->x >= 0 && sample->y >= 0 &&
850 sample->x + sample->width <= src->width &&
851 sample->y + sample->height <= src->height &&
852 _cairo_matrix_is_translation (&pattern->base.matrix))
854 *src_x += pattern->base.matrix.x0;
855 *src_y += pattern->base.matrix.y0;
856 _cairo_xlib_surface_ensure_picture (src);
857 return cairo_surface_reference (&src->base);
860 return embedded_source (dst, pattern, extents, src_x, src_y,
861 init_source (dst, src));
864 static cairo_surface_t *
865 recording_pattern_get_surface (const cairo_pattern_t *pattern)
867 cairo_surface_t *surface;
869 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
870 if (_cairo_surface_is_paginated (surface))
871 surface = _cairo_paginated_surface_get_recording (surface);
872 if (_cairo_surface_is_snapshot (surface))
873 surface = _cairo_surface_snapshot_get_target (surface);
877 static cairo_surface_t *
878 record_source (cairo_xlib_surface_t *dst,
879 const cairo_surface_pattern_t *pattern,
880 cairo_bool_t is_mask,
881 const cairo_rectangle_int_t *extents,
882 const cairo_rectangle_int_t *sample,
883 int *src_x, int *src_y)
885 cairo_xlib_surface_t *src;
886 cairo_matrix_t matrix, m;
887 cairo_status_t status;
888 cairo_rectangle_int_t upload, limit;
891 if (_cairo_surface_get_extents (pattern->surface, &limit) &&
892 ! _cairo_rectangle_intersect (&upload, &limit))
894 if (pattern->base.extend == CAIRO_EXTEND_NONE)
895 return alpha_source (dst, 0);
900 src = (cairo_xlib_surface_t *)
901 _cairo_surface_create_similar_scratch (&dst->base,
902 pattern->surface->content,
905 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
906 cairo_surface_destroy (&src->base);
907 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
910 cairo_matrix_init_translate (&matrix, upload.x, upload.y);
911 status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base),
914 if (unlikely (status)) {
915 cairo_surface_destroy (&src->base);
916 return _cairo_surface_create_in_error (status);
919 matrix = pattern->base.matrix;
920 if (upload.x | upload.y) {
921 cairo_matrix_init_translate (&m, -upload.x, -upload.y);
922 cairo_matrix_multiply (&matrix, &matrix, &m);
925 _cairo_xlib_surface_ensure_picture (src);
926 if (! picture_set_properties (src->display, src->picture,
927 &pattern->base, &matrix, extents,
930 cairo_surface_destroy (&src->base);
931 return render_pattern (dst, &pattern->base, is_mask,
932 extents, src_x, src_y);
938 static cairo_surface_t *
939 surface_source (cairo_xlib_surface_t *dst,
940 const cairo_surface_pattern_t *pattern,
941 cairo_bool_t is_mask,
942 const cairo_rectangle_int_t *extents,
943 const cairo_rectangle_int_t *sample,
944 int *src_x, int *src_y)
946 cairo_surface_t *src;
947 cairo_xlib_surface_t *xsrc;
948 cairo_surface_pattern_t local_pattern;
949 cairo_status_t status;
950 cairo_rectangle_int_t upload, limit;
951 XRenderPictFormat *format = NULL;
953 src = pattern->surface;
954 if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
955 src->device == dst->base.device &&
956 _cairo_xlib_shm_surface_get_pixmap (src)) {
957 cairo_xlib_proxy_t *proxy;
959 proxy = malloc (sizeof(*proxy));
960 if (unlikely (proxy == NULL))
961 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
963 _cairo_surface_init (&proxy->source.base,
964 &cairo_xlib_proxy_backend,
968 proxy->source.dpy = dst->display->display;
969 format = _cairo_xlib_shm_surface_get_xrender_format(src);
970 if (format == NULL) {
972 return _cairo_surface_create_in_error (CAIRO_STATUS_NULL_POINTER);
975 proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
976 _cairo_xlib_shm_surface_get_pixmap (src),
979 proxy->source.pixmap = None;
981 proxy->source.has_component_alpha = 0;
982 proxy->source.has_matrix = 0;
983 proxy->source.filter = CAIRO_FILTER_NEAREST;
984 proxy->source.extend = CAIRO_EXTEND_NONE;
985 proxy->owner = cairo_surface_reference (src);
987 return embedded_source (dst, pattern, extents, src_x, src_y,
992 if (_cairo_surface_get_extents (pattern->surface, &limit)) {
993 if (pattern->base.extend == CAIRO_EXTEND_NONE) {
994 if (! _cairo_rectangle_intersect (&upload, &limit))
995 return alpha_source (dst, 0);
997 if (upload.x < limit.x ||
998 upload.x + upload.width > limit.x + limit.width ||
999 upload.y < limit.y ||
1000 upload.y + upload.height > limit.y + limit.height)
1007 xsrc = (cairo_xlib_surface_t *)
1008 _cairo_surface_create_similar_scratch (&dst->base,
1012 if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
1013 cairo_surface_destroy (src);
1014 cairo_surface_destroy (&xsrc->base);
1018 if (_cairo_surface_is_image (src)) {
1019 status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
1021 upload.width, upload.height,
1024 cairo_image_surface_t *image;
1025 cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
1027 image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
1029 _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
1030 cairo_matrix_init_translate (&local_pattern.base.matrix,
1031 upload.x, upload.y);
1033 status = _cairo_surface_paint (&image->base,
1034 CAIRO_OPERATOR_SOURCE,
1035 &local_pattern.base,
1037 _cairo_pattern_fini (&local_pattern.base);
1039 status = _cairo_surface_unmap_image (&xsrc->base, image);
1040 if (unlikely (status)) {
1041 cairo_surface_destroy (&xsrc->base);
1042 return _cairo_surface_create_in_error (status);
1045 status = _cairo_xlib_surface_put_shm (xsrc);
1046 if (unlikely (status)) {
1047 cairo_surface_destroy (&xsrc->base);
1048 return _cairo_surface_create_in_error (status);
1052 _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
1053 if (upload.x | upload.y) {
1055 cairo_matrix_init_translate (&m, -upload.x, -upload.y);
1056 cairo_matrix_multiply (&local_pattern.base.matrix,
1057 &local_pattern.base.matrix,
1061 *src_x = *src_y = 0;
1062 _cairo_xlib_surface_ensure_picture (xsrc);
1063 if (! picture_set_properties (xsrc->display,
1065 &local_pattern.base,
1066 &local_pattern.base.matrix,
1070 cairo_surface_destroy (&xsrc->base);
1071 return render_pattern (dst, &pattern->base,
1080 pattern_is_supported (cairo_xlib_display_t *display,
1081 const cairo_pattern_t *pattern)
1083 if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
1086 if (display->buggy_pad_reflect) {
1087 if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
1091 if (display->buggy_gradients) {
1092 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1096 if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
1097 if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
1101 if (! CAIRO_RENDER_HAS_FILTERS (display)) {
1102 /* No filters implies no transforms, so we optimise away BILINEAR */
1108 _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
1109 const cairo_pattern_t *pattern,
1110 cairo_bool_t is_mask,
1111 const cairo_rectangle_int_t *extents,
1112 const cairo_rectangle_int_t *sample,
1113 int *src_x, int *src_y)
1115 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
1117 *src_x = *src_y = 0;
1119 if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1120 if (pattern == NULL)
1121 pattern = &_cairo_pattern_white.base;
1123 return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
1126 if (pattern_is_supported (dst->display, pattern)) {
1127 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1128 cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern;
1129 if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB &&
1130 _cairo_xlib_surface_same_screen (dst,
1131 unwrap_source (spattern)))
1132 return native_source (dst, spattern, is_mask,
1136 if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1137 return record_source (dst, spattern, is_mask,
1141 return surface_source (dst, spattern, is_mask,
1146 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1147 pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1149 cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
1150 return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
1154 return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
1157 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */