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