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_IMAGE,
79 _cairo_xlib_source_finish,
80 NULL, /* read-only wrapper */
83 static cairo_surface_t *
84 source (cairo_xlib_surface_t *dst, Picture picture)
86 cairo_xlib_source_t *source;
89 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
91 source = malloc (sizeof (cairo_image_surface_t));
92 if (unlikely (source == NULL)) {
93 XRenderFreePicture (dst->display->display, picture);
94 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
97 _cairo_surface_init (&source->base,
98 &cairo_xlib_source_backend,
100 CAIRO_CONTENT_COLOR_ALPHA);
102 /* The source exists only within an operation */
103 source->picture = picture;
104 source->dpy = dst->display->display;
106 return &source->base;
110 hars_petruska_f54_1_random (void)
112 #define rol(x,k) ((x << k) | (x >> (32-k)))
114 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
118 static const XTransform identity = {
120 { 1 << 16, 0x00000, 0x00000 },
121 { 0x00000, 1 << 16, 0x00000 },
122 { 0x00000, 0x00000, 1 << 16 },
127 picture_set_matrix (cairo_xlib_display_t *display,
129 const cairo_matrix_t *matrix,
130 cairo_filter_t filter,
136 XTransform xtransform;
137 pixman_transform_t *pixman_transform;
138 cairo_int_status_t status;
140 /* Casting between pixman_transform_t and XTransform is safe because
141 * they happen to be the exact same type.
143 pixman_transform = (pixman_transform_t *) &xtransform;
144 status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
147 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
149 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
152 if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
155 /* a late check in case we perturb the matrix too far */
156 if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display))
159 XRenderSetPictureTransform (display->display, picture, &xtransform);
163 static cairo_status_t
164 picture_set_filter (Display *dpy,
166 cairo_filter_t filter)
168 const char *render_filter;
171 case CAIRO_FILTER_FAST:
172 render_filter = FilterFast;
174 case CAIRO_FILTER_GOOD:
175 render_filter = FilterGood;
177 case CAIRO_FILTER_BEST:
178 render_filter = FilterBest;
180 case CAIRO_FILTER_NEAREST:
181 render_filter = FilterNearest;
183 case CAIRO_FILTER_BILINEAR:
184 render_filter = FilterBilinear;
186 case CAIRO_FILTER_GAUSSIAN:
187 /* XXX: The GAUSSIAN value has no implementation in cairo
188 * whatsoever, so it was really a mistake to have it in the
189 * API. We could fix this by officially deprecating it, or
190 * else inventing semantics and providing an actual
191 * implementation for it. */
193 render_filter = FilterBest;
197 XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0);
198 return CAIRO_STATUS_SUCCESS;
202 extend_to_repeat (cairo_extend_t extend)
207 case CAIRO_EXTEND_NONE:
209 case CAIRO_EXTEND_REPEAT:
211 case CAIRO_EXTEND_REFLECT:
212 return RepeatReflect;
213 case CAIRO_EXTEND_PAD:
219 picture_set_properties (cairo_xlib_display_t *display,
221 const cairo_pattern_t *pattern,
222 const cairo_matrix_t *matrix,
223 const cairo_rectangle_int_t *extents,
224 int *x_off, int *y_off)
226 XRenderPictureAttributes pa;
229 if (! picture_set_matrix (display, picture, matrix, pattern->filter,
230 extents->x + extents->width / 2,
231 extents->y + extents->height / 2,
235 picture_set_filter (display->display, picture, pattern->filter);
237 if (pattern->has_component_alpha) {
238 pa.component_alpha = 1;
239 mask |= CPComponentAlpha;
242 if (pattern->extend != CAIRO_EXTEND_NONE) {
243 pa.repeat = extend_to_repeat (pattern->extend);
248 XRenderChangePicture (display->display, picture, mask, &pa);
253 static cairo_surface_t *
254 render_pattern (cairo_xlib_surface_t *dst,
255 const cairo_pattern_t *pattern,
256 cairo_bool_t is_mask,
257 const cairo_rectangle_int_t *extents,
258 int *src_x, int *src_y)
260 Display *dpy = dst->display->display;
261 cairo_xlib_surface_t *src;
262 cairo_surface_t *image;
263 cairo_status_t status;
265 src = (cairo_xlib_surface_t *)
266 _cairo_surface_create_similar_scratch (&dst->base,
267 is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
270 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
271 cairo_surface_destroy (&src->base);
275 image = cairo_surface_map_to_image (&src->base, NULL);
276 status = _cairo_surface_offset_paint (image, extents->x, extents->y,
277 CAIRO_OPERATOR_SOURCE, pattern,
279 cairo_surface_unmap_image (&src->base, image);
280 if (unlikely (status)) {
281 cairo_surface_destroy (&src->base);
282 return _cairo_surface_create_in_error (status);
285 src->picture = XRenderCreatePicture (dpy,
286 src->drawable, src->xrender_format,
289 *src_x = -extents->x;
290 *src_y = -extents->y;
295 static cairo_surface_t *
296 gradient_source (cairo_xlib_surface_t *dst,
297 const cairo_gradient_pattern_t *gradient,
298 cairo_bool_t is_mask,
299 const cairo_rectangle_int_t *extents,
300 int *src_x, int *src_y)
302 cairo_xlib_display_t *display = dst->display;
303 cairo_matrix_t matrix = gradient->base.matrix;
304 char buf[CAIRO_STACK_BUFFER_SIZE];
305 cairo_circle_double_t extremes[2];
307 XRenderColor *colors;
309 unsigned int i, n_stops;
311 /* The RENDER specification says that the inner circle has
312 * to be completely contained inside the outer one. */
313 if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL &&
314 ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
315 return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
317 assert (gradient->n_stops > 0);
318 n_stops = MAX (gradient->n_stops, 2);
320 if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
322 stops = (XFixed *) buf;
327 _cairo_malloc_ab (n_stops,
328 sizeof (XFixed) + sizeof (XRenderColor));
329 if (unlikely (stops == NULL))
330 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
333 colors = (XRenderColor *) (stops + n_stops);
334 for (i = 0; i < gradient->n_stops; i++) {
336 _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
338 colors[i].red = gradient->stops[i].color.red_short;
339 colors[i].green = gradient->stops[i].color.green_short;
340 colors[i].blue = gradient->stops[i].color.blue_short;
341 colors[i].alpha = gradient->stops[i].color.alpha_short;
344 /* RENDER does not support gradients with less than 2
345 * stops. If a gradient has only a single stop, duplicate
346 * it to make RENDER happy. */
347 if (gradient->n_stops == 1) {
349 _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
351 colors[1].red = gradient->stops[0].color.red_short;
352 colors[1].green = gradient->stops[0].color.green_short;
353 colors[1].blue = gradient->stops[0].color.blue_short;
354 colors[1].alpha = gradient->stops[0].color.alpha_short;
358 /* For some weird reason the X server is sometimes getting
359 * CreateGradient requests with bad length. So far I've only seen
360 * XRenderCreateLinearGradient request with 4 stops sometime end up
361 * with length field matching 0 stops at the server side. I've
362 * looked at the libXrender code and I can't see anything that
363 * could cause this behavior. However, for some reason having a
364 * XSync call here seems to avoid the issue so I'll keep it here
367 XSync (display->display, False);
370 _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
372 if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
373 XLinearGradient grad;
375 grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
376 grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
377 grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
378 grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
380 picture = XRenderCreateLinearGradient (display->display, &grad,
384 XRadialGradient grad;
386 grad.inner.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
387 grad.inner.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
388 grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
389 grad.outer.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
390 grad.outer.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
391 grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
393 picture = XRenderCreateRadialGradient (display->display, &grad,
398 if (stops != (XFixed *) buf)
402 if (! picture_set_properties (display, picture,
403 &gradient->base, &gradient->base.matrix,
406 XRenderFreePicture (display->display, picture);
407 return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
410 return source (dst, picture);
413 static cairo_surface_t *
414 color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
416 XRenderColor xrender_color;
418 xrender_color.red = color->red_short;
419 xrender_color.green = color->green_short;
420 xrender_color.blue = color->blue_short;
421 xrender_color.alpha = color->alpha_short;
424 XRenderCreateSolidFill (dst->display->display,
428 static cairo_surface_t *
429 alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha)
431 cairo_xlib_display_t *display = dst->display;
433 if (display->alpha[alpha] == NULL) {
436 color.red_short = color.green_short = color.blue_short = 0;
437 color.alpha_short = alpha << 8 | alpha;
439 display->alpha[alpha] = color_source (dst, &color);
442 return cairo_surface_reference (display->alpha[alpha]);
445 static cairo_surface_t *
446 white_source (cairo_xlib_surface_t *dst)
448 cairo_xlib_display_t *display = dst->display;
450 if (display->white == NULL)
451 display->white = color_source (dst, CAIRO_COLOR_WHITE);
453 return cairo_surface_reference (display->white);
456 static cairo_surface_t *
457 opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
459 cairo_xlib_display_t *display = dst->display;
462 color->red_short >> 8 << 16 |
463 color->green_short >> 8 << 8 |
464 color->blue_short >> 8 << 0;
467 if (display->last_solid_cache[0].color == pixel)
468 return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]);
470 for (i = 0; i < 16; i++) {
471 if (display->solid_cache[i] == pixel)
475 i = hars_petruska_f54_1_random () % 16;
476 cairo_surface_destroy (display->solid[i]);
478 display->solid[i] = color_source (dst, color);
479 display->solid_cache[i] = pixel;
482 display->last_solid_cache[0].color = pixel;
483 display->last_solid_cache[0].index = i;
484 return cairo_surface_reference (display->solid[i]);
487 static cairo_surface_t *
488 transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
490 cairo_xlib_display_t *display = dst->display;
492 color->alpha_short >> 8 << 24 |
493 color->red_short >> 8 << 16 |
494 color->green_short >> 8 << 8 |
495 color->blue_short >> 8 << 0;
498 if (display->last_solid_cache[1].color == pixel) {
499 assert (display->solid[display->last_solid_cache[1].index]);
500 return cairo_surface_reference (display->solid[display->last_solid_cache[1].index]);
503 for (i = 16; i < 32; i++) {
504 if (display->solid_cache[i] == pixel)
508 i = 16 + (hars_petruska_f54_1_random () % 16);
509 cairo_surface_destroy (display->solid[i]);
511 display->solid[i] = color_source (dst, color);
512 display->solid_cache[i] = pixel;
515 display->last_solid_cache[1].color = pixel;
516 display->last_solid_cache[1].index = i;
517 assert (display->solid[i]);
518 return cairo_surface_reference (display->solid[i]);
521 static cairo_surface_t *
522 solid_source (cairo_xlib_surface_t *dst,
523 const cairo_color_t *color)
525 if ((color->red_short | color->green_short | color->blue_short) <= 0xff)
526 return alpha_source (dst, color->alpha_short >> 8);
528 if (CAIRO_ALPHA_SHORT_IS_OPAQUE (color->alpha_short)) {
529 if (color->red_short >= 0xff00 && color->green_short >= 0xff00 && color->blue_short >= 0xff00)
530 return white_source (dst);
532 return opaque_source (dst, color);
534 return transparent_source (dst, color);
537 static cairo_surface_t *
538 embedded_source (cairo_xlib_surface_t *dst,
539 const cairo_surface_pattern_t *pattern,
540 cairo_xlib_surface_t *src,
541 const cairo_rectangle_int_t *extents,
542 int *src_x, int *src_y)
544 cairo_xlib_source_t *source;
545 Display *dpy = dst->display->display;
546 cairo_int_status_t status;
547 XTransform xtransform;
548 XRenderPictureAttributes pa;
551 /* As these are frequent and meant to be fast, we track pictures for
552 * native surface and minimise update requests.
554 source = &src->embedded_source;
555 if (source->picture == None) {
556 XRenderPictureAttributes pa;
558 _cairo_surface_init (&source->base,
559 &cairo_xlib_source_backend,
561 CAIRO_CONTENT_COLOR_ALPHA);
563 pa.subwindow_mode = IncludeInferiors;
564 source->picture = XRenderCreatePicture (dpy,
567 CPSubwindowMode, &pa);
569 source->has_component_alpha = 0;
570 source->has_matrix = 0;
571 source->filter = CAIRO_FILTER_NEAREST;
572 source->extend = CAIRO_EXTEND_NONE;
575 status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
576 pattern->base.filter,
577 extents->x + extents->width / 2,
578 extents->y + extents->height / 2,
579 (pixman_transform_t *)&xtransform,
582 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
583 if (source->has_matrix) {
584 source->has_matrix = 0;
585 memcpy (&xtransform, &identity, sizeof (identity));
586 status = CAIRO_INT_STATUS_SUCCESS;
589 source->has_matrix = 1;
590 if (status == CAIRO_INT_STATUS_SUCCESS)
591 XRenderSetPictureTransform (dpy, source->picture, &xtransform);
593 if (source->filter != pattern->base.filter) {
594 picture_set_filter (dpy, source->picture, pattern->base.filter);
595 source->filter = pattern->base.filter;
598 if (source->has_component_alpha != pattern->base.has_component_alpha) {
599 pa.component_alpha = pattern->base.has_component_alpha;
600 mask |= CPComponentAlpha;
601 source->has_component_alpha = pattern->base.has_component_alpha;
604 if (source->extend != pattern->base.extend) {
605 pa.repeat = extend_to_repeat (pattern->base.extend);
607 source->extend = pattern->base.extend;
611 XRenderChangePicture (dpy, source->picture, mask, &pa);
613 return cairo_surface_reference (&source->base);
616 static cairo_surface_t *
617 subsurface_source (cairo_xlib_surface_t *dst,
618 const cairo_surface_pattern_t *pattern,
619 cairo_bool_t is_mask,
620 const cairo_rectangle_int_t *extents,
621 const cairo_rectangle_int_t *sample,
622 int *src_x, int *src_y)
624 cairo_surface_subsurface_t *sub;
625 cairo_xlib_surface_t *src;
626 cairo_xlib_source_t *source;
627 Display *dpy = dst->display->display;
628 cairo_int_status_t status;
629 cairo_surface_pattern_t local_pattern;
630 XTransform xtransform;
631 XRenderPictureAttributes pa;
634 sub = (cairo_surface_subsurface_t *) pattern->surface;
636 if (sample->x >= 0 && sample->y >= 0 &&
637 sample->x + sample->width <= sub->extents.width &&
638 sample->y + sample->height <= sub->extents.height)
640 src = (cairo_xlib_surface_t *) sub->target;
642 if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
643 _cairo_matrix_is_translation (&pattern->base.matrix))
645 *src_x += pattern->base.matrix.x0 + sub->extents.x;
646 *src_y += pattern->base.matrix.y0 + sub->extents.y;
648 _cairo_xlib_surface_ensure_picture (src);
649 return cairo_surface_reference (&src->base);
653 cairo_surface_pattern_t local_pattern = *pattern;
654 local_pattern.base.matrix.x0 += sub->extents.x;
655 local_pattern.base.matrix.y0 += sub->extents.y;
656 local_pattern.base.extend = CAIRO_EXTEND_NONE;
657 return embedded_source (dst, &local_pattern, src, extents,
662 if (sub->snapshot && sub->snapshot->type == CAIRO_SURFACE_TYPE_XLIB) {
663 src = (cairo_xlib_surface_t *) cairo_surface_reference (sub->snapshot);
664 source = &src->embedded_source;
666 src = (cairo_xlib_surface_t *)
667 _cairo_surface_create_similar_scratch (&dst->base,
670 sub->extents.height);
671 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
672 cairo_surface_destroy (&src->base);
673 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
676 _cairo_pattern_init_for_surface (&local_pattern, sub->target);
677 cairo_matrix_init_translate (&local_pattern.base.matrix,
678 sub->extents.x, sub->extents.y);
679 local_pattern.base.filter = CAIRO_FILTER_NEAREST;
680 status = _cairo_surface_paint (&src->base,
681 CAIRO_OPERATOR_SOURCE,
684 _cairo_pattern_fini (&local_pattern.base);
686 if (unlikely (status)) {
687 cairo_surface_destroy (&src->base);
688 return _cairo_surface_create_in_error (status);
691 _cairo_xlib_surface_ensure_picture (src);
692 _cairo_surface_subsurface_set_snapshot (&sub->base, &src->base);
694 source = &src->embedded_source;
695 source->has_component_alpha = 0;
696 source->has_matrix = 0;
697 source->filter = CAIRO_FILTER_NEAREST;
698 source->extend = CAIRO_EXTEND_NONE;
701 status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
702 pattern->base.filter,
703 extents->x + extents->width / 2,
704 extents->y + extents->height / 2,
705 (pixman_transform_t *)&xtransform,
707 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
708 if (source->has_matrix) {
709 source->has_matrix = 0;
710 memcpy (&xtransform, &identity, sizeof (identity));
711 status = CAIRO_INT_STATUS_SUCCESS;
714 source->has_matrix = 1;
715 if (status == CAIRO_INT_STATUS_SUCCESS)
716 XRenderSetPictureTransform (dpy, src->picture, &xtransform);
718 if (source->filter != pattern->base.filter) {
719 picture_set_filter (dpy, src->picture, pattern->base.filter);
720 source->filter = pattern->base.filter;
723 if (source->has_component_alpha != pattern->base.has_component_alpha) {
724 pa.component_alpha = pattern->base.has_component_alpha;
725 mask |= CPComponentAlpha;
726 source->has_component_alpha = pattern->base.has_component_alpha;
729 if (source->extend != pattern->base.extend) {
730 pa.repeat = extend_to_repeat (pattern->base.extend);
732 source->extend = pattern->base.extend;
736 XRenderChangePicture (dpy, src->picture, mask, &pa);
741 static cairo_surface_t *
742 native_source (cairo_xlib_surface_t *dst,
743 const cairo_surface_pattern_t *pattern,
744 cairo_bool_t is_mask,
745 const cairo_rectangle_int_t *extents,
746 const cairo_rectangle_int_t *sample,
747 int *src_x, int *src_y)
749 cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) pattern->surface;
751 if (_cairo_surface_is_subsurface (pattern->surface))
752 return subsurface_source (dst, pattern, is_mask,
756 src = unwrap_source (pattern);
758 if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
759 sample->x >= 0 && sample->y >= 0 &&
760 sample->x + sample->width <= src->width &&
761 sample->y + sample->height <= src->height &&
762 _cairo_matrix_is_translation (&pattern->base.matrix))
764 *src_x += pattern->base.matrix.x0;
765 *src_y += pattern->base.matrix.y0;
766 _cairo_xlib_surface_ensure_picture (src);
767 return cairo_surface_reference (&src->base);
770 return embedded_source (dst, pattern, src, extents, src_x, src_y);
774 /* It is general quicker if we let the application choose which images
775 * to cache for itself and only upload the fragments required for this
778 static cairo_surface_t *
779 image_source (cairo_xlib_surface_t *dst,
780 const cairo_surface_pattern_t *pattern,
781 const cairo_rectangle_int_t *extents,
782 int *src_x, int *src_y)
784 cairo_image_surface_t *src = (cairo_image_surface_t *) pattern->surface;
785 cairo_xlib_surface_t *snapshot;
786 cairo_surface_pattern_t local_pattern;
787 cairo_status_t status;
789 snapshot = (cairo_xlib_surface_t *)
790 _cairo_surface_has_snapshot (&src->base, dst->base.backend);
791 if (snapshot == NULL || snapshot->screen != dst->screen) {
793 _cairo_surface_detach_snapshot (&snapshot->base);
795 snapshot = (cairo_xlib_surface_t *)
796 _cairo_surface_create_similar_scratch (&dst->base,
800 if (snapshot->base.type != CAIRO_SURFACE_TYPE_XLIB) {
801 cairo_surface_destroy (&snapshot->base);
802 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
805 status = _cairo_xlib_surface_draw_image (snapshot, src,
807 src->width, src->height,
809 if (unlikely (status)) {
810 cairo_surface_destroy (&snapshot->base);
811 return _cairo_surface_create_in_error (status);
814 _cairo_surface_attach_snapshot (&src->base,
816 cairo_surface_finish);
818 /* reference remains held by the snapshot from image */
819 cairo_surface_destroy (&snapshot->base);
822 local_pattern = *pattern;
823 local_pattern.surface = &snapshot->base;
825 return native_source (dst, &local_pattern, extents, src_x, src_y);
829 static cairo_surface_t *
830 recording_pattern_get_surface (const cairo_pattern_t *pattern)
832 cairo_surface_t *surface;
834 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
835 if (_cairo_surface_is_paginated (surface))
836 surface = _cairo_paginated_surface_get_recording (surface);
837 if (_cairo_surface_is_snapshot (surface))
838 surface = _cairo_surface_snapshot_get_target (surface);
842 static cairo_surface_t *
843 record_source (cairo_xlib_surface_t *dst,
844 const cairo_surface_pattern_t *pattern,
845 cairo_bool_t is_mask,
846 const cairo_rectangle_int_t *extents,
847 const cairo_rectangle_int_t *sample,
848 int *src_x, int *src_y)
850 cairo_xlib_surface_t *src;
851 cairo_matrix_t matrix, m;
852 cairo_status_t status;
853 cairo_rectangle_int_t upload, limit;
856 if (_cairo_surface_get_extents (pattern->surface, &limit) &&
857 ! _cairo_rectangle_intersect (&upload, &limit))
859 if (pattern->base.extend == CAIRO_EXTEND_NONE)
860 return alpha_source (dst, 0);
865 src = (cairo_xlib_surface_t *)
866 _cairo_surface_create_similar_scratch (&dst->base,
867 pattern->surface->content,
870 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
871 cairo_surface_destroy (&src->base);
872 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
875 cairo_matrix_init_translate (&matrix, upload.x, upload.y);
876 status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base),
879 if (unlikely (status)) {
880 cairo_surface_destroy (&src->base);
881 return _cairo_surface_create_in_error (status);
884 matrix = pattern->base.matrix;
885 if (upload.x | upload.y) {
886 cairo_matrix_init_translate (&m, -upload.x, -upload.y);
887 cairo_matrix_multiply (&matrix, &matrix, &m);
890 _cairo_xlib_surface_ensure_picture (src);
891 if (! picture_set_properties (src->display, src->picture,
892 &pattern->base, &matrix, extents,
895 cairo_surface_destroy (&src->base);
896 return render_pattern (dst, &pattern->base, is_mask,
897 extents, src_x, src_y);
903 static cairo_surface_t *
904 surface_source (cairo_xlib_surface_t *dst,
905 const cairo_surface_pattern_t *pattern,
906 cairo_bool_t is_mask,
907 const cairo_rectangle_int_t *extents,
908 const cairo_rectangle_int_t *sample,
909 int *src_x, int *src_y)
911 cairo_xlib_surface_t *src;
912 cairo_surface_t *image;
913 cairo_surface_pattern_t local_pattern;
914 cairo_status_t status;
915 cairo_rectangle_int_t upload, limit;
919 if (_cairo_surface_get_extents (pattern->surface, &limit) &&
920 ! _cairo_rectangle_intersect (&upload, &limit))
922 if (pattern->base.extend == CAIRO_EXTEND_NONE)
923 return alpha_source (dst, 0);
928 src = (cairo_xlib_surface_t *)
929 _cairo_surface_create_similar_scratch (&dst->base,
930 pattern->surface->content,
933 if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
934 cairo_surface_destroy (&src->base);
935 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
938 _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
939 cairo_matrix_init_translate (&local_pattern.base.matrix,
942 image = cairo_surface_map_to_image (&src->base, NULL);
943 status = _cairo_surface_paint (image,
944 CAIRO_OPERATOR_SOURCE,
947 cairo_surface_unmap_image (&src->base, image);
948 _cairo_pattern_fini (&local_pattern.base);
950 if (unlikely (status)) {
951 cairo_surface_destroy (&src->base);
952 return _cairo_surface_create_in_error (status);
955 local_pattern.base.matrix = pattern->base.matrix;
956 if (upload.x | upload.y) {
957 cairo_matrix_init_translate (&m, -upload.x, -upload.y);
958 cairo_matrix_multiply (&local_pattern.base.matrix,
959 &local_pattern.base.matrix,
964 _cairo_xlib_surface_ensure_picture (src);
965 if (! picture_set_properties (src->display,
968 &local_pattern.base.matrix,
972 cairo_surface_destroy (&src->base);
973 return render_pattern (dst, &pattern->base,
982 pattern_is_supported (cairo_xlib_display_t *display,
983 const cairo_pattern_t *pattern)
985 if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
988 if (display->buggy_pad_reflect) {
989 if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
993 if (display->buggy_gradients) {
994 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
998 if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
999 if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
1003 if (! CAIRO_RENDER_HAS_FILTERS (display)) {
1004 /* No filters implies no transforms, so we optimise away BILINEAR */
1010 _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
1011 const cairo_pattern_t *pattern,
1012 cairo_bool_t is_mask,
1013 const cairo_rectangle_int_t *extents,
1014 const cairo_rectangle_int_t *sample,
1015 int *src_x, int *src_y)
1017 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
1019 *src_x = *src_y = 0;
1021 if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1022 if (pattern == NULL)
1023 pattern = &_cairo_pattern_white.base;
1025 return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
1028 if (pattern_is_supported (dst->display, pattern)) {
1029 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1030 cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern;
1031 if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB &&
1032 _cairo_xlib_surface_same_screen (dst,
1033 unwrap_source (spattern)))
1034 return native_source (dst, spattern, is_mask,
1038 if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1039 return record_source (dst, spattern, is_mask,
1043 if (spattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
1044 return image_source (dst, spattern, extents, src_x, src_y);
1047 return surface_source (dst, spattern, is_mask,
1052 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1053 pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1055 cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
1056 return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
1060 return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
1063 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */