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
XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
91
if (proxy->source.pixmap)
92
XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
93
_cairo_xlib_shm_surface_mark_active (proxy->owner);
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;
952
src = pattern->surface;
953
if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
954
src->device == dst->base.device &&
955
_cairo_xlib_shm_surface_get_pixmap (src)) {
956
cairo_xlib_proxy_t *proxy;
958
cairo_surface_reference (src);
960
proxy = malloc (sizeof(*proxy));
961
if (unlikely (proxy == NULL)) {
962
cairo_surface_destroy (src);
963
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
966
_cairo_surface_init (&proxy->source.base,
967
&cairo_xlib_proxy_backend,
969
CAIRO_CONTENT_COLOR_ALPHA);
971
proxy->source.dpy = dst->display->display;
972
proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
973
_cairo_xlib_shm_surface_get_pixmap (src),
974
_cairo_xlib_shm_surface_get_xrender_format (src),
976
proxy->source.pixmap = None;
978
proxy->source.has_component_alpha = 0;
979
proxy->source.has_matrix = 0;
980
proxy->source.filter = CAIRO_FILTER_NEAREST;
981
proxy->source.extend = CAIRO_EXTEND_NONE;
984
return embedded_source (dst, pattern, extents, src_x, src_y,
989
if (_cairo_surface_get_extents (pattern->surface, &limit)) {
990
if (pattern->base.extend == CAIRO_EXTEND_NONE) {
991
if (! _cairo_rectangle_intersect (&upload, &limit))
992
return alpha_source (dst, 0);
994
if (upload.x < limit.x ||
995
upload.x + upload.width > limit.x + limit.width ||
996
upload.y < limit.y ||
997
upload.y + upload.height > limit.y + limit.height)
1004
xsrc = (cairo_xlib_surface_t *)
1005
_cairo_surface_create_similar_scratch (&dst->base,
1009
if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
1010
cairo_surface_destroy (src);
1011
cairo_surface_destroy (&xsrc->base);
1015
if (_cairo_surface_is_image (src)) {
1016
status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
1018
upload.width, upload.height,
1021
cairo_image_surface_t *image;
1022
cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
1024
image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
1026
_cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
1027
cairo_matrix_init_translate (&local_pattern.base.matrix,
1028
upload.x, upload.y);
1030
status = _cairo_surface_paint (&image->base,
1031
CAIRO_OPERATOR_SOURCE,
1032
&local_pattern.base,
1034
_cairo_pattern_fini (&local_pattern.base);
1036
status = _cairo_surface_unmap_image (&xsrc->base, image);
1037
if (unlikely (status)) {
1038
cairo_surface_destroy (src);
1039
return _cairo_surface_create_in_error (status);
1043
_cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
1044
if (upload.x | upload.y) {
1046
cairo_matrix_init_translate (&m, -upload.x, -upload.y);
1047
cairo_matrix_multiply (&local_pattern.base.matrix,
1048
&local_pattern.base.matrix,
1052
*src_x = *src_y = 0;
1053
_cairo_xlib_surface_ensure_picture (xsrc);
1054
if (! picture_set_properties (xsrc->display,
1056
&local_pattern.base,
1057
&local_pattern.base.matrix,
1061
cairo_surface_destroy (&xsrc->base);
1062
return render_pattern (dst, &pattern->base,
1071
pattern_is_supported (cairo_xlib_display_t *display,
1072
const cairo_pattern_t *pattern)
1074
if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
1077
if (display->buggy_pad_reflect) {
1078
if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
1082
if (display->buggy_gradients) {
1083
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1087
if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
1088
if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
1092
if (! CAIRO_RENDER_HAS_FILTERS (display)) {
1093
/* No filters implies no transforms, so we optimise away BILINEAR */
1099
_cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
1100
const cairo_pattern_t *pattern,
1101
cairo_bool_t is_mask,
1102
const cairo_rectangle_int_t *extents,
1103
const cairo_rectangle_int_t *sample,
1104
int *src_x, int *src_y)
1106
cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
1108
*src_x = *src_y = 0;
1110
if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1111
if (pattern == NULL)
1112
pattern = &_cairo_pattern_white.base;
1114
return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
1117
if (pattern_is_supported (dst->display, pattern)) {
1118
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1119
cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern;
1120
if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB &&
1121
_cairo_xlib_surface_same_screen (dst,
1122
unwrap_source (spattern)))
1123
return native_source (dst, spattern, is_mask,
1127
if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1128
return record_source (dst, spattern, is_mask,
1132
return surface_source (dst, spattern, is_mask,
1137
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1138
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1140
cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
1141
return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
1145
return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
1148
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */